summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorglebius <glebius@FreeBSD.org>2004-10-18 20:13:57 +0000
committerglebius <glebius@FreeBSD.org>2004-10-18 20:13:57 +0000
commit3c69856ec59055937844e49a3b20699d15b2bdfc (patch)
tree8c0ce186ab50c929b13a350edcdc8adfa4becefd /sys
parent7b853afb002723c73c5121562d0e6da52a480cc5 (diff)
downloadFreeBSD-src-3c69856ec59055937844e49a3b20699d15b2bdfc.zip
FreeBSD-src-3c69856ec59055937844e49a3b20699d15b2bdfc.tar.gz
Major overhaul.
List of functional changes: - Make a single device per single node with a single hook. This gives us parrallelizm, which can't be achieved on a single node with many devices/hooks. This also gives us flexibility - we can play with a particular device node, not affecting others. - Remove read queue as it is. Use struct ifqueue instead. This change removes a lot of extra memcpy()ing, m_devget()ting and m_copymem()ming. In ng_device_receivedata() we enqueue an mbuf and wake readers. In ngdread() we take one mbuf from qeueue and uiomove() it to userspace. If no mbuf is present we optionally block. [1] - In ngdwrite() we create an mbuf from uio using m_uiotombuf(). This is faster then uiomove() into buffer, and then m_copydata(), and this is much better than huge m_pullup(). - Perform locking of device - Perform locking of connection list. - Clear out _rcvmsg method, since it does nothing good yet. - Implement NGM_DEVICE_GET_DEVNAME message. - #if 0 ioctl method, while nothing is done here yet. - Return immediately from ngdwrite() if uio_resid == 0. List of tidyness changes: - Introduce device2priv(), to remove cut'n'paste. - Use MALLOC/FREE, instead of malloc/free. - Use unit2minor(). - Use UID_ROOT/GID_WHEEL instead of 0/0. - Define NGD_DEVICE_DEVNAME, use it. - Use more nice macros for debugging. [2] - Return Exxx, not -1. style(9) changes: - No "#endif" after short block. - Break long lines. - Remove extra spaces, add needed spaces. [1] Obtained from: if_tun.c [2] Obtained from: ng_pppoe.c Reviewed by: marks Approved by: julian (mentor) MFC after: 1 month
Diffstat (limited to 'sys')
-rw-r--r--sys/modules/netgraph/device/Makefile2
-rw-r--r--sys/netgraph/ng_device.c629
-rw-r--r--sys/netgraph/ng_device.h11
3 files changed, 281 insertions, 361 deletions
diff --git a/sys/modules/netgraph/device/Makefile b/sys/modules/netgraph/device/Makefile
index 9f85151..92eaa98 100644
--- a/sys/modules/netgraph/device/Makefile
+++ b/sys/modules/netgraph/device/Makefile
@@ -2,6 +2,6 @@
KMOD= ng_device
SRCS= ng_device.c
-SRCS+= device_if.h
+SRCS+= device_if.h vnode_if.h
.include <bsd.kmod.mk>
diff --git a/sys/netgraph/ng_device.c b/sys/netgraph/ng_device.c
index 7dcaea3..c209fd1 100644
--- a/sys/netgraph/ng_device.c
+++ b/sys/netgraph/ng_device.c
@@ -23,13 +23,19 @@
*
* Netgraph "device" node
*
- * This node presents a /dev/ngd%d device that interfaces to an other
+ * This node presents a /dev/ngd%d device that interfaces to an other
* netgraph node.
*
* $FreeBSD$
*
*/
+#if 0
+#define AAA printf("ng_device: %s\n", __func__ );
+#else
+#define AAA
+#endif
+
#include <sys/param.h>
#include <sys/conf.h>
#include <sys/ioccom.h>
@@ -38,407 +44,328 @@
#include <sys/mbuf.h>
#include <sys/poll.h>
#include <sys/queue.h>
+#include <sys/socket.h>
#include <sys/systm.h>
#include <sys/uio.h>
+#include <sys/vnode.h>
+
+#include <net/if.h>
+#include <net/if_var.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
#include <netgraph/ng_message.h>
#include <netgraph/netgraph.h>
#include <netgraph/ng_device.h>
-/* turn this on for verbose messages */
-#define NGD_DEBUG
-
#define ERROUT(x) do { error = (x); goto done; } while (0)
/* Netgraph methods */
-static ng_constructor_t ng_device_cons;
+static ng_constructor_t ng_device_constructor;
static ng_rcvmsg_t ng_device_rcvmsg;
+static ng_shutdown_t ng_device_shutdown;
static ng_newhook_t ng_device_newhook;
-static ng_connect_t ng_device_connect;
static ng_rcvdata_t ng_device_rcvdata;
static ng_disconnect_t ng_device_disconnect;
-static int ng_device_mod_event(module_t mod, int event, void *data);
-
-static int ng_device_init(void);
-static int get_free_unit(void);
/* Netgraph type */
-static struct ng_type typestruct = {
+static struct ng_type ngd_typestruct = {
.version = NG_ABI_VERSION,
.name = NG_DEVICE_NODE_TYPE,
- .mod_event = ng_device_mod_event,
- .constructor = ng_device_cons,
- .rcvmsg = ng_device_rcvmsg,
+ .constructor = ng_device_constructor,
+ .rcvmsg = ng_device_rcvmsg,
+ .shutdown = ng_device_shutdown,
.newhook = ng_device_newhook,
- .connect = ng_device_connect,
.rcvdata = ng_device_rcvdata,
.disconnect = ng_device_disconnect,
};
-NETGRAPH_INIT(device, &typestruct);
-
-/* per hook data */
-struct ngd_connection {
- SLIST_ENTRY(ngd_connection) links;
-
- struct cdev *ngddev;
- struct ng_hook *active_hook;
- char *readq;
- int loc;
- int unit;
+NETGRAPH_INIT(device, &ngd_typestruct);
+
+/* per node data */
+struct ngd_private {
+ struct ifqueue readq;
+ SLIST_ENTRY(ngd_private) links;
+ struct ng_node *node;
+ struct ng_hook *hook;
+ struct cdev *ngddev;
+ struct mtx ngd_mtx;
+ int unit;
+ uint16_t flags;
+#define NGDF_OPEN 0x0001
+#define NGDF_RWAIT 0x0002
};
+typedef struct ngd_private *priv_p;
-/* global data */
-struct ngd_softc {
- SLIST_HEAD(, ngd_connection) head;
-
- node_p node;
- char nodename[NG_NODESIZ];
-} ngd_softc;
-
-/* the per connection receiving queue maximum */
-#define NGD_QUEUE_SIZE (1024*10)
+/* List of all active nodes and mutex to protect it */
+static SLIST_HEAD(, ngd_private) ngd_nodes = SLIST_HEAD_INITIALIZER(ngd_nodes);
+static struct mtx ng_device_mtx;
+MTX_SYSINIT(ng_device, &ng_device_mtx, "ng_device", MTX_DEF);
/* Maximum number of NGD devices */
-#define MAX_NGD 25 /* should be more than enough for now */
+#define MAX_NGD 25 /* should be more than enough for now */
static d_close_t ngdclose;
static d_open_t ngdopen;
static d_read_t ngdread;
static d_write_t ngdwrite;
+#if 0
static d_ioctl_t ngdioctl;
+#endif
static d_poll_t ngdpoll;
static struct cdevsw ngd_cdevsw = {
.d_version = D_VERSION,
- .d_flags = D_NEEDGIANT,
.d_open = ngdopen,
.d_close = ngdclose,
.d_read = ngdread,
.d_write = ngdwrite,
+#if 0
.d_ioctl = ngdioctl,
+#endif
.d_poll = ngdpoll,
- .d_name = "ngd",
+ .d_name = NG_DEVICE_DEVNAME,
};
-/*
- * this holds all the stuff that should be done at load time
+/* Helper functions */
+static int get_free_unit(void);
+
+/******************************************************************************
+ * Netgraph methods
+ ******************************************************************************/
+
+/*
+ * create new node
*/
static int
-ng_device_mod_event(module_t mod, int event, void *data)
+ng_device_constructor(node_p node)
{
- int error = 0;
+ priv_p priv;
-#ifdef NGD_DEBUG
- printf("%s()\n",__func__);
-#endif /* NGD_DEBUG */
+AAA
- switch (event) {
- case MOD_LOAD:
+ MALLOC(priv, priv_p, sizeof(*priv), M_NETGRAPH, M_NOWAIT | M_ZERO);
+ if (priv == NULL)
+ return (ENOMEM);
- ng_device_init();
- break;
+ mtx_init(&priv->ngd_mtx, "ng_device", NULL, MTX_DEF);
+ mtx_lock(&priv->ngd_mtx);
- case MOD_UNLOAD:
- /* XXX do we need to do something specific ? */
- /* ng_device_breakdown */
- break;
-
- default:
- error = EOPNOTSUPP;
- break;
- }
+ mtx_lock(&ng_device_mtx);
- return(error);
-}
+ priv->unit = get_free_unit();
+ if(priv->unit < 0) {
+ printf("%s: No free unit found by get_free_unit(), "
+ "increase MAX_NGD\n",__func__);
+ mtx_unlock(&ng_device_mtx);
+ mtx_destroy(&priv->ngd_mtx);
+ FREE(priv, M_NETGRAPH);
+ return(EINVAL);
+ }
+ priv->ngddev = make_dev(&ngd_cdevsw, unit2minor(priv->unit), UID_ROOT,
+ GID_WHEEL, 0600, NG_DEVICE_DEVNAME "%d", priv->unit);
+ if(priv->ngddev == NULL) {
+ printf("%s(): make_dev() failed\n",__func__);
+ mtx_unlock(&ng_device_mtx);
+ mtx_destroy(&priv->ngd_mtx);
+ FREE(priv, M_NETGRAPH);
+ return(EINVAL);
+ }
-static int
-ng_device_init()
-{
- struct ngd_softc *sc = &ngd_softc;
-
-#ifdef NGD_DEBUG
- printf("%s()\n",__func__);
-#endif /* NGD_DEBUG */
-
- SLIST_INIT(&sc->head);
-
- if (ng_make_node_common(&typestruct, &sc->node) != 0) {
- printf("%s(): ng_make_node_common failed\n",__func__);
- return(ENXIO);
- }
- sprintf(sc->nodename, "%s", NG_DEVICE_NODE_TYPE);
- if (ng_name_node(sc->node, sc->nodename)) {
- NG_NODE_UNREF(sc->node); /* make it go away again */
- printf("%s(): ng_name_node failed\n",__func__);
- return(ENXIO);
- }
- NG_NODE_SET_PRIVATE(sc->node, sc);
+ SLIST_INSERT_HEAD(&ngd_nodes, priv, links);
- return(0);
-}
+ mtx_unlock(&ng_device_mtx);
-/*
- * don't allow to be created, only the device can do that
- */
-static int
-ng_device_cons(node_p node)
-{
+ mtx_init(&priv->readq.ifq_mtx, "ng_device queue", NULL, MTX_DEF);
+ IFQ_SET_MAXLEN(&priv->readq, ifqmaxlen);
-#ifdef NGD_DEBUG
- printf("%s()\n",__func__);
-#endif /* NGD_DEBUG */
+ /* Link everything together */
+ NG_NODE_SET_PRIVATE(node, priv);
+ priv->node = node;
+ priv->ngddev->si_drv1 = priv;
- return(EINVAL);
+ mtx_unlock(&priv->ngd_mtx);
+
+ return(0);
}
/*
- * Receive control message. We just bounce it back as a reply.
+ * Process control message.
*/
+
static int
ng_device_rcvmsg(node_p node, item_p item, hook_p lasthook)
{
- struct ngd_softc *sc = &ngd_softc;
+ const priv_p priv = NG_NODE_PRIVATE(node);
struct ng_mesg *msg;
+ struct ng_mesg *resp = NULL;
int error = 0;
- struct ngd_connection * connection = NULL;
- struct ngd_connection *tmp = NULL;
-#ifdef NGD_DEBUG
- printf("%s()\n",__func__);
-#endif /* NGD_DEBUG */
+ NGI_GET_MSG(item, msg);
- NGI_GET_MSG(item, msg);
+ if (msg->header.typecookie == NGM_DEVICE_COOKIE) {
+ switch (msg->header.cmd) {
+ case NGM_DEVICE_GET_DEVNAME:
+ /* XXX: Fix when NGD_MAX us bigger */
+ NG_MKRESPONSE(resp, msg,
+ strlen(NG_DEVICE_DEVNAME) + 3, M_NOWAIT);
- SLIST_FOREACH(tmp,&sc->head,links) {
- if(tmp->active_hook == lasthook) {
- connection = tmp;
- }
- }
- if(connection == NULL) {
- printf("%s(): connection is still NULL, no hook found\n",__func__);
- return(-1);
- }
+ if (resp == NULL)
+ ERROUT(ENOMEM);
- return(error);
-}
-
-static int
-get_free_unit()
-{
- struct ngd_connection *tmp = NULL;
- struct ngd_softc *sc = &ngd_softc;
- int n = 0;
- int unit = -1;
-
-#ifdef NGD_DEBUG
- printf("%s()\n",__func__);
-#endif /* NGD_DEBUG */
-
- /* When there is no list yet, the first device unit is always 0. */
- if SLIST_EMPTY(&sc->head) {
- unit = 0;
- return(unit);
- }
-
- /* Just do a brute force loop to find the first free unit that is
- * smaller than MAX_NGD.
- * Set MAX_NGD to a large value, doesn't impact performance.
- */
- for(n = 0;n<MAX_NGD && unit == -1;n++) {
- SLIST_FOREACH(tmp,&sc->head,links) {
+ strlcpy((char *)resp->data, priv->ngddev->si_name,
+ strlen(priv->ngddev->si_name) + 1);
+ break;
- if(tmp->unit == n) {
- unit = -1;
- break;
- }
- unit = n;
+ default:
+ error = EINVAL;
+ break;
}
- }
+ } else
+ error = EINVAL;
- return(unit);
+done:
+ NG_RESPOND_MSG(error, node, item, resp);
+ NG_FREE_MSG(msg);
+ return (error);
}
/*
- * incoming hook
+ * Accept incoming hook. We support only one hook per node.
*/
static int
ng_device_newhook(node_p node, hook_p hook, const char *name)
{
- struct ngd_softc *sc = &ngd_softc;
- struct ngd_connection * new_connection = NULL;
-
-#ifdef NGD_DEBUG
- printf("%s()\n",__func__);
-#endif
-
- new_connection = malloc(sizeof(struct ngd_connection), M_DEVBUF, M_NOWAIT);
- if(new_connection == NULL) {
- printf("%s(): ERROR: new_connection == NULL\n",__func__);
- return(ENOMEM);
- }
-
- new_connection->unit = get_free_unit();
- if(new_connection->unit<0) {
- printf("%s: No free unit found by get_free_unit(), "
- "increase MAX_NGD\n",__func__);
- free(new_connection, M_DEVBUF);
- return(EINVAL);
- }
- new_connection->ngddev = make_dev(&ngd_cdevsw, new_connection->unit, 0, 0,0600,"ngd%d",new_connection->unit);
- if(new_connection->ngddev == NULL) {
- printf("%s(): make_dev failed\n",__func__);
- free(new_connection, M_DEVBUF);
- return(EINVAL);
- }
-
- new_connection->readq = malloc(sizeof(char)*NGD_QUEUE_SIZE, M_DEVBUF, M_NOWAIT | M_ZERO);
- if(new_connection->readq == NULL) {
- printf("%s(): readq malloc failed\n",__func__);
- free(new_connection, M_DEVBUF);
- return(ENOMEM);
- }
-
- /* point to begin of buffer */
- new_connection->loc = 0;
- new_connection->active_hook = hook;
-
- SLIST_INSERT_HEAD(&sc->head, new_connection, links);
+ priv_p priv = NG_NODE_PRIVATE(node);
- return(0);
-}
+AAA
-/*
- * we gave ok to a new hook
- * now connect
- */
-static int
-ng_device_connect(hook_p hook)
-{
+ /* We have only one hook per node */
+ if (priv->hook != NULL)
+ return (EISCONN);
-#ifdef NGD_DEBUG
- printf("%s()\n",__func__);
-#endif /* NGD_DEBUG */
+ priv->hook = hook;
return(0);
}
-
/*
- * Receive data from hook
+ * Receive data from hook, write it to device.
*/
static int
ng_device_rcvdata(hook_p hook, item_p item)
{
+ priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
struct mbuf *m;
- struct ngd_softc *sc = &ngd_softc;
- struct ngd_connection * connection = NULL;
- struct ngd_connection * tmp;
- char *buffer;
- int error = 0;
-#ifdef NGD_DEBUG
- printf("%s()\n",__func__);
-#endif
+AAA
NGI_GET_M(item, m);
NG_FREE_ITEM(item);
- SLIST_FOREACH(tmp,&sc->head,links)
- if(tmp->active_hook == hook)
- connection = tmp;
-
- if (connection == NULL) {
- printf("%s(): connection is still NULL, no hook found\n",__func__);
- ERROUT(ENOTCONN);
- }
-
- if ((m = m_pullup(m,m->m_len)) == NULL) {
- printf("%s(): ERROR: m_pullup failed\n",__func__);
- ERROUT(ENOMEM);
+ IF_LOCK(&priv->readq);
+ if (_IF_QFULL(&priv->readq)) {
+ _IF_DROP(&priv->readq);
+ IF_UNLOCK(&priv->readq);
+ NG_FREE_M(m);
+ return (ENOBUFS);
}
- buffer = mtod(m,char *);
-
- if ((connection->loc + m->m_len) < NGD_QUEUE_SIZE) {
- memcpy(connection->readq + connection->loc, buffer, m->m_len);
- connection->loc += m->m_len;
- } else {
- printf("%s(): queue full, first read out a bit\n",__func__);
- ERROUT(ENOSPC);
+ _IF_ENQUEUE(&priv->readq, m);
+ IF_UNLOCK(&priv->readq);
+ mtx_lock(&priv->ngd_mtx);
+ if (priv->flags & NGDF_RWAIT) {
+ priv->flags &= ~NGDF_RWAIT;
+ wakeup(priv);
}
+ mtx_unlock(&priv->ngd_mtx);
-done:
- NG_FREE_M(m);
- return(error);
+ return(0);
}
/*
- * Removal of the last link destroys the node
+ * Removal of the hook destroys the node.
*/
static int
ng_device_disconnect(hook_p hook)
{
- struct ngd_softc *sc = &ngd_softc;
- struct ngd_connection * connection = NULL;
- struct ngd_connection * tmp;
+ priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
-#ifdef NGD_DEBUG
- printf("%s()\n",__func__);
-#endif
+AAA
- SLIST_FOREACH(tmp,&sc->head,links)
- if(tmp->active_hook == hook)
- connection = tmp;
+ destroy_dev(priv->ngddev);
+ mtx_destroy(&priv->ngd_mtx);
- if(connection == NULL) {
- printf("%s(): connection is still NULL, no hook found\n",__func__);
- return(ENOTCONN);
- }
+ mtx_lock(&ng_device_mtx);
+ SLIST_REMOVE(&ngd_nodes, priv, ngd_private, links);
+ mtx_unlock(&ng_device_mtx);
- free(connection->readq, M_DEVBUF);
+ IF_DRAIN(&priv->readq);
+ mtx_destroy(&(priv)->readq.ifq_mtx);
- destroy_dev(connection->ngddev);
+ FREE(priv, M_NETGRAPH);
- SLIST_REMOVE(&sc->head,connection,ngd_connection,links);
- free(connection, M_DEVBUF);
+ ng_rmnode_self(NG_HOOK_NODE(hook));
return(0);
}
+
/*
- * the device is opened
+ * Node shutdown. Everything is already done in disconnect method.
+ */
+static int
+ng_device_shutdown(node_p node)
+{
+ NG_NODE_UNREF(node);
+ return (0);
+}
+
+/******************************************************************************
+ * Device methods
+ ******************************************************************************/
+
+/*
+ * the device is opened
*/
static int
ngdopen(struct cdev *dev, int flag, int mode, struct thread *td)
{
+ priv_p priv = (priv_p )dev->si_drv1;
-#ifdef NGD_DEBUG
- printf("%s()\n",__func__);
-#endif /* NGD_DEBUG */
+AAA
+ mtx_lock(&priv->ngd_mtx);
+ priv->flags |= NGDF_OPEN;
+ mtx_unlock(&priv->ngd_mtx);
return(0);
}
/*
- * the device is closed
+ * the device is closed
*/
static int
ngdclose(struct cdev *dev, int flag, int mode, struct thread *td)
{
+ priv_p priv = (priv_p )dev->si_drv1;
-#ifdef NGD_DEBUG
- printf("%s()\n",__func__);
-#endif
+AAA
+ mtx_lock(&priv->ngd_mtx);
+ priv->flags &= ~NGDF_OPEN;
+ mtx_unlock(&priv->ngd_mtx);
return(0);
}
-
+#if 0 /*
+ * The ioctl is transformed into netgraph control message.
+ * We do not process them, yet.
+ */
/*
* process ioctl
*
* they are translated into netgraph messages and passed on
- *
+ *
*/
static int
ngdioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td)
@@ -448,11 +375,9 @@ ngdioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td
struct ngd_connection * tmp;
int error = 0;
struct ng_mesg *msg;
- struct ngd_param_s * datap;
+ struct ngd_param_s * datap;
-#ifdef NGD_DEBUG
- printf("%s()\n",__func__);
-#endif /* NGD_DEBUG */
+AAA
SLIST_FOREACH(tmp,&sc->head,links) {
if(tmp->ngddev == dev) {
@@ -464,8 +389,7 @@ ngdioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td
return(-1);
}
- /* NG_MKMESSAGE(msg, cookie, cmdid, len, how) */
- NG_MKMESSAGE(msg, NGM_DEVICE_COOKIE, cmd, sizeof(struct ngd_param_s),
+ NG_MKMESSAGE(msg, NGM_DEVICE_COOKIE, cmd, sizeof(struct ngd_param_s),
M_NOWAIT);
if (msg == NULL) {
printf("%s(): msg == NULL\n",__func__);
@@ -474,7 +398,7 @@ ngdioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td
/* pass the ioctl data into the ->data area */
datap = (struct ngd_param_s *)msg->data;
- datap->p = addr;
+ datap->p = addr;
NG_SEND_MSG_HOOK(error, sc->node, msg, connection->active_hook, 0);
if(error)
@@ -484,108 +408,76 @@ nomsg:
return(0);
}
-
+#endif /* if 0 */
/*
* This function is called when a read(2) is done to our device.
- * We pass the data available in kernelspace on into userland using
- * uiomove.
+ * We process one mbuf from queue.
*/
static int
ngdread(struct cdev *dev, struct uio *uio, int flag)
{
- int ret = 0, amnt;
- char buffer[uio->uio_resid+1];
- struct ngd_softc *sc = &ngd_softc;
- struct ngd_connection * connection = NULL;
- struct ngd_connection * tmp;
-
-#ifdef NGD_DEBUG
- printf("%s()\n",__func__);
-#endif /* NGD_DEBUG */
-
- SLIST_FOREACH(tmp,&sc->head,links) {
- if(tmp->ngddev == dev) {
- connection = tmp;
+ priv_p priv = (priv_p )dev->si_drv1;
+ struct mbuf *m;
+ int len, error = 0;
+
+AAA
+
+ /* get an mbuf */
+ do {
+ IF_DEQUEUE(&priv->readq, m);
+ if (m == NULL) {
+ if (flag & IO_NDELAY)
+ return (EWOULDBLOCK);
+ mtx_lock(&priv->ngd_mtx);
+ priv->flags |= NGDF_RWAIT;
+ mtx_unlock(&priv->ngd_mtx);
+ if ((error = tsleep(priv, PCATCH | (PZERO + 1),
+ "ngdread", 0)) != 0)
+ return (error);
}
- }
- if(connection == NULL) {
- printf("%s(): connection is still NULL, no dev found\n",__func__);
- return(-1);
- }
-
- while ( ( uio->uio_resid > 0 ) && ( connection->loc > 0 ) ) {
- amnt = MIN(uio->uio_resid,connection->loc);
-
- memcpy(buffer,connection->readq, amnt);
- memcpy(connection->readq, connection->readq+amnt,
- connection->loc-amnt);
- connection->loc -= amnt;
-
- ret = uiomove((caddr_t)buffer, amnt, uio);
- if(ret != 0)
- goto error;
+ } while (m == NULL);
+ while (m && uio->uio_resid > 0 && error == 0) {
+ len = MIN(uio->uio_resid, m->m_len);
+ if (len != 0)
+ error = uiomove(mtod(m, void *), len, uio);
+ m = m_free(m);
}
- return(0);
-error:
- printf("%s(): uiomove returns error %d\n",__func__,ret);
- /* do error cleanup here */
- return(ret);
+ if (m)
+ m_freem(m);
+
+ return (error);
}
-/*
+/*
* This function is called when our device is written to.
- * We read the data from userland into our local buffer and pass it on
- * into the remote hook.
+ * We read the data from userland into mbuf chain and pass it to the remote hook.
*
*/
static int
ngdwrite(struct cdev *dev, struct uio *uio, int flag)
{
- int ret;
- int error = 0;
+ priv_p priv = (priv_p )dev->si_drv1;
struct mbuf *m;
- char buffer[uio->uio_resid];
- int len = uio->uio_resid;
- struct ngd_softc *sc =& ngd_softc;
- struct ngd_connection * connection = NULL;
- struct ngd_connection * tmp;
-
-#ifdef NGD_DEBUG
- printf("%s()\n",__func__);
-#endif /* NGD_DEBUG */
-
- SLIST_FOREACH(tmp,&sc->head,links) {
- if(tmp->ngddev == dev) {
- connection = tmp;
- }
- }
-
- if(connection == NULL) {
- printf("%s(): connection is still NULL, no dev found\n",__func__);
- return(-1);
- }
+ int error = 0;
- if (len > 0) {
- if ((ret = uiomove((caddr_t)buffer, len, uio)) != 0)
- goto error;
- } else
- printf("%s(): len <= 0 : is this supposed to happen?!\n",__func__);
+AAA
- m = m_devget(buffer,len,0,NULL,NULL);
+ if (uio->uio_resid == 0)
+ return (0);
- NG_SEND_DATA_ONLY(error,connection->active_hook,m);
+ if (uio->uio_resid < 0 || uio->uio_resid > IP_MAXPACKET)
+ return (EIO);
- return(0);
+ if ((m = m_uiotombuf(uio, M_DONTWAIT, 0)) == NULL)
+ return (ENOBUFS);
-error:
- /* do error cleanup here */
- printf("%s(): uiomove returned err: %d\n",__func__,ret);
+ NG_SEND_DATA_ONLY(error, priv->hook, m);
- return(ret);
+ return (error);
}
/*
@@ -595,28 +487,49 @@ error:
static int
ngdpoll(struct cdev *dev, int events, struct thread *td)
{
+ priv_p priv = (priv_p )dev->si_drv1;
int revents = 0;
- struct ngd_softc *sc = &ngd_softc;
- struct ngd_connection * connection = NULL;
- struct ngd_connection * tmp;
+ if (events & (POLLIN | POLLRDNORM) &&
+ !IFQ_IS_EMPTY(&priv->readq))
+ revents |= events & (POLLIN | POLLRDNORM);
+
+ return (revents);
+}
+
+/******************************************************************************
+ * Helper subroutines
+ ******************************************************************************/
+
+static int
+get_free_unit()
+{
+ struct ngd_private *priv = NULL;
+ int n = 0;
+ int unit = -1;
+
+AAA
+
+ mtx_assert(&ng_device_mtx, MA_OWNED);
- if (events & (POLLIN | POLLRDNORM)) {
- /* get the connection we have to know the loc from */
- SLIST_FOREACH(tmp,&sc->head,links) {
- if(tmp->ngddev == dev) {
- connection = tmp;
+ /* When there is no list yet, the first device unit is always 0. */
+ if SLIST_EMPTY(&ngd_nodes)
+ return(0);
+
+ /* Just do a brute force loop to find the first free unit that is
+ * smaller than MAX_NGD.
+ * Set MAX_NGD to a large value, doesn't impact performance.
+ */
+ for(n = 0; n<MAX_NGD && unit == -1; n++) {
+ SLIST_FOREACH(priv, &ngd_nodes, links) {
+
+ if(priv->unit == n) {
+ unit = -1;
+ break;
}
+ unit = n;
}
- if(connection == NULL) {
- printf("%s(): ERROR: connection is still NULL,"
- "no dev found\n",__func__);
- return(-1);
- }
-
- if (connection->loc > 0)
- revents |= events & (POLLIN | POLLRDNORM);
}
- return(revents);
+ return (unit);
}
diff --git a/sys/netgraph/ng_device.h b/sys/netgraph/ng_device.h
index 5596134..9f33369 100644
--- a/sys/netgraph/ng_device.h
+++ b/sys/netgraph/ng_device.h
@@ -31,12 +31,19 @@
/* Node type name and magic cookie */
#define NG_DEVICE_NODE_TYPE "device"
-#define NGM_DEVICE_COOKIE 1009920473
+#define NGM_DEVICE_COOKIE 1091129178
+#define NG_DEVICE_DEVNAME "ngd"
+/* Netgraph control messages */
+enum {
+ NGM_DEVICE_GET_DEVNAME,
+};
+
+#if 0
/* passing ioctl params */
struct ngd_param_s {
void * p;
};
-
+#endif
#endif /* _NETGRAPH_NG_DEVICE_H_ */
OpenPOWER on IntegriCloud