1098ca2bdSWarner Losh /*-
2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
3718cf2ccSPedro F. Giffuni *
4932ef5b5SEd Schouten * Copyright (c) 2008 Ed Schouten <ed@FreeBSD.org>
5932ef5b5SEd Schouten * All rights reserved.
6dde8a05bSUgen J.S. Antsilevich *
7932ef5b5SEd Schouten * Redistribution and use in source and binary forms, with or without
8932ef5b5SEd Schouten * modification, are permitted provided that the following conditions
9932ef5b5SEd Schouten * are met:
10932ef5b5SEd Schouten * 1. Redistributions of source code must retain the above copyright
11932ef5b5SEd Schouten * notice, this list of conditions and the following disclaimer.
12932ef5b5SEd Schouten * 2. Redistributions in binary form must reproduce the above copyright
13932ef5b5SEd Schouten * notice, this list of conditions and the following disclaimer in the
14932ef5b5SEd Schouten * documentation and/or other materials provided with the distribution.
15dde8a05bSUgen J.S. Antsilevich *
16932ef5b5SEd Schouten * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17932ef5b5SEd Schouten * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18932ef5b5SEd Schouten * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19932ef5b5SEd Schouten * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20932ef5b5SEd Schouten * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21932ef5b5SEd Schouten * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22932ef5b5SEd Schouten * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23932ef5b5SEd Schouten * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24932ef5b5SEd Schouten * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25932ef5b5SEd Schouten * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26932ef5b5SEd Schouten * SUCH DAMAGE.
27dde8a05bSUgen J.S. Antsilevich */
28dde8a05bSUgen J.S. Antsilevich
29dde8a05bSUgen J.S. Antsilevich #include <sys/param.h>
30932ef5b5SEd Schouten #include <sys/conf.h>
311ef0fc1dSPoul-Henning Kamp #include <sys/fcntl.h>
3271455815SBruce Evans #include <sys/filio.h>
33dde8a05bSUgen J.S. Antsilevich #include <sys/kernel.h>
34932ef5b5SEd Schouten #include <sys/malloc.h>
35fe12f24bSPoul-Henning Kamp #include <sys/module.h>
36932ef5b5SEd Schouten #include <sys/poll.h>
37a9385ad1SAlexander Motin #include <sys/proc.h>
3887f6c662SJulian Elischer #include <sys/snoop.h>
39932ef5b5SEd Schouten #include <sys/sx.h>
40932ef5b5SEd Schouten #include <sys/systm.h>
41932ef5b5SEd Schouten #include <sys/tty.h>
421ef0fc1dSPoul-Henning Kamp #include <sys/uio.h>
4387f6c662SJulian Elischer
44932ef5b5SEd Schouten static struct cdev *snp_dev;
457fb6f685SEd Schouten static MALLOC_DEFINE(M_SNP, "snp", "tty snoop device");
467fb6f685SEd Schouten
47932ef5b5SEd Schouten /* XXX: should be mtx, but TTY can be locked by Giant. */
487fb6f685SEd Schouten #if 0
497fb6f685SEd Schouten static struct mtx snp_register_lock;
507fb6f685SEd Schouten MTX_SYSINIT(snp_register_lock, &snp_register_lock,
517fb6f685SEd Schouten "tty snoop registration", MTX_DEF);
527fb6f685SEd Schouten #define SNP_LOCK() mtx_lock(&snp_register_lock)
537fb6f685SEd Schouten #define SNP_UNLOCK() mtx_unlock(&snp_register_lock)
547fb6f685SEd Schouten #else
55932ef5b5SEd Schouten static struct sx snp_register_lock;
56932ef5b5SEd Schouten SX_SYSINIT(snp_register_lock, &snp_register_lock,
57932ef5b5SEd Schouten "tty snoop registration");
587fb6f685SEd Schouten #define SNP_LOCK() sx_xlock(&snp_register_lock)
597fb6f685SEd Schouten #define SNP_UNLOCK() sx_xunlock(&snp_register_lock)
607fb6f685SEd Schouten #endif
61932ef5b5SEd Schouten
6269921123SKonstantin Belousov #define SNPGTYY_32DEV _IOR('T', 89, uint32_t)
6369921123SKonstantin Belousov
64932ef5b5SEd Schouten /*
65932ef5b5SEd Schouten * There is no need to have a big input buffer. In most typical setups,
66932ef5b5SEd Schouten * we won't inject much data into the TTY, because users can't type
67932ef5b5SEd Schouten * really fast.
68932ef5b5SEd Schouten */
69932ef5b5SEd Schouten #define SNP_INPUT_BUFSIZE 16
70932ef5b5SEd Schouten /*
71932ef5b5SEd Schouten * The output buffer has to be really big. Right now we don't support
72932ef5b5SEd Schouten * any form of flow control, which means we lost any data we can't
73932ef5b5SEd Schouten * accept. We set the output buffer size to about twice the size of a
74932ef5b5SEd Schouten * pseudo-terminal/virtual console's output buffer.
75932ef5b5SEd Schouten */
76932ef5b5SEd Schouten #define SNP_OUTPUT_BUFSIZE 16384
77932ef5b5SEd Schouten
78932ef5b5SEd Schouten static d_open_t snp_open;
79932ef5b5SEd Schouten static d_read_t snp_read;
80932ef5b5SEd Schouten static d_write_t snp_write;
81932ef5b5SEd Schouten static d_ioctl_t snp_ioctl;
82932ef5b5SEd Schouten static d_poll_t snp_poll;
8387f6c662SJulian Elischer
844e2f199eSPoul-Henning Kamp static struct cdevsw snp_cdevsw = {
85dc08ffecSPoul-Henning Kamp .d_version = D_VERSION,
86932ef5b5SEd Schouten .d_open = snp_open,
87932ef5b5SEd Schouten .d_read = snp_read,
88932ef5b5SEd Schouten .d_write = snp_write,
89932ef5b5SEd Schouten .d_ioctl = snp_ioctl,
90932ef5b5SEd Schouten .d_poll = snp_poll,
917ac40f5fSPoul-Henning Kamp .d_name = "snp",
924e2f199eSPoul-Henning Kamp };
9387f6c662SJulian Elischer
94932ef5b5SEd Schouten static th_getc_capture_t snp_getc_capture;
95932ef5b5SEd Schouten
96932ef5b5SEd Schouten static struct ttyhook snp_hook = {
97932ef5b5SEd Schouten .th_getc_capture = snp_getc_capture,
98f09f49f1SDima Dorfman };
9953ac6efbSJulian Elischer
100101f105dSDima Dorfman /*
101932ef5b5SEd Schouten * Per-instance structure.
102932ef5b5SEd Schouten *
103932ef5b5SEd Schouten * List of locks
104932ef5b5SEd Schouten * (r) locked by snp_register_lock on assignment
105932ef5b5SEd Schouten * (t) locked by tty_lock
106101f105dSDima Dorfman */
107932ef5b5SEd Schouten struct snp_softc {
108932ef5b5SEd Schouten struct tty *snp_tty; /* (r) TTY we're snooping. */
109932ef5b5SEd Schouten struct ttyoutq snp_outq; /* (t) Output queue. */
110932ef5b5SEd Schouten struct cv snp_outwait; /* (t) Output wait queue. */
111932ef5b5SEd Schouten struct selinfo snp_outpoll; /* (t) Output polling. */
112101f105dSDima Dorfman };
113101f105dSDima Dorfman
1142e37c8eaSEd Schouten static void
snp_dtor(void * data)1152e37c8eaSEd Schouten snp_dtor(void *data)
1162e37c8eaSEd Schouten {
117932ef5b5SEd Schouten struct snp_softc *ss = data;
118932ef5b5SEd Schouten struct tty *tp;
1192e37c8eaSEd Schouten
120932ef5b5SEd Schouten tp = ss->snp_tty;
121932ef5b5SEd Schouten if (tp != NULL) {
122932ef5b5SEd Schouten tty_lock(tp);
123932ef5b5SEd Schouten ttyoutq_free(&ss->snp_outq);
124932ef5b5SEd Schouten ttyhook_unregister(tp);
125550e01c5SKonstantin Belousov ss->snp_tty = NULL;
126932ef5b5SEd Schouten }
127932ef5b5SEd Schouten
128932ef5b5SEd Schouten cv_destroy(&ss->snp_outwait);
129932ef5b5SEd Schouten free(ss, M_SNP);
130932ef5b5SEd Schouten }
131932ef5b5SEd Schouten
132932ef5b5SEd Schouten /*
133932ef5b5SEd Schouten * Snoop device node routines.
134932ef5b5SEd Schouten */
135932ef5b5SEd Schouten
136932ef5b5SEd Schouten static int
snp_open(struct cdev * dev,int flag,int mode,struct thread * td)137932ef5b5SEd Schouten snp_open(struct cdev *dev, int flag, int mode, struct thread *td)
138932ef5b5SEd Schouten {
139932ef5b5SEd Schouten struct snp_softc *ss;
140932ef5b5SEd Schouten
141932ef5b5SEd Schouten /* Allocate per-snoop data. */
142932ef5b5SEd Schouten ss = malloc(sizeof(struct snp_softc), M_SNP, M_WAITOK|M_ZERO);
143932ef5b5SEd Schouten cv_init(&ss->snp_outwait, "snp out");
144932ef5b5SEd Schouten
145932ef5b5SEd Schouten devfs_set_cdevpriv(ss, snp_dtor);
146932ef5b5SEd Schouten
147932ef5b5SEd Schouten return (0);
1482e37c8eaSEd Schouten }
1492e37c8eaSEd Schouten
15087f6c662SJulian Elischer static int
snp_read(struct cdev * dev,struct uio * uio,int flag)151932ef5b5SEd Schouten snp_read(struct cdev *dev, struct uio *uio, int flag)
152dde8a05bSUgen J.S. Antsilevich {
153932ef5b5SEd Schouten int error, oresid = uio->uio_resid;
154932ef5b5SEd Schouten struct snp_softc *ss;
155932ef5b5SEd Schouten struct tty *tp;
156dde8a05bSUgen J.S. Antsilevich
157932ef5b5SEd Schouten if (uio->uio_resid == 0)
158932ef5b5SEd Schouten return (0);
159932ef5b5SEd Schouten
160932ef5b5SEd Schouten error = devfs_get_cdevpriv((void **)&ss);
161932ef5b5SEd Schouten if (error != 0)
162932ef5b5SEd Schouten return (error);
163932ef5b5SEd Schouten
164932ef5b5SEd Schouten tp = ss->snp_tty;
165932ef5b5SEd Schouten if (tp == NULL || tty_gone(tp))
166932ef5b5SEd Schouten return (EIO);
167932ef5b5SEd Schouten
168932ef5b5SEd Schouten tty_lock(tp);
169932ef5b5SEd Schouten for (;;) {
170932ef5b5SEd Schouten error = ttyoutq_read_uio(&ss->snp_outq, tp, uio);
171932ef5b5SEd Schouten if (error != 0 || uio->uio_resid != oresid)
172932ef5b5SEd Schouten break;
173932ef5b5SEd Schouten
174932ef5b5SEd Schouten /* Wait for more data. */
175932ef5b5SEd Schouten if (flag & O_NONBLOCK) {
176932ef5b5SEd Schouten error = EWOULDBLOCK;
177932ef5b5SEd Schouten break;
178932ef5b5SEd Schouten }
179ed623289SKyle Evans error = cv_wait_sig(&ss->snp_outwait, tty_getlock(tp));
180932ef5b5SEd Schouten if (error != 0)
181932ef5b5SEd Schouten break;
182932ef5b5SEd Schouten if (tty_gone(tp)) {
183932ef5b5SEd Schouten error = EIO;
184932ef5b5SEd Schouten break;
185932ef5b5SEd Schouten }
186932ef5b5SEd Schouten }
187932ef5b5SEd Schouten tty_unlock(tp);
188932ef5b5SEd Schouten
1892e37c8eaSEd Schouten return (error);
1902e37c8eaSEd Schouten }
19177f77631SPaul Traina
192932ef5b5SEd Schouten static int
snp_write(struct cdev * dev,struct uio * uio,int flag)193932ef5b5SEd Schouten snp_write(struct cdev *dev, struct uio *uio, int flag)
194019b4d63SUgen J.S. Antsilevich {
195932ef5b5SEd Schouten struct snp_softc *ss;
196019b4d63SUgen J.S. Antsilevich struct tty *tp;
1975c67885aSEd Schouten int error, len;
198932ef5b5SEd Schouten char in[SNP_INPUT_BUFSIZE];
199019b4d63SUgen J.S. Antsilevich
200932ef5b5SEd Schouten error = devfs_get_cdevpriv((void **)&ss);
201932ef5b5SEd Schouten if (error != 0)
202932ef5b5SEd Schouten return (error);
203932ef5b5SEd Schouten
204932ef5b5SEd Schouten tp = ss->snp_tty;
205932ef5b5SEd Schouten if (tp == NULL || tty_gone(tp))
206932ef5b5SEd Schouten return (EIO);
207932ef5b5SEd Schouten
208932ef5b5SEd Schouten while (uio->uio_resid > 0) {
209932ef5b5SEd Schouten /* Read new data. */
210932ef5b5SEd Schouten len = imin(uio->uio_resid, sizeof in);
211932ef5b5SEd Schouten error = uiomove(in, len, uio);
212932ef5b5SEd Schouten if (error != 0)
213932ef5b5SEd Schouten return (error);
214932ef5b5SEd Schouten
215932ef5b5SEd Schouten tty_lock(tp);
216932ef5b5SEd Schouten
217932ef5b5SEd Schouten /* Driver could have abandoned the TTY in the mean time. */
218932ef5b5SEd Schouten if (tty_gone(tp)) {
219932ef5b5SEd Schouten tty_unlock(tp);
220932ef5b5SEd Schouten return (ENXIO);
221932ef5b5SEd Schouten }
222019b4d63SUgen J.S. Antsilevich
223019b4d63SUgen J.S. Antsilevich /*
224932ef5b5SEd Schouten * Deliver data to the TTY. Ignore errors for now,
225932ef5b5SEd Schouten * because we shouldn't bail out when we're running
226932ef5b5SEd Schouten * close to the watermarks.
227019b4d63SUgen J.S. Antsilevich */
2285c67885aSEd Schouten ttydisc_rint_simple(tp, in, len);
229932ef5b5SEd Schouten ttydisc_rint_done(tp);
2305c67885aSEd Schouten
231932ef5b5SEd Schouten tty_unlock(tp);
23276e90dbcSBrian Feldman }
233dde8a05bSUgen J.S. Antsilevich
234542a8db5SKonstantin Belousov return (0);
235964587caSUgen J.S. Antsilevich }
236dde8a05bSUgen J.S. Antsilevich
23787f6c662SJulian Elischer static int
snp_ioctl(struct cdev * dev,u_long cmd,caddr_t data,int flags,struct thread * td)238932ef5b5SEd Schouten snp_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flags,
2397409f6cdSCraig Rodrigues struct thread *td)
240dde8a05bSUgen J.S. Antsilevich {
241932ef5b5SEd Schouten struct snp_softc *ss;
242316d90a3SKonstantin Belousov struct tty *tp;
243932ef5b5SEd Schouten int error;
244dde8a05bSUgen J.S. Antsilevich
245932ef5b5SEd Schouten error = devfs_get_cdevpriv((void **)&ss);
2462e37c8eaSEd Schouten if (error != 0)
2472e37c8eaSEd Schouten return (error);
2482e37c8eaSEd Schouten
249dde8a05bSUgen J.S. Antsilevich switch (cmd) {
250dde8a05bSUgen J.S. Antsilevich case SNPSTTY:
251932ef5b5SEd Schouten /* Bind TTY to snoop instance. */
2527fb6f685SEd Schouten SNP_LOCK();
253550e01c5SKonstantin Belousov tp = ss->snp_tty;
254550e01c5SKonstantin Belousov if (tp != NULL) {
255550e01c5SKonstantin Belousov if (*(int *)data == -1) {
256550e01c5SKonstantin Belousov tty_lock(tp);
257550e01c5SKonstantin Belousov ss->snp_tty = NULL;
258550e01c5SKonstantin Belousov ttyoutq_free(&ss->snp_outq);
259550e01c5SKonstantin Belousov ttyhook_unregister(tp);
260550e01c5SKonstantin Belousov error = 0;
261550e01c5SKonstantin Belousov } else {
262550e01c5SKonstantin Belousov error = EBUSY;
263550e01c5SKonstantin Belousov }
2647fb6f685SEd Schouten SNP_UNLOCK();
265550e01c5SKonstantin Belousov return (error);
26630ce1aadSOlivier Houchard }
267a9d2f8d8SRobert Watson /*
268a9d2f8d8SRobert Watson * XXXRW / XXXJA: no capability check here.
269a9d2f8d8SRobert Watson */
270aa16f86cSEd Schouten error = ttyhook_register(&ss->snp_tty, td->td_proc,
271aa16f86cSEd Schouten *(int *)data, &snp_hook, ss);
2727fb6f685SEd Schouten SNP_UNLOCK();
273932ef5b5SEd Schouten if (error != 0)
274932ef5b5SEd Schouten return (error);
275964587caSUgen J.S. Antsilevich
276932ef5b5SEd Schouten /* Now that went okay, allocate a buffer for the queue. */
277932ef5b5SEd Schouten tp = ss->snp_tty;
278932ef5b5SEd Schouten tty_lock(tp);
279932ef5b5SEd Schouten ttyoutq_setsize(&ss->snp_outq, tp, SNP_OUTPUT_BUFSIZE);
280932ef5b5SEd Schouten tty_unlock(tp);
281316d90a3SKonstantin Belousov
282932ef5b5SEd Schouten return (0);
283dde8a05bSUgen J.S. Antsilevich case SNPGTTY:
284932ef5b5SEd Schouten /* Obtain device number of associated TTY. */
285932ef5b5SEd Schouten if (ss->snp_tty == NULL)
286932ef5b5SEd Schouten *(dev_t *)data = NODEV;
287dde8a05bSUgen J.S. Antsilevich else
288932ef5b5SEd Schouten *(dev_t *)data = tty_udev(ss->snp_tty);
289932ef5b5SEd Schouten return (0);
29069921123SKonstantin Belousov case SNPGTYY_32DEV:
29169921123SKonstantin Belousov if (ss->snp_tty == NULL)
29269921123SKonstantin Belousov *(uint32_t *)data = -1;
29369921123SKonstantin Belousov else
29469921123SKonstantin Belousov *(uint32_t *)data = tty_udev(ss->snp_tty); /* trunc */
29569921123SKonstantin Belousov return (0);
296dde8a05bSUgen J.S. Antsilevich case FIONREAD:
297932ef5b5SEd Schouten tp = ss->snp_tty;
298932ef5b5SEd Schouten if (tp != NULL) {
299932ef5b5SEd Schouten tty_lock(tp);
300bb4be76cSKonstantin Belousov if (tty_gone(tp))
301bb4be76cSKonstantin Belousov *(int *)data = SNP_TTYCLOSE;
302bb4be76cSKonstantin Belousov else
303932ef5b5SEd Schouten *(int *)data = ttyoutq_bytesused(&ss->snp_outq);
304932ef5b5SEd Schouten tty_unlock(tp);
305964587caSUgen J.S. Antsilevich } else {
306bb4be76cSKonstantin Belousov *(int *)data = SNP_DETACH;
307964587caSUgen J.S. Antsilevich }
308932ef5b5SEd Schouten return (0);
309dde8a05bSUgen J.S. Antsilevich default:
310dde8a05bSUgen J.S. Antsilevich return (ENOTTY);
311dde8a05bSUgen J.S. Antsilevich }
312dde8a05bSUgen J.S. Antsilevich }
313dde8a05bSUgen J.S. Antsilevich
31487f6c662SJulian Elischer static int
snp_poll(struct cdev * dev,int events,struct thread * td)315932ef5b5SEd Schouten snp_poll(struct cdev *dev, int events, struct thread *td)
316dde8a05bSUgen J.S. Antsilevich {
317932ef5b5SEd Schouten struct snp_softc *ss;
318932ef5b5SEd Schouten struct tty *tp;
319f09f49f1SDima Dorfman int revents;
320dde8a05bSUgen J.S. Antsilevich
321932ef5b5SEd Schouten if (devfs_get_cdevpriv((void **)&ss) != 0)
3222e37c8eaSEd Schouten return (events &
3232e37c8eaSEd Schouten (POLLHUP|POLLIN|POLLRDNORM|POLLOUT|POLLWRNORM));
3242e37c8eaSEd Schouten
325f09f49f1SDima Dorfman revents = 0;
326932ef5b5SEd Schouten
327dfd5dee1SPeter Wemm if (events & (POLLIN | POLLRDNORM)) {
328932ef5b5SEd Schouten tp = ss->snp_tty;
329932ef5b5SEd Schouten if (tp != NULL) {
330932ef5b5SEd Schouten tty_lock(tp);
331932ef5b5SEd Schouten if (ttyoutq_bytesused(&ss->snp_outq) > 0)
332659ffb48SPeter Wemm revents |= events & (POLLIN | POLLRDNORM);
333932ef5b5SEd Schouten tty_unlock(tp);
334dfd5dee1SPeter Wemm }
335932ef5b5SEd Schouten }
336932ef5b5SEd Schouten
337932ef5b5SEd Schouten if (revents == 0)
338932ef5b5SEd Schouten selrecord(td, &ss->snp_outpoll);
339932ef5b5SEd Schouten
340659ffb48SPeter Wemm return (revents);
341dde8a05bSUgen J.S. Antsilevich }
342dde8a05bSUgen J.S. Antsilevich
343932ef5b5SEd Schouten /*
344932ef5b5SEd Schouten * TTY hook events.
345932ef5b5SEd Schouten */
346932ef5b5SEd Schouten
34747eaa5f5SDima Dorfman static int
snp_modevent(module_t mod,int type,void * data)3487409f6cdSCraig Rodrigues snp_modevent(module_t mod, int type, void *data)
34953ac6efbSJulian Elischer {
35053ac6efbSJulian Elischer
35147eaa5f5SDima Dorfman switch (type) {
35247eaa5f5SDima Dorfman case MOD_LOAD:
353932ef5b5SEd Schouten snp_dev = make_dev(&snp_cdevsw, 0,
354932ef5b5SEd Schouten UID_ROOT, GID_WHEEL, 0600, "snp");
355932ef5b5SEd Schouten return (0);
35647eaa5f5SDima Dorfman case MOD_UNLOAD:
357932ef5b5SEd Schouten /* XXX: Make existing users leave. */
358932ef5b5SEd Schouten destroy_dev(snp_dev);
359932ef5b5SEd Schouten return (0);
36047eaa5f5SDima Dorfman default:
3613e019deaSPoul-Henning Kamp return (EOPNOTSUPP);
36247eaa5f5SDima Dorfman }
363932ef5b5SEd Schouten }
364932ef5b5SEd Schouten
365932ef5b5SEd Schouten static void
snp_getc_capture(struct tty * tp,const void * buf,size_t len)366932ef5b5SEd Schouten snp_getc_capture(struct tty *tp, const void *buf, size_t len)
367932ef5b5SEd Schouten {
368932ef5b5SEd Schouten struct snp_softc *ss = ttyhook_softc(tp);
369932ef5b5SEd Schouten
370932ef5b5SEd Schouten ttyoutq_write(&ss->snp_outq, buf, len);
371932ef5b5SEd Schouten
372932ef5b5SEd Schouten cv_broadcast(&ss->snp_outwait);
373932ef5b5SEd Schouten selwakeup(&ss->snp_outpoll);
3747198bf47SJulian Elischer }
37553ac6efbSJulian Elischer
37647eaa5f5SDima Dorfman static moduledata_t snp_mod = {
37747eaa5f5SDima Dorfman "snp",
37847eaa5f5SDima Dorfman snp_modevent,
37947eaa5f5SDima Dorfman NULL
38047eaa5f5SDima Dorfman };
381932ef5b5SEd Schouten
382b0b03348SPoul-Henning Kamp DECLARE_MODULE(snp, snp_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
383