1b06ebda0SMatthew Dillon /*-
2b06ebda0SMatthew Dillon * Copyright (c) 2002 Mark Santcroos <marks@ripe.net>
3b06ebda0SMatthew Dillon * Copyright (c) 2004-2005 Gleb Smirnoff <glebius@FreeBSD.org>
4b06ebda0SMatthew Dillon *
5b06ebda0SMatthew Dillon * Redistribution and use in source and binary forms, with or without
6b06ebda0SMatthew Dillon * modification, are permitted provided that the following conditions
7b06ebda0SMatthew Dillon * are met:
8b06ebda0SMatthew Dillon * 1. Redistributions of source code must retain the above copyright
9b06ebda0SMatthew Dillon * notice, this list of conditions and the following disclaimer.
10b06ebda0SMatthew Dillon * 2. Redistributions in binary form must reproduce the above copyright
11b06ebda0SMatthew Dillon * notice, this list of conditions and the following disclaimer in the
12b06ebda0SMatthew Dillon * documentation and/or other materials provided with the distribution.
13b06ebda0SMatthew Dillon *
14b06ebda0SMatthew Dillon * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15b06ebda0SMatthew Dillon * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16b06ebda0SMatthew Dillon * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17b06ebda0SMatthew Dillon * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18b06ebda0SMatthew Dillon * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19b06ebda0SMatthew Dillon * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20b06ebda0SMatthew Dillon * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21b06ebda0SMatthew Dillon * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22b06ebda0SMatthew Dillon * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23b06ebda0SMatthew Dillon * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24b06ebda0SMatthew Dillon *
25b06ebda0SMatthew Dillon * Netgraph "device" node
26b06ebda0SMatthew Dillon *
27b06ebda0SMatthew Dillon * This node presents a /dev/ngd%d device that interfaces to an other
28b06ebda0SMatthew Dillon * netgraph node.
29b06ebda0SMatthew Dillon *
30b06ebda0SMatthew Dillon * $FreeBSD: src/sys/netgraph/ng_device.c,v 1.22 2006/11/02 17:37:21 andre Exp $
31b06ebda0SMatthew Dillon *
32b06ebda0SMatthew Dillon */
33b06ebda0SMatthew Dillon
34b06ebda0SMatthew Dillon #if 0
35a62226e4SSascha Wildner #define DBG do { kprintf("ng_device: %s\n", __func__ ); } while (0)
36b06ebda0SMatthew Dillon #else
37b06ebda0SMatthew Dillon #define DBG do {} while (0)
38b06ebda0SMatthew Dillon #endif
39b06ebda0SMatthew Dillon
40b06ebda0SMatthew Dillon #include <sys/param.h>
41b06ebda0SMatthew Dillon #include <sys/conf.h>
42b06ebda0SMatthew Dillon #include <sys/kernel.h>
43b06ebda0SMatthew Dillon #include <sys/malloc.h>
44b06ebda0SMatthew Dillon #include <sys/mbuf.h>
45b06ebda0SMatthew Dillon #include <sys/poll.h>
46b06ebda0SMatthew Dillon #include <sys/queue.h>
47b06ebda0SMatthew Dillon #include <sys/socket.h>
48b06ebda0SMatthew Dillon #include <sys/systm.h>
49b06ebda0SMatthew Dillon #include <sys/uio.h>
50b06ebda0SMatthew Dillon #include <sys/vnode.h>
51b06ebda0SMatthew Dillon
52b06ebda0SMatthew Dillon #include <net/if.h>
53b06ebda0SMatthew Dillon #include <net/if_var.h>
54b06ebda0SMatthew Dillon #include <netinet/in.h>
55b06ebda0SMatthew Dillon #include <netinet/in_systm.h>
56b06ebda0SMatthew Dillon #include <netinet/ip.h>
57b06ebda0SMatthew Dillon
585a975a3dSMatthew Dillon #include "ng_message.h"
595a975a3dSMatthew Dillon #include "netgraph.h"
605a975a3dSMatthew Dillon #include "ng_device.h"
61b06ebda0SMatthew Dillon
62b06ebda0SMatthew Dillon #define ERROUT(x) do { error = (x); goto done; } while (0)
63b06ebda0SMatthew Dillon
64b06ebda0SMatthew Dillon /* Netgraph methods */
65b06ebda0SMatthew Dillon static int ng_device_mod_event(module_t, int, void *);
66b06ebda0SMatthew Dillon static ng_constructor_t ng_device_constructor;
67b06ebda0SMatthew Dillon static ng_rcvmsg_t ng_device_rcvmsg;
68b06ebda0SMatthew Dillon static ng_shutdown_t ng_device_shutdown;
69b06ebda0SMatthew Dillon static ng_newhook_t ng_device_newhook;
70b06ebda0SMatthew Dillon static ng_rcvdata_t ng_device_rcvdata;
71b06ebda0SMatthew Dillon static ng_disconnect_t ng_device_disconnect;
72b06ebda0SMatthew Dillon
73b06ebda0SMatthew Dillon /* Netgraph type */
74b06ebda0SMatthew Dillon static struct ng_type ngd_typestruct = {
75b06ebda0SMatthew Dillon .version = NG_ABI_VERSION,
76b06ebda0SMatthew Dillon .name = NG_DEVICE_NODE_TYPE,
77b06ebda0SMatthew Dillon .mod_event = ng_device_mod_event,
78b06ebda0SMatthew Dillon .constructor = ng_device_constructor,
79b06ebda0SMatthew Dillon .rcvmsg = ng_device_rcvmsg,
80b06ebda0SMatthew Dillon .shutdown = ng_device_shutdown,
81b06ebda0SMatthew Dillon .newhook = ng_device_newhook,
82b06ebda0SMatthew Dillon .rcvdata = ng_device_rcvdata,
83b06ebda0SMatthew Dillon .disconnect = ng_device_disconnect,
84b06ebda0SMatthew Dillon };
85b06ebda0SMatthew Dillon NETGRAPH_INIT(device, &ngd_typestruct);
86b06ebda0SMatthew Dillon
87b06ebda0SMatthew Dillon /* per node data */
88b06ebda0SMatthew Dillon struct ngd_private {
89b06ebda0SMatthew Dillon struct ifqueue readq;
90b06ebda0SMatthew Dillon struct ng_node *node;
91b06ebda0SMatthew Dillon struct ng_hook *hook;
92b06ebda0SMatthew Dillon struct cdev *ngddev;
93b06ebda0SMatthew Dillon struct mtx ngd_mtx;
94b06ebda0SMatthew Dillon int unit;
95b06ebda0SMatthew Dillon uint16_t flags;
96b06ebda0SMatthew Dillon #define NGDF_OPEN 0x0001
97b06ebda0SMatthew Dillon #define NGDF_RWAIT 0x0002
98b06ebda0SMatthew Dillon };
99b06ebda0SMatthew Dillon typedef struct ngd_private *priv_p;
100b06ebda0SMatthew Dillon
101b06ebda0SMatthew Dillon /* unit number allocator entity */
102b06ebda0SMatthew Dillon static struct unrhdr *ngd_unit;
103b06ebda0SMatthew Dillon
104b06ebda0SMatthew Dillon /* Maximum number of NGD devices */
105b06ebda0SMatthew Dillon #define MAX_NGD 999
106b06ebda0SMatthew Dillon
107b06ebda0SMatthew Dillon static d_close_t ngdclose;
108b06ebda0SMatthew Dillon static d_open_t ngdopen;
109b06ebda0SMatthew Dillon static d_read_t ngdread;
110b06ebda0SMatthew Dillon static d_write_t ngdwrite;
111b06ebda0SMatthew Dillon #if 0
112b06ebda0SMatthew Dillon static d_ioctl_t ngdioctl;
113b06ebda0SMatthew Dillon #endif
114b06ebda0SMatthew Dillon static d_poll_t ngdpoll;
115b06ebda0SMatthew Dillon
116b06ebda0SMatthew Dillon static struct cdevsw ngd_cdevsw = {
117b06ebda0SMatthew Dillon .d_version = D_VERSION,
118b06ebda0SMatthew Dillon .d_open = ngdopen,
119b06ebda0SMatthew Dillon .d_close = ngdclose,
120b06ebda0SMatthew Dillon .d_read = ngdread,
121b06ebda0SMatthew Dillon .d_write = ngdwrite,
122b06ebda0SMatthew Dillon #if 0
123b06ebda0SMatthew Dillon .d_ioctl = ngdioctl,
124b06ebda0SMatthew Dillon #endif
125b06ebda0SMatthew Dillon .d_poll = ngdpoll,
126b06ebda0SMatthew Dillon .d_name = NG_DEVICE_DEVNAME,
127b06ebda0SMatthew Dillon };
128b06ebda0SMatthew Dillon
129b06ebda0SMatthew Dillon /******************************************************************************
130b06ebda0SMatthew Dillon * Netgraph methods
131b06ebda0SMatthew Dillon ******************************************************************************/
132b06ebda0SMatthew Dillon
133b06ebda0SMatthew Dillon /*
134b06ebda0SMatthew Dillon * Handle loading and unloading for this node type.
135b06ebda0SMatthew Dillon */
136b06ebda0SMatthew Dillon static int
ng_device_mod_event(module_t mod,int event,void * data)137b06ebda0SMatthew Dillon ng_device_mod_event(module_t mod, int event, void *data)
138b06ebda0SMatthew Dillon {
139b06ebda0SMatthew Dillon int error = 0;
140b06ebda0SMatthew Dillon
141b06ebda0SMatthew Dillon switch (event) {
142b06ebda0SMatthew Dillon case MOD_LOAD:
143b06ebda0SMatthew Dillon ngd_unit = new_unrhdr(0, MAX_NGD, NULL);
144b06ebda0SMatthew Dillon break;
145b06ebda0SMatthew Dillon case MOD_UNLOAD:
146b06ebda0SMatthew Dillon delete_unrhdr(ngd_unit);
147b06ebda0SMatthew Dillon break;
148b06ebda0SMatthew Dillon default:
149b06ebda0SMatthew Dillon error = EOPNOTSUPP;
150b06ebda0SMatthew Dillon break;
151b06ebda0SMatthew Dillon }
152b06ebda0SMatthew Dillon return (error);
153b06ebda0SMatthew Dillon }
154b06ebda0SMatthew Dillon
155b06ebda0SMatthew Dillon /*
156b06ebda0SMatthew Dillon * create new node
157b06ebda0SMatthew Dillon */
158b06ebda0SMatthew Dillon static int
ng_device_constructor(node_p node)159b06ebda0SMatthew Dillon ng_device_constructor(node_p node)
160b06ebda0SMatthew Dillon {
161b06ebda0SMatthew Dillon priv_p priv;
162b06ebda0SMatthew Dillon
163b06ebda0SMatthew Dillon DBG;
164b06ebda0SMatthew Dillon
165fc025606SSascha Wildner priv = kmalloc(sizeof(*priv), M_NETGRAPH, M_WAITOK | M_ZERO);
166b06ebda0SMatthew Dillon
167b06ebda0SMatthew Dillon /* Allocate unit number */
168b06ebda0SMatthew Dillon priv->unit = alloc_unr(ngd_unit);
169b06ebda0SMatthew Dillon
170b06ebda0SMatthew Dillon /* Initialize mutexes and queue */
171b06ebda0SMatthew Dillon mtx_init(&priv->ngd_mtx, "ng_device", NULL, MTX_DEF);
172b06ebda0SMatthew Dillon mtx_init(&priv->readq.ifq_mtx, "ng_device queue", NULL, MTX_DEF);
173b06ebda0SMatthew Dillon IFQ_SET_MAXLEN(&priv->readq, ifqmaxlen);
174b06ebda0SMatthew Dillon
175b06ebda0SMatthew Dillon /* Link everything together */
176b06ebda0SMatthew Dillon NG_NODE_SET_PRIVATE(node, priv);
177b06ebda0SMatthew Dillon priv->node = node;
178b06ebda0SMatthew Dillon
179b06ebda0SMatthew Dillon priv->ngddev = make_dev(&ngd_cdevsw, unit2minor(priv->unit), UID_ROOT,
180b06ebda0SMatthew Dillon GID_WHEEL, 0600, NG_DEVICE_DEVNAME "%d", priv->unit);
181b06ebda0SMatthew Dillon if(priv->ngddev == NULL) {
182a62226e4SSascha Wildner kprintf("%s(): make_dev() failed\n",__func__);
183b06ebda0SMatthew Dillon mtx_destroy(&priv->ngd_mtx);
184b06ebda0SMatthew Dillon mtx_destroy(&priv->readq.ifq_mtx);
185b06ebda0SMatthew Dillon free_unr(ngd_unit, priv->unit);
186fc025606SSascha Wildner kfree(priv, M_NETGRAPH);
187b06ebda0SMatthew Dillon return(EINVAL);
188b06ebda0SMatthew Dillon }
189b06ebda0SMatthew Dillon /* XXX: race here? */
190b06ebda0SMatthew Dillon priv->ngddev->si_drv1 = priv;
191b06ebda0SMatthew Dillon
192b06ebda0SMatthew Dillon return(0);
193b06ebda0SMatthew Dillon }
194b06ebda0SMatthew Dillon
195b06ebda0SMatthew Dillon /*
196b06ebda0SMatthew Dillon * Process control message.
197b06ebda0SMatthew Dillon */
198b06ebda0SMatthew Dillon
199b06ebda0SMatthew Dillon static int
ng_device_rcvmsg(node_p node,item_p item,hook_p lasthook)200b06ebda0SMatthew Dillon ng_device_rcvmsg(node_p node, item_p item, hook_p lasthook)
201b06ebda0SMatthew Dillon {
202b06ebda0SMatthew Dillon const priv_p priv = NG_NODE_PRIVATE(node);
203b06ebda0SMatthew Dillon struct ng_mesg *msg;
204b06ebda0SMatthew Dillon struct ng_mesg *resp = NULL;
205b06ebda0SMatthew Dillon int error = 0;
206b06ebda0SMatthew Dillon
207b06ebda0SMatthew Dillon NGI_GET_MSG(item, msg);
208b06ebda0SMatthew Dillon
209b06ebda0SMatthew Dillon if (msg->header.typecookie == NGM_DEVICE_COOKIE) {
210b06ebda0SMatthew Dillon switch (msg->header.cmd) {
211b06ebda0SMatthew Dillon case NGM_DEVICE_GET_DEVNAME:
212b06ebda0SMatthew Dillon /* XXX: Fix when MAX_NGD us bigger */
213b06ebda0SMatthew Dillon NG_MKRESPONSE(resp, msg,
2145a975a3dSMatthew Dillon strlen(NG_DEVICE_DEVNAME) + 4, M_WAITOK);
215b06ebda0SMatthew Dillon
216b06ebda0SMatthew Dillon if (resp == NULL)
217b06ebda0SMatthew Dillon ERROUT(ENOMEM);
218b06ebda0SMatthew Dillon
219b06ebda0SMatthew Dillon strlcpy((char *)resp->data, priv->ngddev->si_name,
220b06ebda0SMatthew Dillon strlen(priv->ngddev->si_name) + 1);
221b06ebda0SMatthew Dillon break;
222b06ebda0SMatthew Dillon
223b06ebda0SMatthew Dillon default:
224b06ebda0SMatthew Dillon error = EINVAL;
225b06ebda0SMatthew Dillon break;
226b06ebda0SMatthew Dillon }
227b06ebda0SMatthew Dillon } else
228b06ebda0SMatthew Dillon error = EINVAL;
229b06ebda0SMatthew Dillon
230b06ebda0SMatthew Dillon done:
231b06ebda0SMatthew Dillon NG_RESPOND_MSG(error, node, item, resp);
232b06ebda0SMatthew Dillon NG_FREE_MSG(msg);
233b06ebda0SMatthew Dillon return (error);
234b06ebda0SMatthew Dillon }
235b06ebda0SMatthew Dillon
236b06ebda0SMatthew Dillon /*
237b06ebda0SMatthew Dillon * Accept incoming hook. We support only one hook per node.
238b06ebda0SMatthew Dillon */
239b06ebda0SMatthew Dillon static int
ng_device_newhook(node_p node,hook_p hook,const char * name)240b06ebda0SMatthew Dillon ng_device_newhook(node_p node, hook_p hook, const char *name)
241b06ebda0SMatthew Dillon {
242b06ebda0SMatthew Dillon priv_p priv = NG_NODE_PRIVATE(node);
243b06ebda0SMatthew Dillon
244b06ebda0SMatthew Dillon DBG;
245b06ebda0SMatthew Dillon
246b06ebda0SMatthew Dillon /* We have only one hook per node */
247b06ebda0SMatthew Dillon if (priv->hook != NULL)
248b06ebda0SMatthew Dillon return (EISCONN);
249b06ebda0SMatthew Dillon
250b06ebda0SMatthew Dillon priv->hook = hook;
251b06ebda0SMatthew Dillon
252b06ebda0SMatthew Dillon return(0);
253b06ebda0SMatthew Dillon }
254b06ebda0SMatthew Dillon
255b06ebda0SMatthew Dillon /*
256b06ebda0SMatthew Dillon * Receive data from hook, write it to device.
257b06ebda0SMatthew Dillon */
258b06ebda0SMatthew Dillon static int
ng_device_rcvdata(hook_p hook,item_p item)259b06ebda0SMatthew Dillon ng_device_rcvdata(hook_p hook, item_p item)
260b06ebda0SMatthew Dillon {
261b06ebda0SMatthew Dillon priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
262b06ebda0SMatthew Dillon struct mbuf *m;
263b06ebda0SMatthew Dillon
264b06ebda0SMatthew Dillon DBG;
265b06ebda0SMatthew Dillon
266b06ebda0SMatthew Dillon NGI_GET_M(item, m);
267b06ebda0SMatthew Dillon NG_FREE_ITEM(item);
268b06ebda0SMatthew Dillon
269b06ebda0SMatthew Dillon IF_LOCK(&priv->readq);
270b06ebda0SMatthew Dillon if (_IF_QFULL(&priv->readq)) {
271b06ebda0SMatthew Dillon _IF_DROP(&priv->readq);
272b06ebda0SMatthew Dillon IF_UNLOCK(&priv->readq);
273b06ebda0SMatthew Dillon NG_FREE_M(m);
274b06ebda0SMatthew Dillon return (ENOBUFS);
275b06ebda0SMatthew Dillon }
276b06ebda0SMatthew Dillon
277b06ebda0SMatthew Dillon _IF_ENQUEUE(&priv->readq, m);
278b06ebda0SMatthew Dillon IF_UNLOCK(&priv->readq);
279b06ebda0SMatthew Dillon mtx_lock(&priv->ngd_mtx);
280b06ebda0SMatthew Dillon if (priv->flags & NGDF_RWAIT) {
281b06ebda0SMatthew Dillon priv->flags &= ~NGDF_RWAIT;
282b06ebda0SMatthew Dillon wakeup(priv);
283b06ebda0SMatthew Dillon }
284b06ebda0SMatthew Dillon mtx_unlock(&priv->ngd_mtx);
285b06ebda0SMatthew Dillon
286b06ebda0SMatthew Dillon return(0);
287b06ebda0SMatthew Dillon }
288b06ebda0SMatthew Dillon
289b06ebda0SMatthew Dillon /*
290b06ebda0SMatthew Dillon * Removal of the hook destroys the node.
291b06ebda0SMatthew Dillon */
292b06ebda0SMatthew Dillon static int
ng_device_disconnect(hook_p hook)293b06ebda0SMatthew Dillon ng_device_disconnect(hook_p hook)
294b06ebda0SMatthew Dillon {
295b06ebda0SMatthew Dillon priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
296b06ebda0SMatthew Dillon
297b06ebda0SMatthew Dillon DBG;
298b06ebda0SMatthew Dillon
299b06ebda0SMatthew Dillon destroy_dev(priv->ngddev);
300b06ebda0SMatthew Dillon mtx_destroy(&priv->ngd_mtx);
301b06ebda0SMatthew Dillon
302b06ebda0SMatthew Dillon IF_DRAIN(&priv->readq);
303b06ebda0SMatthew Dillon mtx_destroy(&(priv)->readq.ifq_mtx);
304b06ebda0SMatthew Dillon
305b06ebda0SMatthew Dillon free_unr(ngd_unit, priv->unit);
306b06ebda0SMatthew Dillon
307fc025606SSascha Wildner kfree(priv, M_NETGRAPH);
308b06ebda0SMatthew Dillon
309b06ebda0SMatthew Dillon ng_rmnode_self(NG_HOOK_NODE(hook));
310b06ebda0SMatthew Dillon
311b06ebda0SMatthew Dillon return(0);
312b06ebda0SMatthew Dillon }
313b06ebda0SMatthew Dillon
314b06ebda0SMatthew Dillon /*
315b06ebda0SMatthew Dillon * Node shutdown. Everything is already done in disconnect method.
316b06ebda0SMatthew Dillon */
317b06ebda0SMatthew Dillon static int
ng_device_shutdown(node_p node)318b06ebda0SMatthew Dillon ng_device_shutdown(node_p node)
319b06ebda0SMatthew Dillon {
320b06ebda0SMatthew Dillon NG_NODE_UNREF(node);
321b06ebda0SMatthew Dillon return (0);
322b06ebda0SMatthew Dillon }
323b06ebda0SMatthew Dillon
324b06ebda0SMatthew Dillon /******************************************************************************
325b06ebda0SMatthew Dillon * Device methods
326b06ebda0SMatthew Dillon ******************************************************************************/
327b06ebda0SMatthew Dillon
328b06ebda0SMatthew Dillon /*
329b06ebda0SMatthew Dillon * the device is opened
330b06ebda0SMatthew Dillon */
331b06ebda0SMatthew Dillon static int
ngdopen(struct cdev * dev,int flag,int mode,struct thread * td)332b06ebda0SMatthew Dillon ngdopen(struct cdev *dev, int flag, int mode, struct thread *td)
333b06ebda0SMatthew Dillon {
334b06ebda0SMatthew Dillon priv_p priv = (priv_p )dev->si_drv1;
335b06ebda0SMatthew Dillon
336b06ebda0SMatthew Dillon DBG;
337b06ebda0SMatthew Dillon
338b06ebda0SMatthew Dillon mtx_lock(&priv->ngd_mtx);
339b06ebda0SMatthew Dillon priv->flags |= NGDF_OPEN;
340b06ebda0SMatthew Dillon mtx_unlock(&priv->ngd_mtx);
341b06ebda0SMatthew Dillon
342b06ebda0SMatthew Dillon return(0);
343b06ebda0SMatthew Dillon }
344b06ebda0SMatthew Dillon
345b06ebda0SMatthew Dillon /*
346b06ebda0SMatthew Dillon * the device is closed
347b06ebda0SMatthew Dillon */
348b06ebda0SMatthew Dillon static int
ngdclose(struct cdev * dev,int flag,int mode,struct thread * td)349b06ebda0SMatthew Dillon ngdclose(struct cdev *dev, int flag, int mode, struct thread *td)
350b06ebda0SMatthew Dillon {
351b06ebda0SMatthew Dillon priv_p priv = (priv_p )dev->si_drv1;
352b06ebda0SMatthew Dillon
353b06ebda0SMatthew Dillon DBG;
354b06ebda0SMatthew Dillon mtx_lock(&priv->ngd_mtx);
355b06ebda0SMatthew Dillon priv->flags &= ~NGDF_OPEN;
356b06ebda0SMatthew Dillon mtx_unlock(&priv->ngd_mtx);
357b06ebda0SMatthew Dillon
358b06ebda0SMatthew Dillon return(0);
359b06ebda0SMatthew Dillon }
360b06ebda0SMatthew Dillon
361b06ebda0SMatthew Dillon #if 0 /*
362b06ebda0SMatthew Dillon * The ioctl is transformed into netgraph control message.
363b06ebda0SMatthew Dillon * We do not process them, yet.
364b06ebda0SMatthew Dillon */
365b06ebda0SMatthew Dillon /*
366b06ebda0SMatthew Dillon * process ioctl
367b06ebda0SMatthew Dillon *
368b06ebda0SMatthew Dillon * they are translated into netgraph messages and passed on
369b06ebda0SMatthew Dillon *
370b06ebda0SMatthew Dillon */
371b06ebda0SMatthew Dillon static int
372b06ebda0SMatthew Dillon ngdioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td)
373b06ebda0SMatthew Dillon {
374b06ebda0SMatthew Dillon struct ngd_softc *sc = &ngd_softc;
375b06ebda0SMatthew Dillon struct ngd_connection * connection = NULL;
376b06ebda0SMatthew Dillon struct ngd_connection * tmp;
377b06ebda0SMatthew Dillon int error = 0;
378b06ebda0SMatthew Dillon struct ng_mesg *msg;
379b06ebda0SMatthew Dillon struct ngd_param_s * datap;
380b06ebda0SMatthew Dillon
381b06ebda0SMatthew Dillon DBG;
382b06ebda0SMatthew Dillon
383b06ebda0SMatthew Dillon NG_MKMESSAGE(msg, NGM_DEVICE_COOKIE, cmd, sizeof(struct ngd_param_s),
3845a975a3dSMatthew Dillon M_WAITOK);
385b06ebda0SMatthew Dillon if (msg == NULL) {
386a62226e4SSascha Wildner kprintf("%s(): msg == NULL\n",__func__);
387b06ebda0SMatthew Dillon goto nomsg;
388b06ebda0SMatthew Dillon }
389b06ebda0SMatthew Dillon
390b06ebda0SMatthew Dillon /* pass the ioctl data into the ->data area */
391b06ebda0SMatthew Dillon datap = (struct ngd_param_s *)msg->data;
392b06ebda0SMatthew Dillon datap->p = addr;
393b06ebda0SMatthew Dillon
394b06ebda0SMatthew Dillon NG_SEND_MSG_HOOK(error, sc->node, msg, connection->active_hook, 0);
395b06ebda0SMatthew Dillon if(error)
396a62226e4SSascha Wildner kprintf("%s(): NG_SEND_MSG_HOOK error: %d\n",__func__,error);
397b06ebda0SMatthew Dillon
398b06ebda0SMatthew Dillon nomsg:
399b06ebda0SMatthew Dillon
400b06ebda0SMatthew Dillon return(0);
401b06ebda0SMatthew Dillon }
402b06ebda0SMatthew Dillon #endif /* if 0 */
403b06ebda0SMatthew Dillon
404b06ebda0SMatthew Dillon /*
405b06ebda0SMatthew Dillon * This function is called when a read(2) is done to our device.
406b06ebda0SMatthew Dillon * We process one mbuf from queue.
407b06ebda0SMatthew Dillon */
408b06ebda0SMatthew Dillon static int
ngdread(struct cdev * dev,struct uio * uio,int flag)409b06ebda0SMatthew Dillon ngdread(struct cdev *dev, struct uio *uio, int flag)
410b06ebda0SMatthew Dillon {
411b06ebda0SMatthew Dillon priv_p priv = (priv_p )dev->si_drv1;
412b06ebda0SMatthew Dillon struct mbuf *m;
413b06ebda0SMatthew Dillon int len, error = 0;
414b06ebda0SMatthew Dillon
415b06ebda0SMatthew Dillon DBG;
416b06ebda0SMatthew Dillon
417b06ebda0SMatthew Dillon /* get an mbuf */
418b06ebda0SMatthew Dillon do {
419b06ebda0SMatthew Dillon IF_DEQUEUE(&priv->readq, m);
420b06ebda0SMatthew Dillon if (m == NULL) {
421b06ebda0SMatthew Dillon if (flag & IO_NDELAY)
422b06ebda0SMatthew Dillon return (EWOULDBLOCK);
423b06ebda0SMatthew Dillon mtx_lock(&priv->ngd_mtx);
424b06ebda0SMatthew Dillon priv->flags |= NGDF_RWAIT;
425b06ebda0SMatthew Dillon if ((error = msleep(priv, &priv->ngd_mtx,
426b06ebda0SMatthew Dillon PDROP | PCATCH | (PZERO + 1),
427b06ebda0SMatthew Dillon "ngdread", 0)) != 0)
428b06ebda0SMatthew Dillon return (error);
429b06ebda0SMatthew Dillon }
430b06ebda0SMatthew Dillon } while (m == NULL);
431b06ebda0SMatthew Dillon
432b06ebda0SMatthew Dillon while (m && uio->uio_resid > 0 && error == 0) {
433b06ebda0SMatthew Dillon len = MIN(uio->uio_resid, m->m_len);
434b06ebda0SMatthew Dillon if (len != 0)
435b06ebda0SMatthew Dillon error = uiomove(mtod(m, void *), len, uio);
436b06ebda0SMatthew Dillon m = m_free(m);
437b06ebda0SMatthew Dillon }
438b06ebda0SMatthew Dillon
439b06ebda0SMatthew Dillon if (m)
440b06ebda0SMatthew Dillon m_freem(m);
441b06ebda0SMatthew Dillon
442b06ebda0SMatthew Dillon return (error);
443b06ebda0SMatthew Dillon }
444b06ebda0SMatthew Dillon
445b06ebda0SMatthew Dillon
446b06ebda0SMatthew Dillon /*
447b06ebda0SMatthew Dillon * This function is called when our device is written to.
448b06ebda0SMatthew Dillon * We read the data from userland into mbuf chain and pass it to the remote hook.
449b06ebda0SMatthew Dillon *
450b06ebda0SMatthew Dillon */
451b06ebda0SMatthew Dillon static int
ngdwrite(struct cdev * dev,struct uio * uio,int flag)452b06ebda0SMatthew Dillon ngdwrite(struct cdev *dev, struct uio *uio, int flag)
453b06ebda0SMatthew Dillon {
454b06ebda0SMatthew Dillon priv_p priv = (priv_p )dev->si_drv1;
455b06ebda0SMatthew Dillon struct mbuf *m;
456b06ebda0SMatthew Dillon int error = 0;
457b06ebda0SMatthew Dillon
458b06ebda0SMatthew Dillon DBG;
459b06ebda0SMatthew Dillon
460b06ebda0SMatthew Dillon if (uio->uio_resid == 0)
461b06ebda0SMatthew Dillon return (0);
462b06ebda0SMatthew Dillon
463e54488bbSMatthew Dillon if (uio->uio_resid > IP_MAXPACKET)
464b06ebda0SMatthew Dillon return (EIO);
465b06ebda0SMatthew Dillon
466*b5523eacSSascha Wildner if ((m = m_uiotombuf(uio, M_NOWAIT, 0, 0, M_PKTHDR)) == NULL)
467b06ebda0SMatthew Dillon return (ENOBUFS);
468b06ebda0SMatthew Dillon
469b06ebda0SMatthew Dillon NG_SEND_DATA_ONLY(error, priv->hook, m);
470b06ebda0SMatthew Dillon
471b06ebda0SMatthew Dillon return (error);
472b06ebda0SMatthew Dillon }
473b06ebda0SMatthew Dillon
474b06ebda0SMatthew Dillon /*
475b06ebda0SMatthew Dillon * we are being polled/selected
476b06ebda0SMatthew Dillon * check if there is data available for read
477b06ebda0SMatthew Dillon */
478b06ebda0SMatthew Dillon static int
ngdpoll(struct cdev * dev,int events,struct thread * td)479b06ebda0SMatthew Dillon ngdpoll(struct cdev *dev, int events, struct thread *td)
480b06ebda0SMatthew Dillon {
481b06ebda0SMatthew Dillon priv_p priv = (priv_p )dev->si_drv1;
482b06ebda0SMatthew Dillon int revents = 0;
483b06ebda0SMatthew Dillon
484b06ebda0SMatthew Dillon if (events & (POLLIN | POLLRDNORM) &&
485b06ebda0SMatthew Dillon !IFQ_IS_EMPTY(&priv->readq))
486b06ebda0SMatthew Dillon revents |= events & (POLLIN | POLLRDNORM);
487b06ebda0SMatthew Dillon
488b06ebda0SMatthew Dillon return (revents);
489b06ebda0SMatthew Dillon }
490