xref: /freebsd/sys/netinet/netdump/netdump_client.c (revision 4a84c26cfc241ffa113d2e815d61d4b406b937e9)
1 /*-
2  * Copyright (c) 2005-2014 Sandvine Incorporated. All rights reserved.
3  * Copyright (c) 2000 Darrell Anderson
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27 
28 /*
29  * netdump_client.c
30  * FreeBSD subsystem supporting netdump network dumps.
31  * A dedicated server must be running to accept client dumps.
32  */
33 
34 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD$");
36 
37 #include <sys/param.h>
38 #include <sys/conf.h>
39 #include <sys/disk.h>
40 #include <sys/endian.h>
41 #include <sys/kernel.h>
42 #include <sys/kerneldump.h>
43 #include <sys/mbuf.h>
44 #include <sys/module.h>
45 #include <sys/priv.h>
46 #include <sys/proc.h>
47 #include <sys/protosw.h>
48 #include <sys/socket.h>
49 #include <sys/sysctl.h>
50 #include <sys/systm.h>
51 
52 #include <net/ethernet.h>
53 #include <net/if.h>
54 #include <net/if_arp.h>
55 #include <net/if_dl.h>
56 #include <net/if_types.h>
57 #include <net/if_var.h>
58 
59 #include <netinet/in.h>
60 #include <netinet/in_systm.h>
61 #include <netinet/in_var.h>
62 #include <netinet/ip.h>
63 #include <netinet/ip_var.h>
64 #include <netinet/ip_options.h>
65 #include <netinet/udp.h>
66 #include <netinet/udp_var.h>
67 #include <netinet/netdump/netdump.h>
68 
69 #include <machine/in_cksum.h>
70 #include <machine/pcb.h>
71 
72 #define	NETDDEBUG(f, ...) do {						\
73 	if (nd_debug > 0)						\
74 		printf(("%s: " f), __func__, ## __VA_ARGS__);		\
75 } while (0)
76 #define	NETDDEBUG_IF(i, f, ...) do {					\
77 	if (nd_debug > 0)						\
78 		if_printf((i), ("%s: " f), __func__, ## __VA_ARGS__);	\
79 } while (0)
80 #define	NETDDEBUGV(f, ...) do {						\
81 	if (nd_debug > 1)						\
82 		printf(("%s: " f), __func__, ## __VA_ARGS__);		\
83 } while (0)
84 #define	NETDDEBUGV_IF(i, f, ...) do {					\
85 	if (nd_debug > 1)						\
86 		if_printf((i), ("%s: " f), __func__, ## __VA_ARGS__);	\
87 } while (0)
88 
89 static int	 netdump_arp_gw(void);
90 static void	 netdump_cleanup(void);
91 static int	 netdump_configure(struct netdump_conf *);
92 static int	 netdump_dumper(void *priv __unused, void *virtual,
93 		    vm_offset_t physical __unused, off_t offset, size_t length);
94 static int	 netdump_ether_output(struct mbuf *m, struct ifnet *ifp,
95 		    struct ether_addr dst, u_short etype);
96 static void	 netdump_handle_arp(struct mbuf **mb);
97 static void	 netdump_handle_ip(struct mbuf **mb);
98 static int	 netdump_ioctl(struct cdev *dev __unused, u_long cmd,
99 		    caddr_t addr, int flags __unused, struct thread *td);
100 static int	 netdump_modevent(module_t mod, int type, void *priv);
101 static void	 netdump_network_poll(void);
102 static void	 netdump_pkt_in(struct ifnet *ifp, struct mbuf *m);
103 static int	 netdump_send(uint32_t type, off_t offset, unsigned char *data,
104 		    uint32_t datalen);
105 static int	 netdump_send_arp(in_addr_t dst);
106 static int	 netdump_start(struct dumperinfo *di);
107 static int	 netdump_udp_output(struct mbuf *m);
108 
109 /* Must be at least as big as the chunks dumpsys() gives us. */
110 static unsigned char nd_buf[MAXDUMPPGS * PAGE_SIZE];
111 static uint32_t nd_seqno;
112 static int dump_failed, have_gw_mac;
113 static void (*drv_if_input)(struct ifnet *, struct mbuf *);
114 static int restore_gw_addr;
115 
116 static uint64_t rcvd_acks;
117 CTASSERT(sizeof(rcvd_acks) * NBBY == NETDUMP_MAX_IN_FLIGHT);
118 
119 /*
120  * Times to poll the NIC (0.5ms each poll) before assuming packetloss
121  * occurred (default to 1s).
122  */
123 static int nd_polls = 2000;
124 
125 /* Times to retransmit lost packets. */
126 static int nd_retries = 10;
127 
128 /* Number of ARP retries. */
129 static int nd_arp_retries = 3;
130 
131 /* Configuration parameters. */
132 static struct netdump_conf nd_conf;
133 #define	nd_server	nd_conf.ndc_server
134 #define	nd_client	nd_conf.ndc_client
135 #define	nd_gateway	nd_conf.ndc_gateway
136 
137 /* General dynamic settings. */
138 static struct ether_addr nd_gw_mac;
139 static struct ifnet *nd_ifp;
140 static uint16_t nd_server_port = NETDUMP_PORT;
141 
142 FEATURE(netdump, "Netdump client support");
143 
144 static SYSCTL_NODE(_net, OID_AUTO, netdump, CTLFLAG_RD, NULL,
145     "netdump parameters");
146 
147 static int nd_debug;
148 SYSCTL_INT(_net_netdump, OID_AUTO, debug, CTLFLAG_RWTUN,
149     &nd_debug, 0,
150     "Debug message verbosity");
151 static int nd_enabled;
152 SYSCTL_INT(_net_netdump, OID_AUTO, enabled, CTLFLAG_RD,
153     &nd_enabled, 0,
154     "netdump configuration status");
155 static char nd_path[MAXPATHLEN];
156 SYSCTL_STRING(_net_netdump, OID_AUTO, path, CTLFLAG_RW,
157     nd_path, sizeof(nd_path),
158     "Server path for output files");
159 
160 /*
161  * Checks for netdump support on a network interface
162  *
163  * Parameters:
164  *	ifp	The network interface that is being tested for support
165  *
166  * Returns:
167  *	int	1 if the interface is supported, 0 if not
168  */
169 static bool
170 netdump_supported_nic(struct ifnet *ifp)
171 {
172 
173 	return (ifp->if_netdump_methods != NULL);
174 }
175 
176 /*-
177  * Network specific primitives.
178  * Following down the code they are divided ordered as:
179  * - Packet buffer primitives
180  * - Output primitives
181  * - Input primitives
182  * - Polling primitives
183  */
184 
185 /*
186  * Handles creation of the ethernet header, then places outgoing packets into
187  * the tx buffer for the NIC
188  *
189  * Parameters:
190  *	m	The mbuf containing the packet to be sent (will be freed by
191  *		this function or the NIC driver)
192  *	ifp	The interface to send on
193  *	dst	The destination ethernet address (source address will be looked
194  *		up using ifp)
195  *	etype	The ETHERTYPE_* value for the protocol that is being sent
196  *
197  * Returns:
198  *	int	see errno.h, 0 for success
199  */
200 static int
201 netdump_ether_output(struct mbuf *m, struct ifnet *ifp, struct ether_addr dst,
202     u_short etype)
203 {
204 	struct ether_header *eh;
205 
206 	if (((ifp->if_flags & (IFF_MONITOR | IFF_UP)) != IFF_UP) ||
207 	    (ifp->if_drv_flags & IFF_DRV_RUNNING) != IFF_DRV_RUNNING) {
208 		if_printf(ifp, "netdump_ether_output: interface isn't up\n");
209 		m_freem(m);
210 		return (ENETDOWN);
211 	}
212 
213 	/* Fill in the ethernet header. */
214 	M_PREPEND(m, ETHER_HDR_LEN, M_NOWAIT);
215 	if (m == NULL) {
216 		printf("%s: out of mbufs\n", __func__);
217 		return (ENOBUFS);
218 	}
219 	eh = mtod(m, struct ether_header *);
220 	memcpy(eh->ether_shost, IF_LLADDR(ifp), ETHER_ADDR_LEN);
221 	memcpy(eh->ether_dhost, dst.octet, ETHER_ADDR_LEN);
222 	eh->ether_type = htons(etype);
223 	return ((ifp->if_netdump_methods->nd_transmit)(ifp, m));
224 }
225 
226 /*
227  * Unreliable transmission of an mbuf chain to the netdump server
228  * Note: can't handle fragmentation; fails if the packet is larger than
229  *	 nd_ifp->if_mtu after adding the UDP/IP headers
230  *
231  * Parameters:
232  *	m	mbuf chain
233  *
234  * Returns:
235  *	int	see errno.h, 0 for success
236  */
237 static int
238 netdump_udp_output(struct mbuf *m)
239 {
240 	struct udpiphdr *ui;
241 	struct ip *ip;
242 
243 	MPASS(nd_ifp != NULL);
244 
245 	M_PREPEND(m, sizeof(struct udpiphdr), M_NOWAIT);
246 	if (m == NULL) {
247 		printf("%s: out of mbufs\n", __func__);
248 		return (ENOBUFS);
249 	}
250 
251 	if (m->m_pkthdr.len > nd_ifp->if_mtu) {
252 		printf("netdump_udp_output: Packet is too big: %d > MTU %u\n",
253 		    m->m_pkthdr.len, nd_ifp->if_mtu);
254 		m_freem(m);
255 		return (ENOBUFS);
256 	}
257 
258 	ui = mtod(m, struct udpiphdr *);
259 	bzero(ui->ui_x1, sizeof(ui->ui_x1));
260 	ui->ui_pr = IPPROTO_UDP;
261 	ui->ui_len = htons(m->m_pkthdr.len - sizeof(struct ip));
262 	ui->ui_ulen = ui->ui_len;
263 	ui->ui_src = nd_client;
264 	ui->ui_dst = nd_server;
265 	/* Use this src port so that the server can connect() the socket */
266 	ui->ui_sport = htons(NETDUMP_ACKPORT);
267 	ui->ui_dport = htons(nd_server_port);
268 	ui->ui_sum = 0;
269 	if ((ui->ui_sum = in_cksum(m, m->m_pkthdr.len)) == 0)
270 		ui->ui_sum = 0xffff;
271 
272 	ip = mtod(m, struct ip *);
273 	ip->ip_v = IPVERSION;
274 	ip->ip_hl = sizeof(struct ip) >> 2;
275 	ip->ip_tos = 0;
276 	ip->ip_len = htons(m->m_pkthdr.len);
277 	ip->ip_id = 0;
278 	ip->ip_off = htons(IP_DF);
279 	ip->ip_ttl = 255;
280 	ip->ip_sum = 0;
281 	ip->ip_sum = in_cksum(m, sizeof(struct ip));
282 
283 	return (netdump_ether_output(m, nd_ifp, nd_gw_mac, ETHERTYPE_IP));
284 }
285 
286 /*
287  * Builds and sends a single ARP request to locate the server
288  *
289  * Return value:
290  *	0 on success
291  *	errno on error
292  */
293 static int
294 netdump_send_arp(in_addr_t dst)
295 {
296 	struct ether_addr bcast;
297 	struct mbuf *m;
298 	struct arphdr *ah;
299 	int pktlen;
300 
301 	MPASS(nd_ifp != NULL);
302 
303 	/* Fill-up a broadcast address. */
304 	memset(&bcast, 0xFF, ETHER_ADDR_LEN);
305 	m = m_gethdr(M_NOWAIT, MT_DATA);
306 	if (m == NULL) {
307 		printf("netdump_send_arp: Out of mbufs\n");
308 		return (ENOBUFS);
309 	}
310 	pktlen = arphdr_len2(ETHER_ADDR_LEN, sizeof(struct in_addr));
311 	m->m_len = pktlen;
312 	m->m_pkthdr.len = pktlen;
313 	MH_ALIGN(m, pktlen);
314 	ah = mtod(m, struct arphdr *);
315 	ah->ar_hrd = htons(ARPHRD_ETHER);
316 	ah->ar_pro = htons(ETHERTYPE_IP);
317 	ah->ar_hln = ETHER_ADDR_LEN;
318 	ah->ar_pln = sizeof(struct in_addr);
319 	ah->ar_op = htons(ARPOP_REQUEST);
320 	memcpy(ar_sha(ah), IF_LLADDR(nd_ifp), ETHER_ADDR_LEN);
321 	((struct in_addr *)ar_spa(ah))->s_addr = nd_client.s_addr;
322 	bzero(ar_tha(ah), ETHER_ADDR_LEN);
323 	((struct in_addr *)ar_tpa(ah))->s_addr = dst;
324 	return (netdump_ether_output(m, nd_ifp, bcast, ETHERTYPE_ARP));
325 }
326 
327 /*
328  * Sends ARP requests to locate the server and waits for a response.
329  * We first try to ARP the server itself, and fall back to the provided
330  * gateway if the server appears to be off-link.
331  *
332  * Return value:
333  *	0 on success
334  *	errno on error
335  */
336 static int
337 netdump_arp_gw(void)
338 {
339 	in_addr_t dst;
340 	int error, polls, retries;
341 
342 	dst = nd_server.s_addr;
343 restart:
344 	for (retries = 0; retries < nd_arp_retries && have_gw_mac == 0;
345 	    retries++) {
346 		error = netdump_send_arp(dst);
347 		if (error != 0)
348 			return (error);
349 		for (polls = 0; polls < nd_polls && have_gw_mac == 0; polls++) {
350 			netdump_network_poll();
351 			DELAY(500);
352 		}
353 		if (have_gw_mac == 0)
354 			printf("(ARP retry)");
355 	}
356 	if (have_gw_mac != 0)
357 		return (0);
358 	if (dst == nd_server.s_addr && nd_server.s_addr != nd_gateway.s_addr) {
359 		printf("Failed to ARP server, trying to reach gateway...\n");
360 		dst = nd_gateway.s_addr;
361 		goto restart;
362 	}
363 
364 	printf("\nARP timed out.\n");
365 	return (ETIMEDOUT);
366 }
367 
368 /*
369  * Dummy free function for netdump clusters.
370  */
371 static void
372 netdump_mbuf_free(struct mbuf *m __unused)
373 {
374 }
375 
376 /*
377  * Construct and reliably send a netdump packet.  May fail from a resource
378  * shortage or extreme number of unacknowledged retransmissions.  Wait for
379  * an acknowledgement before returning.  Splits packets into chunks small
380  * enough to be sent without fragmentation (looks up the interface MTU)
381  *
382  * Parameters:
383  *	type	netdump packet type (HERALD, FINISHED, or VMCORE)
384  *	offset	vmcore data offset (bytes)
385  *	data	vmcore data
386  *	datalen	vmcore data size (bytes)
387  *
388  * Returns:
389  *	int see errno.h, 0 for success
390  */
391 static int
392 netdump_send(uint32_t type, off_t offset, unsigned char *data, uint32_t datalen)
393 {
394 	struct netdump_msg_hdr *nd_msg_hdr;
395 	struct mbuf *m, *m2;
396 	uint64_t want_acks;
397 	uint32_t i, pktlen, sent_so_far;
398 	int retries, polls, error;
399 
400 	want_acks = 0;
401 	rcvd_acks = 0;
402 	retries = 0;
403 
404 	MPASS(nd_ifp != NULL);
405 
406 retransmit:
407 	/* Chunks can be too big to fit in packets. */
408 	for (i = sent_so_far = 0; sent_so_far < datalen ||
409 	    (i == 0 && datalen == 0); i++) {
410 		pktlen = datalen - sent_so_far;
411 
412 		/* First bound: the packet structure. */
413 		pktlen = min(pktlen, NETDUMP_DATASIZE);
414 
415 		/* Second bound: the interface MTU (assume no IP options). */
416 		pktlen = min(pktlen, nd_ifp->if_mtu - sizeof(struct udpiphdr) -
417 		    sizeof(struct netdump_msg_hdr));
418 
419 		/*
420 		 * Check if it is retransmitting and this has been ACKed
421 		 * already.
422 		 */
423 		if ((rcvd_acks & (1 << i)) != 0) {
424 			sent_so_far += pktlen;
425 			continue;
426 		}
427 
428 		/*
429 		 * Get and fill a header mbuf, then chain data as an extended
430 		 * mbuf.
431 		 */
432 		m = m_gethdr(M_NOWAIT, MT_DATA);
433 		if (m == NULL) {
434 			printf("netdump_send: Out of mbufs\n");
435 			return (ENOBUFS);
436 		}
437 		m->m_len = sizeof(struct netdump_msg_hdr);
438 		m->m_pkthdr.len = sizeof(struct netdump_msg_hdr);
439 		MH_ALIGN(m, sizeof(struct netdump_msg_hdr));
440 		nd_msg_hdr = mtod(m, struct netdump_msg_hdr *);
441 		nd_msg_hdr->mh_seqno = htonl(nd_seqno + i);
442 		nd_msg_hdr->mh_type = htonl(type);
443 		nd_msg_hdr->mh_offset = htobe64(offset + sent_so_far);
444 		nd_msg_hdr->mh_len = htonl(pktlen);
445 		nd_msg_hdr->mh__pad = 0;
446 
447 		if (pktlen != 0) {
448 			m2 = m_get(M_NOWAIT, MT_DATA);
449 			if (m2 == NULL) {
450 				m_freem(m);
451 				printf("netdump_send: Out of mbufs\n");
452 				return (ENOBUFS);
453 			}
454 			MEXTADD(m2, data + sent_so_far, pktlen,
455 			    netdump_mbuf_free, NULL, NULL, 0, EXT_DISPOSABLE);
456 			m2->m_len = pktlen;
457 
458 			m_cat(m, m2);
459 			m->m_pkthdr.len += pktlen;
460 		}
461 		error = netdump_udp_output(m);
462 		if (error != 0)
463 			return (error);
464 
465 		/* Note that we're waiting for this packet in the bitfield. */
466 		want_acks |= (1 << i);
467 		sent_so_far += pktlen;
468 	}
469 	if (i >= NETDUMP_MAX_IN_FLIGHT)
470 		printf("Warning: Sent more than %d packets (%d). "
471 		    "Acknowledgements will fail unless the size of "
472 		    "rcvd_acks/want_acks is increased.\n",
473 		    NETDUMP_MAX_IN_FLIGHT, i);
474 
475 	/*
476 	 * Wait for acks.  A *real* window would speed things up considerably.
477 	 */
478 	polls = 0;
479 	while (rcvd_acks != want_acks) {
480 		if (polls++ > nd_polls) {
481 			if (retries++ > nd_retries)
482 				return (ETIMEDOUT);
483 			printf(". ");
484 			goto retransmit;
485 		}
486 		netdump_network_poll();
487 		DELAY(500);
488 	}
489 	nd_seqno += i;
490 	return (0);
491 }
492 
493 /*
494  * Handler for IP packets: checks their sanity and then processes any netdump
495  * ACK packets it finds.
496  *
497  * It needs to replicate partially the behaviour of ip_input() and
498  * udp_input().
499  *
500  * Parameters:
501  *	mb	a pointer to an mbuf * containing the packet received
502  *		Updates *mb if m_pullup et al change the pointer
503  *		Assumes the calling function will take care of freeing the mbuf
504  */
505 static void
506 netdump_handle_ip(struct mbuf **mb)
507 {
508 	struct ip *ip;
509 	struct udpiphdr *udp;
510 	struct netdump_ack *nd_ack;
511 	struct mbuf *m;
512 	int rcv_ackno;
513 	unsigned short hlen;
514 
515 	/* IP processing. */
516 	m = *mb;
517 	if (m->m_pkthdr.len < sizeof(struct ip)) {
518 		NETDDEBUG("dropping packet too small for IP header\n");
519 		return;
520 	}
521 	if (m->m_len < sizeof(struct ip)) {
522 		m = m_pullup(m, sizeof(struct ip));
523 		*mb = m;
524 		if (m == NULL) {
525 			NETDDEBUG("m_pullup failed\n");
526 			return;
527 		}
528 	}
529 	ip = mtod(m, struct ip *);
530 
531 	/* IP version. */
532 	if (ip->ip_v != IPVERSION) {
533 		NETDDEBUG("bad IP version %d\n", ip->ip_v);
534 		return;
535 	}
536 
537 	/* Header length. */
538 	hlen = ip->ip_hl << 2;
539 	if (hlen < sizeof(struct ip)) {
540 		NETDDEBUG("bad IP header length (%hu)\n", hlen);
541 		return;
542 	}
543 	if (hlen > m->m_len) {
544 		m = m_pullup(m, hlen);
545 		*mb = m;
546 		if (m == NULL) {
547 			NETDDEBUG("m_pullup failed\n");
548 			return;
549 		}
550 		ip = mtod(m, struct ip *);
551 	}
552 	/* Ignore packets with IP options. */
553 	if (hlen > sizeof(struct ip)) {
554 		NETDDEBUG("drop packet with IP options\n");
555 		return;
556 	}
557 
558 #ifdef INVARIANTS
559 	if (((ntohl(ip->ip_dst.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET ||
560 	    (ntohl(ip->ip_src.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET) &&
561 	    (m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) == 0) {
562 		NETDDEBUG("Bad IP header (RFC1122)\n");
563 		return;
564 	}
565 #endif
566 
567 	/* Checksum. */
568 	if ((m->m_pkthdr.csum_flags & CSUM_IP_CHECKED) != 0) {
569 		if ((m->m_pkthdr.csum_flags & CSUM_IP_VALID) == 0) {
570 			NETDDEBUG("bad IP checksum\n");
571 			return;
572 		}
573 	} else {
574 		/* XXX */ ;
575 	}
576 
577 	/* Convert fields to host byte order. */
578 	ip->ip_len = ntohs(ip->ip_len);
579 	if (ip->ip_len < hlen) {
580 		NETDDEBUG("IP packet smaller (%hu) than header (%hu)\n",
581 		    ip->ip_len, hlen);
582 		return;
583 	}
584 	if (m->m_pkthdr.len < ip->ip_len) {
585 		NETDDEBUG("IP packet bigger (%hu) than ethernet packet (%d)\n",
586 		    ip->ip_len, m->m_pkthdr.len);
587 		return;
588 	}
589 	if (m->m_pkthdr.len > ip->ip_len) {
590 
591 		/* Truncate the packet to the IP length. */
592 		if (m->m_len == m->m_pkthdr.len) {
593 			m->m_len = ip->ip_len;
594 			m->m_pkthdr.len = ip->ip_len;
595 		} else
596 			m_adj(m, ip->ip_len - m->m_pkthdr.len);
597 	}
598 
599 	ip->ip_off = ntohs(ip->ip_off);
600 
601 	/* Check that the source is the server's IP. */
602 	if (ip->ip_src.s_addr != nd_server.s_addr) {
603 		NETDDEBUG("drop packet not from server (from 0x%x)\n",
604 		    ip->ip_src.s_addr);
605 		return;
606 	}
607 
608 	/* Check if the destination IP is ours. */
609 	if (ip->ip_dst.s_addr != nd_client.s_addr) {
610 		NETDDEBUGV("drop packet not to our IP\n");
611 		return;
612 	}
613 
614 	if (ip->ip_p != IPPROTO_UDP) {
615 		NETDDEBUG("drop non-UDP packet\n");
616 		return;
617 	}
618 
619 	/* Do not deal with fragments. */
620 	if ((ip->ip_off & (IP_MF | IP_OFFMASK)) != 0) {
621 		NETDDEBUG("drop fragmented packet\n");
622 		return;
623 	}
624 
625 	/* UDP custom is to have packet length not include IP header. */
626 	ip->ip_len -= hlen;
627 
628 	/* UDP processing. */
629 
630 	/* Get IP and UDP headers together, along with the netdump packet. */
631 	if (m->m_pkthdr.len <
632 	    sizeof(struct udpiphdr) + sizeof(struct netdump_ack)) {
633 		NETDDEBUG("ignoring small packet\n");
634 		return;
635 	}
636 	if (m->m_len < sizeof(struct udpiphdr) + sizeof(struct netdump_ack)) {
637 		m = m_pullup(m, sizeof(struct udpiphdr) +
638 		    sizeof(struct netdump_ack));
639 		*mb = m;
640 		if (m == NULL) {
641 			NETDDEBUG("m_pullup failed\n");
642 			return;
643 		}
644 	}
645 	udp = mtod(m, struct udpiphdr *);
646 
647 	if (ntohs(udp->ui_u.uh_dport) != NETDUMP_ACKPORT) {
648 		NETDDEBUG("not on the netdump port.\n");
649 		return;
650 	}
651 
652 	/* Netdump processing. */
653 
654 	/*
655 	 * Packet is meant for us.  Extract the ack sequence number and the
656 	 * port number if necessary.
657 	 */
658 	nd_ack = (struct netdump_ack *)(mtod(m, caddr_t) +
659 	    sizeof(struct udpiphdr));
660 	rcv_ackno = ntohl(nd_ack->na_seqno);
661 	if (nd_server_port == NETDUMP_PORT)
662 		nd_server_port = ntohs(udp->ui_u.uh_sport);
663 	if (rcv_ackno >= nd_seqno + NETDUMP_MAX_IN_FLIGHT)
664 		printf("%s: ACK %d too far in future!\n", __func__, rcv_ackno);
665 	else if (rcv_ackno >= nd_seqno) {
666 		/* We're interested in this ack. Record it. */
667 		rcvd_acks |= 1 << (rcv_ackno - nd_seqno);
668 	}
669 }
670 
671 /*
672  * Handler for ARP packets: checks their sanity and then
673  * 1. If the ARP is a request for our IP, respond with our MAC address
674  * 2. If the ARP is a response from our server, record its MAC address
675  *
676  * It needs to replicate partially the behaviour of arpintr() and
677  * in_arpinput().
678  *
679  * Parameters:
680  *	mb	a pointer to an mbuf * containing the packet received
681  *		Updates *mb if m_pullup et al change the pointer
682  *		Assumes the calling function will take care of freeing the mbuf
683  */
684 static void
685 netdump_handle_arp(struct mbuf **mb)
686 {
687 	char buf[INET_ADDRSTRLEN];
688 	struct in_addr isaddr, itaddr, myaddr;
689 	struct ether_addr dst;
690 	struct mbuf *m;
691 	struct arphdr *ah;
692 	struct ifnet *ifp;
693 	uint8_t *enaddr;
694 	int req_len, op;
695 
696 	m = *mb;
697 	ifp = m->m_pkthdr.rcvif;
698 	if (m->m_len < sizeof(struct arphdr)) {
699 		m = m_pullup(m, sizeof(struct arphdr));
700 		*mb = m;
701 		if (m == NULL) {
702 			NETDDEBUG("runt packet: m_pullup failed\n");
703 			return;
704 		}
705 	}
706 
707 	ah = mtod(m, struct arphdr *);
708 	if (ntohs(ah->ar_hrd) != ARPHRD_ETHER) {
709 		NETDDEBUG("unknown hardware address 0x%2D)\n",
710 		    (unsigned char *)&ah->ar_hrd, "");
711 		return;
712 	}
713 	if (ntohs(ah->ar_pro) != ETHERTYPE_IP) {
714 		NETDDEBUG("drop ARP for unknown protocol %d\n",
715 		    ntohs(ah->ar_pro));
716 		return;
717 	}
718 	req_len = arphdr_len2(ifp->if_addrlen, sizeof(struct in_addr));
719 	if (m->m_len < req_len) {
720 		m = m_pullup(m, req_len);
721 		*mb = m;
722 		if (m == NULL) {
723 			NETDDEBUG("runt packet: m_pullup failed\n");
724 			return;
725 		}
726 	}
727 	ah = mtod(m, struct arphdr *);
728 
729 	op = ntohs(ah->ar_op);
730 	memcpy(&isaddr, ar_spa(ah), sizeof(isaddr));
731 	memcpy(&itaddr, ar_tpa(ah), sizeof(itaddr));
732 	enaddr = (uint8_t *)IF_LLADDR(ifp);
733 	myaddr = nd_client;
734 
735 	if (memcmp(ar_sha(ah), enaddr, ifp->if_addrlen) == 0) {
736 		NETDDEBUG("ignoring ARP from myself\n");
737 		return;
738 	}
739 
740 	if (isaddr.s_addr == nd_client.s_addr) {
741 		printf("%s: %*D is using my IP address %s!\n", __func__,
742 		    ifp->if_addrlen, (u_char *)ar_sha(ah), ":",
743 		    inet_ntoa_r(isaddr, buf));
744 		return;
745 	}
746 
747 	if (memcmp(ar_sha(ah), ifp->if_broadcastaddr, ifp->if_addrlen) == 0) {
748 		NETDDEBUG("ignoring ARP from broadcast address\n");
749 		return;
750 	}
751 
752 	if (op == ARPOP_REPLY) {
753 		if (isaddr.s_addr != nd_gateway.s_addr &&
754 		    isaddr.s_addr != nd_server.s_addr) {
755 			inet_ntoa_r(isaddr, buf);
756 			NETDDEBUG(
757 			    "ignoring ARP reply from %s (not netdump server)\n",
758 			    buf);
759 			return;
760 		}
761 		memcpy(nd_gw_mac.octet, ar_sha(ah),
762 		    min(ah->ar_hln, ETHER_ADDR_LEN));
763 		have_gw_mac = 1;
764 		NETDDEBUG("got server MAC address %6D\n", nd_gw_mac.octet, ":");
765 		return;
766 	}
767 
768 	if (op != ARPOP_REQUEST) {
769 		NETDDEBUG("ignoring ARP non-request/reply\n");
770 		return;
771 	}
772 
773 	if (itaddr.s_addr != nd_client.s_addr) {
774 		NETDDEBUG("ignoring ARP not to our IP\n");
775 		return;
776 	}
777 
778 	memcpy(ar_tha(ah), ar_sha(ah), ah->ar_hln);
779 	memcpy(ar_sha(ah), enaddr, ah->ar_hln);
780 	memcpy(ar_tpa(ah), ar_spa(ah), ah->ar_pln);
781 	memcpy(ar_spa(ah), &itaddr, ah->ar_pln);
782 	ah->ar_op = htons(ARPOP_REPLY);
783 	ah->ar_pro = htons(ETHERTYPE_IP);
784 	m->m_flags &= ~(M_BCAST|M_MCAST);
785 	m->m_len = arphdr_len(ah);
786 	m->m_pkthdr.len = m->m_len;
787 
788 	memcpy(dst.octet, ar_tha(ah), ETHER_ADDR_LEN);
789 	netdump_ether_output(m, ifp, dst, ETHERTYPE_ARP);
790 	*mb = NULL;
791 }
792 
793 /*
794  * Handler for incoming packets directly from the network adapter
795  * Identifies the packet type (IP or ARP) and passes it along to one of the
796  * helper functions netdump_handle_ip or netdump_handle_arp.
797  *
798  * It needs to replicate partially the behaviour of ether_input() and
799  * ether_demux().
800  *
801  * Parameters:
802  *	ifp	the interface the packet came from (should be nd_ifp)
803  *	m	an mbuf containing the packet received
804  */
805 static void
806 netdump_pkt_in(struct ifnet *ifp, struct mbuf *m)
807 {
808 	struct ifreq ifr;
809 	struct ether_header *eh;
810 	u_short etype;
811 
812 	/* Ethernet processing. */
813 	if ((m->m_flags & M_PKTHDR) == 0) {
814 		NETDDEBUG_IF(ifp, "discard frame without packet header\n");
815 		goto done;
816 	}
817 	if (m->m_len < ETHER_HDR_LEN) {
818 		NETDDEBUG_IF(ifp,
819 	    "discard frame without leading eth header (len %u pktlen %u)\n",
820 		    m->m_len, m->m_pkthdr.len);
821 		goto done;
822 	}
823 	if ((m->m_flags & M_HASFCS) != 0) {
824 		m_adj(m, -ETHER_CRC_LEN);
825 		m->m_flags &= ~M_HASFCS;
826 	}
827 	eh = mtod(m, struct ether_header *);
828 	etype = ntohs(eh->ether_type);
829 	if ((m->m_flags & M_VLANTAG) != 0 || etype == ETHERTYPE_VLAN) {
830 		NETDDEBUG_IF(ifp, "ignoring vlan packets\n");
831 		goto done;
832 	}
833 	if (if_gethwaddr(ifp, &ifr) != 0) {
834 		NETDDEBUG_IF(ifp, "failed to get hw addr for interface\n");
835 		goto done;
836 	}
837 	if (memcmp(ifr.ifr_addr.sa_data, eh->ether_dhost,
838 	    ETHER_ADDR_LEN) != 0) {
839 		NETDDEBUG_IF(ifp,
840 		    "discard frame with incorrect destination addr\n");
841 		goto done;
842 	}
843 
844 	/* Done ethernet processing. Strip off the ethernet header. */
845 	m_adj(m, ETHER_HDR_LEN);
846 	switch (etype) {
847 	case ETHERTYPE_ARP:
848 		netdump_handle_arp(&m);
849 		break;
850 	case ETHERTYPE_IP:
851 		netdump_handle_ip(&m);
852 		break;
853 	default:
854 		NETDDEBUG_IF(ifp, "dropping unknown ethertype %hu\n", etype);
855 		break;
856 	}
857 done:
858 	if (m != NULL)
859 		m_freem(m);
860 }
861 
862 /*
863  * After trapping, instead of assuming that most of the network stack is sane,
864  * we just poll the driver directly for packets.
865  */
866 static void
867 netdump_network_poll(void)
868 {
869 
870 	MPASS(nd_ifp != NULL);
871 
872 	nd_ifp->if_netdump_methods->nd_poll(nd_ifp, 1000);
873 }
874 
875 /*-
876  * Dumping specific primitives.
877  */
878 
879 /*
880  * Callback from dumpsys() to dump a chunk of memory.
881  * Copies it out to our static buffer then sends it across the network.
882  * Detects the initial KDH and makes sure it is given a special packet type.
883  *
884  * Parameters:
885  *	priv	 Unused. Optional private pointer.
886  *	virtual  Virtual address (where to read the data from)
887  *	physical Unused. Physical memory address.
888  *	offset	 Offset from start of core file
889  *	length	 Data length
890  *
891  * Return value:
892  *	0 on success
893  *	errno on error
894  */
895 static int
896 netdump_dumper(void *priv __unused, void *virtual,
897     vm_offset_t physical __unused, off_t offset, size_t length)
898 {
899 	int error;
900 
901 	NETDDEBUGV("netdump_dumper(NULL, %p, NULL, %ju, %zu)\n",
902 	    virtual, (uintmax_t)offset, length);
903 
904 	if (virtual == NULL) {
905 		if (dump_failed != 0)
906 			printf("failed to dump the kernel core\n");
907 		else if (netdump_send(NETDUMP_FINISHED, 0, NULL, 0) != 0)
908 			printf("failed to close the transaction\n");
909 		else
910 			printf("\nnetdump finished.\n");
911 		netdump_cleanup();
912 		return (0);
913 	}
914 	if (length > sizeof(nd_buf))
915 		return (ENOSPC);
916 
917 	memmove(nd_buf, virtual, length);
918 	error = netdump_send(NETDUMP_VMCORE, offset, nd_buf, length);
919 	if (error != 0) {
920 		dump_failed = 1;
921 		return (error);
922 	}
923 	return (0);
924 }
925 
926 /*
927  * Perform any initalization needed prior to transmitting the kernel core.
928  */
929 static int
930 netdump_start(struct dumperinfo *di)
931 {
932 	char *path;
933 	char buf[INET_ADDRSTRLEN];
934 	uint32_t len;
935 	int error;
936 
937 	error = 0;
938 
939 	/* Check if the dumping is allowed to continue. */
940 	if (nd_enabled == 0)
941 		return (EINVAL);
942 
943 	if (panicstr == NULL) {
944 		printf(
945 		    "netdump_start: netdump may only be used after a panic\n");
946 		return (EINVAL);
947 	}
948 
949 	MPASS(nd_ifp != NULL);
950 
951 	if (nd_server.s_addr == INADDR_ANY) {
952 		printf("netdump_start: can't netdump; no server IP given\n");
953 		return (EINVAL);
954 	}
955 	if (nd_client.s_addr == INADDR_ANY) {
956 		printf("netdump_start: can't netdump; no client IP given\n");
957 		return (EINVAL);
958 	}
959 
960 	/* We start dumping at offset 0. */
961 	di->dumpoff = 0;
962 
963 	nd_seqno = 1;
964 
965 	/*
966 	 * nd_server_port could have switched after the first ack the
967 	 * first time it gets called.  Adjust it accordingly.
968 	 */
969 	nd_server_port = NETDUMP_PORT;
970 
971 	/* Switch to the netdump mbuf zones. */
972 	netdump_mbuf_dump();
973 
974 	nd_ifp->if_netdump_methods->nd_event(nd_ifp, NETDUMP_START);
975 
976 	/* Make the card use *our* receive callback. */
977 	drv_if_input = nd_ifp->if_input;
978 	nd_ifp->if_input = netdump_pkt_in;
979 
980 	if (nd_gateway.s_addr == INADDR_ANY) {
981 		restore_gw_addr = 1;
982 		nd_gateway.s_addr = nd_server.s_addr;
983 	}
984 
985 	printf("netdump in progress. searching for server...\n");
986 	if (netdump_arp_gw()) {
987 		printf("failed to locate server MAC address\n");
988 		error = EINVAL;
989 		goto trig_abort;
990 	}
991 
992 	if (nd_path[0] != '\0') {
993 		path = nd_path;
994 		len = strlen(path) + 1;
995 	} else {
996 		path = NULL;
997 		len = 0;
998 	}
999 	if (netdump_send(NETDUMP_HERALD, 0, path, len) != 0) {
1000 		printf("failed to contact netdump server\n");
1001 		error = EINVAL;
1002 		goto trig_abort;
1003 	}
1004 	printf("netdumping to %s (%6D)\n", inet_ntoa_r(nd_server, buf),
1005 	    nd_gw_mac.octet, ":");
1006 	return (0);
1007 
1008 trig_abort:
1009 	netdump_cleanup();
1010 	return (error);
1011 }
1012 
1013 static int
1014 netdump_write_headers(struct dumperinfo *di, struct kerneldumpheader *kdh,
1015     void *key, uint32_t keysize)
1016 {
1017 	int error;
1018 
1019 	memcpy(nd_buf, kdh, sizeof(*kdh));
1020 	error = netdump_send(NETDUMP_KDH, 0, nd_buf, sizeof(*kdh));
1021 	if (error == 0 && keysize > 0) {
1022 		if (keysize > sizeof(nd_buf))
1023 			return (EINVAL);
1024 		memcpy(nd_buf, key, keysize);
1025 		error = netdump_send(NETDUMP_EKCD_KEY, 0, nd_buf, keysize);
1026 	}
1027 	return (error);
1028 }
1029 
1030 /*
1031  * Cleanup routine for a possibly failed netdump.
1032  */
1033 static void
1034 netdump_cleanup(void)
1035 {
1036 
1037 	if (restore_gw_addr != 0) {
1038 		nd_gateway.s_addr = INADDR_ANY;
1039 		restore_gw_addr = 0;
1040 	}
1041 	if (drv_if_input != NULL) {
1042 		nd_ifp->if_input = drv_if_input;
1043 		drv_if_input = NULL;
1044 	}
1045 	nd_ifp->if_netdump_methods->nd_event(nd_ifp, NETDUMP_END);
1046 }
1047 
1048 /*-
1049  * KLD specific code.
1050  */
1051 
1052 static struct cdevsw netdump_cdevsw = {
1053 	.d_version =	D_VERSION,
1054 	.d_ioctl =	netdump_ioctl,
1055 	.d_name =	"netdump",
1056 };
1057 
1058 static struct cdev *netdump_cdev;
1059 
1060 static int
1061 netdump_configure(struct netdump_conf *conf)
1062 {
1063 	struct ifnet *ifp;
1064 
1065 	IFNET_RLOCK_NOSLEEP();
1066 	TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
1067 		if (strcmp(ifp->if_xname, conf->ndc_iface) == 0)
1068 			break;
1069 	}
1070 	/* XXX ref */
1071 	IFNET_RUNLOCK_NOSLEEP();
1072 
1073 	if (ifp == NULL)
1074 		return (ENOENT);
1075 	if ((if_getflags(ifp) & IFF_UP) == 0)
1076 		return (ENXIO);
1077 	if (!netdump_supported_nic(ifp) || ifp->if_type != IFT_ETHER)
1078 		return (EINVAL);
1079 
1080 	nd_ifp = ifp;
1081 	netdump_reinit(ifp);
1082 	memcpy(&nd_conf, conf, sizeof(nd_conf));
1083 	nd_enabled = 1;
1084 	return (0);
1085 }
1086 
1087 /*
1088  * Reinitialize the mbuf pool used by drivers while dumping. This is called
1089  * from the generic ioctl handler for SIOCSIFMTU after the driver has
1090  * reconfigured itself.
1091  */
1092 void
1093 netdump_reinit(struct ifnet *ifp)
1094 {
1095 	int clsize, nmbuf, ncl, nrxr;
1096 
1097 	if (ifp != nd_ifp)
1098 		return;
1099 
1100 	ifp->if_netdump_methods->nd_init(ifp, &nrxr, &ncl, &clsize);
1101 	KASSERT(nrxr > 0, ("invalid receive ring count %d", nrxr));
1102 
1103 	/*
1104 	 * We need two headers per message on the transmit side. Multiply by
1105 	 * four to give us some breathing room.
1106 	 */
1107 	nmbuf = ncl * (4 + nrxr);
1108 	ncl *= nrxr;
1109 	netdump_mbuf_reinit(nmbuf, ncl, clsize);
1110 }
1111 
1112 /*
1113  * ioctl(2) handler for the netdump device. This is currently only used to
1114  * register netdump as a dump device.
1115  *
1116  * Parameters:
1117  *     dev, Unused.
1118  *     cmd, The ioctl to be handled.
1119  *     addr, The parameter for the ioctl.
1120  *     flags, Unused.
1121  *     td, The thread invoking this ioctl.
1122  *
1123  * Returns:
1124  *     0 on success, and an errno value on failure.
1125  */
1126 static int
1127 netdump_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t addr,
1128     int flags __unused, struct thread *td)
1129 {
1130 	struct diocskerneldump_arg *kda;
1131 	struct dumperinfo dumper;
1132 	struct netdump_conf *conf;
1133 	uint8_t *encryptedkey;
1134 	int error;
1135 	u_int u;
1136 
1137 	error = 0;
1138 	switch (cmd) {
1139 	case DIOCSKERNELDUMP:
1140 		u = *(u_int *)addr;
1141 		if (u != 0) {
1142 			error = ENXIO;
1143 			break;
1144 		}
1145 
1146 		if (nd_enabled) {
1147 			nd_enabled = 0;
1148 			netdump_mbuf_drain();
1149 		}
1150 		break;
1151 	case NETDUMPGCONF:
1152 		conf = (struct netdump_conf *)addr;
1153 		if (!nd_enabled) {
1154 			error = ENXIO;
1155 			break;
1156 		}
1157 
1158 		strlcpy(conf->ndc_iface, nd_ifp->if_xname,
1159 		    sizeof(conf->ndc_iface));
1160 		memcpy(&conf->ndc_server, &nd_server, sizeof(nd_server));
1161 		memcpy(&conf->ndc_client, &nd_client, sizeof(nd_client));
1162 		memcpy(&conf->ndc_gateway, &nd_gateway, sizeof(nd_gateway));
1163 		break;
1164 	case NETDUMPSCONF:
1165 		conf = (struct netdump_conf *)addr;
1166 		encryptedkey = NULL;
1167 		kda = &conf->ndc_kda;
1168 
1169 		conf->ndc_iface[sizeof(conf->ndc_iface) - 1] = '\0';
1170 		if (kda->kda_enable == 0) {
1171 			if (nd_enabled) {
1172 				error = clear_dumper(td);
1173 				if (error == 0)
1174 					nd_enabled = 0;
1175 			}
1176 			break;
1177 		}
1178 
1179 		error = netdump_configure(conf);
1180 		if (error != 0)
1181 			break;
1182 
1183 		if (kda->kda_encryption != KERNELDUMP_ENC_NONE) {
1184 			if (kda->kda_encryptedkeysize <= 0 ||
1185 			    kda->kda_encryptedkeysize >
1186 			    KERNELDUMP_ENCKEY_MAX_SIZE)
1187 				return (EINVAL);
1188 			encryptedkey = malloc(kda->kda_encryptedkeysize, M_TEMP,
1189 			    M_WAITOK);
1190 			error = copyin(kda->kda_encryptedkey, encryptedkey,
1191 			    kda->kda_encryptedkeysize);
1192 			if (error != 0) {
1193 				free(encryptedkey, M_TEMP);
1194 				return (error);
1195 			}
1196 		}
1197 
1198 		dumper.dumper_start = netdump_start;
1199 		dumper.dumper_hdr = netdump_write_headers;
1200 		dumper.dumper = netdump_dumper;
1201 		dumper.priv = NULL;
1202 		dumper.blocksize = NETDUMP_DATASIZE;
1203 		dumper.maxiosize = MAXDUMPPGS * PAGE_SIZE;
1204 		dumper.mediaoffset = 0;
1205 		dumper.mediasize = 0;
1206 
1207 		error = set_dumper(&dumper, conf->ndc_iface, td,
1208 		    kda->kda_compression, kda->kda_encryption,
1209 		    kda->kda_key, kda->kda_encryptedkeysize,
1210 		    encryptedkey);
1211 		if (encryptedkey != NULL) {
1212 			explicit_bzero(encryptedkey, kda->kda_encryptedkeysize);
1213 			free(encryptedkey, M_TEMP);
1214 		}
1215 		if (error != 0)
1216 			nd_enabled = 0;
1217 		break;
1218 	default:
1219 		error = EINVAL;
1220 		break;
1221 	}
1222 	return (error);
1223 }
1224 
1225 /*
1226  * Called upon system init or kld load.  Initializes the netdump parameters to
1227  * sane defaults (locates the first available NIC and uses the first IPv4 IP on
1228  * that card as the client IP).  Leaves the server IP unconfigured.
1229  *
1230  * Parameters:
1231  *	mod, Unused.
1232  *	what, The module event type.
1233  *	priv, Unused.
1234  *
1235  * Returns:
1236  *	int, An errno value if an error occured, 0 otherwise.
1237  */
1238 static int
1239 netdump_modevent(module_t mod __unused, int what, void *priv __unused)
1240 {
1241 	struct netdump_conf conf;
1242 	char *arg;
1243 	int error;
1244 
1245 	error = 0;
1246 	switch (what) {
1247 	case MOD_LOAD:
1248 		error = make_dev_p(MAKEDEV_WAITOK, &netdump_cdev,
1249 		    &netdump_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "netdump");
1250 		if (error != 0)
1251 			return (error);
1252 
1253 		if ((arg = kern_getenv("net.dump.iface")) != NULL) {
1254 			strlcpy(conf.ndc_iface, arg, sizeof(conf.ndc_iface));
1255 			freeenv(arg);
1256 
1257 			if ((arg = kern_getenv("net.dump.server")) != NULL) {
1258 				inet_aton(arg, &conf.ndc_server);
1259 				freeenv(arg);
1260 			}
1261 			if ((arg = kern_getenv("net.dump.client")) != NULL) {
1262 				inet_aton(arg, &conf.ndc_server);
1263 				freeenv(arg);
1264 			}
1265 			if ((arg = kern_getenv("net.dump.gateway")) != NULL) {
1266 				inet_aton(arg, &conf.ndc_server);
1267 				freeenv(arg);
1268 			}
1269 
1270 			/* Ignore errors; we print a message to the console. */
1271 			(void)netdump_configure(&conf);
1272 		}
1273 		break;
1274 	case MOD_UNLOAD:
1275 		destroy_dev(netdump_cdev);
1276 		if (nd_enabled) {
1277 			printf("netdump: disabling dump device for unload\n");
1278 			(void)clear_dumper(curthread);
1279 			nd_enabled = 0;
1280 		}
1281 		break;
1282 	default:
1283 		error = EOPNOTSUPP;
1284 		break;
1285 	}
1286 	return (error);
1287 }
1288 
1289 static moduledata_t netdump_mod = {
1290 	"netdump",
1291 	netdump_modevent,
1292 	NULL,
1293 };
1294 
1295 MODULE_VERSION(netdump, 1);
1296 DECLARE_MODULE(netdump, netdump_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
1297