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