freebsd-ports/misc/dahdi-kmod/files/patch-dahdi-iface
Max Khon a48ecfeaa4 - Fix wcte12xp unloading (implement flush_workqueue)
- Fix nethdlc -> bchan/dchan reconfiguration (unlock chan mtx
before destroying iface)
- Bump PORTREVISION
2012-05-30 08:40:11 +00:00

939 lines
27 KiB
Text

Index: freebsd/include/dahdi/kernel.h
===================================================================
--- freebsd/include/dahdi/kernel.h (revision 10321)
+++ freebsd/include/dahdi/kernel.h (working copy)
@@ -468,6 +468,7 @@
struct cdev *dev; /*!< Device structure */
struct cdev *file; /*!< File structure */
int file_flags;
+ struct dahdi_iface *iface;
#else
struct file *file; /*!< File structure */
#endif
@@ -1361,4 +1362,8 @@
void dahdi_poll_wait(struct file *file, struct pollinfo *sel, struct poll_table_struct *wait_table);
+int dahdi_net_chan_init(struct dahdi_chan *chan, int numbufs);
+void dahdi_net_chan_destroy(struct dahdi_chan *chan);
+void dahdi_net_chan_xmit(struct dahdi_chan *chan);
+
#endif /* _DAHDI_KERNEL_H */
Index: freebsd/freebsd/dahdi/ng_dahdi_iface.c
===================================================================
--- freebsd/freebsd/dahdi/ng_dahdi_iface.c (revision 0)
+++ freebsd/freebsd/dahdi/ng_dahdi_iface.c (revision 10329)
@@ -0,0 +1,605 @@
+/*-
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Max Khon.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+#include <sys/types.h>
+#include <sys/mbuf.h>
+#include <sys/linker.h>
+#include <sys/syscallsubr.h>
+#include <sys/taskqueue.h>
+
+#include <netgraph/ng_message.h>
+#include <netgraph/netgraph.h>
+
+#include <netinet/in.h>
+#include <netgraph/ng_cisco.h>
+#include <netgraph/ng_iface.h>
+
+#include <dahdi/kernel.h>
+
+#include "ng_dahdi_iface.h"
+
+#define module_printk(level, fmt, args...) printk(level "%s: " fmt, THIS_MODULE->name, ## args)
+
+#if __FreeBSD_version < 800000
+struct ng_node *ng_name2noderef(struct ng_node *node, const char *name);
+#endif
+
+#define DAHDI_IFACE_HOOK_UPPER "upper"
+
+static ng_rcvmsg_t ng_dahdi_iface_rcvmsg;
+static ng_shutdown_t ng_dahdi_iface_shutdown;
+static ng_newhook_t ng_dahdi_iface_newhook;
+static ng_disconnect_t ng_dahdi_iface_disconnect;
+static ng_rcvdata_t ng_dahdi_iface_rcvdata;
+
+static struct ng_type ng_dahdi_iface_typestruct = {
+ .version = NG_ABI_VERSION,
+ .name = "ng_dahdi_iface",
+ .rcvmsg = ng_dahdi_iface_rcvmsg,
+ .shutdown = ng_dahdi_iface_shutdown,
+ .newhook = ng_dahdi_iface_newhook,
+ .rcvdata = ng_dahdi_iface_rcvdata,
+ .disconnect = ng_dahdi_iface_disconnect,
+};
+NETGRAPH_INIT(dahdi_iface, &ng_dahdi_iface_typestruct);
+
+static void dahdi_iface_rx_task(void *context, int pending);
+
+/**
+ * iface struct
+ */
+struct dahdi_iface {
+ struct dahdi_chan *chan; /**< dahdi master channel associated with the iface */
+ struct taskqueue *rx_taskqueue; /**< rx task queue */
+ struct task rx_task; /**< rx task */
+ struct ng_node *node; /**< our netgraph node */
+ struct ng_hook *upper; /**< our upper hook */
+ char path[64]; /**< iface node path */
+};
+
+/**
+ * Create iface struct
+ */
+static struct dahdi_iface *
+dahdi_iface_alloc(struct dahdi_chan *chan)
+{
+ struct dahdi_iface *iface;
+
+ iface = malloc(sizeof(*iface), M_DAHDI, M_WAITOK | M_ZERO);
+ iface->chan = chan;
+ iface->rx_taskqueue = taskqueue_create_fast("dahdi_iface_taskq", M_WAITOK,
+ taskqueue_thread_enqueue, &iface->rx_taskqueue);
+ taskqueue_start_threads(&iface->rx_taskqueue, 1, PI_NET, "%s taskq", chan->name);
+ TASK_INIT(&iface->rx_task, 0, dahdi_iface_rx_task, chan);
+ return iface;
+}
+
+/**
+ * Free iface struct
+ */
+static void
+dahdi_iface_free(struct dahdi_iface *iface)
+{
+ taskqueue_free(iface->rx_taskqueue);
+ free(iface, M_DAHDI);
+}
+
+/**
+ * Ensure that specified netgraph type is available
+ */
+static int
+ng_ensure_type(const char *type)
+{
+ int error;
+ int fileid;
+ char filename[NG_TYPESIZ + 3];
+
+ if (ng_findtype(type) != NULL)
+ return (0);
+
+ /* Not found, try to load it as a loadable module. */
+ snprintf(filename, sizeof(filename), "ng_%s", type);
+ error = kern_kldload(curthread, filename, &fileid);
+ if (error != 0)
+ return (-1);
+
+ /* See if type has been loaded successfully. */
+ if (ng_findtype(type) == NULL) {
+ (void)kern_kldunload(curthread, fileid, LINKER_UNLOAD_NORMAL);
+ return (-1);
+ }
+
+ return (0);
+}
+
+/**
+ * Connect hooks
+ */
+static void
+dahdi_iface_connect_node_path(struct ng_node *node, const char *ourpath,
+ const char *path, const char *ourhook, const char *peerhook)
+{
+ int error;
+ struct ng_mesg *msg;
+ struct ngm_connect *nc;
+
+ NG_MKMESSAGE(msg, NGM_GENERIC_COOKIE, NGM_CONNECT, sizeof(*nc), M_WAITOK);
+ if (msg == NULL) {
+ printf("dahdi_iface(%s): Error: can not allocate NGM_CONNECT message (ignored)\n",
+ NG_NODE_NAME(node));
+ return;
+ }
+ nc = (struct ngm_connect *) msg->data;
+ strlcpy(nc->path, path, sizeof(nc->path));
+ strlcpy(nc->ourhook, ourhook, sizeof(nc->ourhook));
+ strlcpy(nc->peerhook, peerhook, sizeof(nc->peerhook));
+ NG_SEND_MSG_PATH(error, node, msg, __DECONST(char *, ourpath), NG_NODE_ID(node));
+ if (error) {
+ printf("dahdi_iface(%s): Error: NGM_CONNECT(%s<->%s): error %d (ignored)\n",
+ NG_NODE_NAME(node), ourhook, peerhook, error);
+ return;
+ }
+}
+
+/**
+ * Shutdown node specified by path
+ */
+static void
+dahdi_iface_shutdown_node_path(struct ng_node *node, const char *path)
+{
+ int error;
+ struct ng_mesg *msg;
+
+ if (path[0] == '\0')
+ return;
+
+ NG_MKMESSAGE(msg, NGM_GENERIC_COOKIE, NGM_SHUTDOWN, 0, M_WAITOK);
+ NG_SEND_MSG_PATH(error, node, msg, __DECONST(char *, path), NG_NODE_ID(node));
+ if (error) {
+ printf("dahdi_iface(%s): Error: NGM_SHUTDOWN: error %d (ignored)\n",
+ NG_NODE_NAME(node), error);
+ return;
+ }
+}
+
+/**
+ * Create a netgraph node and connect it to ng_iface instance
+ *
+ * @return 0 on success, -1 on error
+ */
+int
+dahdi_iface_create(struct dahdi_chan *chan)
+{
+ struct dahdi_iface *iface = NULL;
+ struct ng_node *node;
+ struct ng_mesg *msg;
+ char node_name[64];
+ int error;
+ struct ngm_mkpeer *ngm_mkpeer;
+
+ /* check if DAHDI netgraph node for that device already exists */
+ snprintf(node_name, sizeof(node_name), "dahdi@%s", chan->name);
+ node = ng_name2noderef(NULL, node_name);
+ if (node != NULL) {
+ printf("dahdi_iface(%s): existing netgraph node\n", NG_NODE_NAME(node));
+ NG_NODE_UNREF(node);
+ return (0);
+ }
+
+ /* create new network device */
+ iface = dahdi_iface_alloc(chan);
+ if (iface == NULL) {
+ printf("dahdi_iface(%s): Error: Failed to create iface struct\n",
+ node_name);
+ return (0);
+ }
+ chan->iface = iface;
+
+ /* create new DAHDI netgraph node */
+ if (ng_make_node_common(&ng_dahdi_iface_typestruct, &node) != 0) {
+ printf("dahdi_iface(%s): Error: Failed to create netgraph node\n",
+ node_name);
+ goto error;
+ }
+ iface->node = node;
+ NG_NODE_SET_PRIVATE(node, iface);
+ if (ng_name_node(node, node_name) != 0) {
+ printf("dahdi_iface(%s): Error: Failed to set netgraph node name\n",
+ node_name);
+ goto error;
+ }
+
+ /* create HDLC encapsulation layer peer node */
+ if (ng_ensure_type(NG_CISCO_NODE_TYPE) < 0) {
+ printf("dahdi_iface(%s): Error: Failed to load %s netgraph type\n",
+ NG_NODE_NAME(node), NG_CISCO_NODE_TYPE);
+ goto error;
+ }
+
+ NG_MKMESSAGE(msg, NGM_GENERIC_COOKIE, NGM_MKPEER, sizeof(*ngm_mkpeer), M_WAITOK);
+ ngm_mkpeer = (struct ngm_mkpeer *) msg->data;
+ strlcpy(ngm_mkpeer->type, NG_CISCO_NODE_TYPE, sizeof(ngm_mkpeer->type));
+ strlcpy(ngm_mkpeer->ourhook, DAHDI_IFACE_HOOK_UPPER, sizeof(ngm_mkpeer->ourhook));
+ strlcpy(ngm_mkpeer->peerhook, NG_CISCO_HOOK_DOWNSTREAM, sizeof(ngm_mkpeer->peerhook));
+ NG_SEND_MSG_ID(error, node, msg, NG_NODE_ID(node), NG_NODE_ID(node));
+ if (error) {
+ printf("dahdi_iface(%s): Error: NGM_MKPEER: error %d (%s)\n",
+ NG_NODE_NAME(node), error, NG_CISCO_NODE_TYPE);
+ goto error;
+ }
+
+ /* create network iface peer node */
+ if (ng_ensure_type(NG_IFACE_NODE_TYPE) < 0) {
+ printf("dahdi_iface(%s): Error: Failed to load %s netgraph type\n",
+ NG_NODE_NAME(node), NG_IFACE_NODE_TYPE);
+ goto error;
+ }
+
+ NG_MKMESSAGE(msg, NGM_GENERIC_COOKIE, NGM_MKPEER, sizeof(*ngm_mkpeer), M_WAITOK);
+ ngm_mkpeer = (struct ngm_mkpeer *) msg->data;
+ strlcpy(ngm_mkpeer->type, NG_IFACE_NODE_TYPE, sizeof(ngm_mkpeer->type));
+ strlcpy(ngm_mkpeer->ourhook, NG_CISCO_HOOK_INET, sizeof(ngm_mkpeer->ourhook));
+ strlcpy(ngm_mkpeer->peerhook, NG_IFACE_HOOK_INET, sizeof(ngm_mkpeer->peerhook));
+ NG_SEND_MSG_PATH(error, node, msg, DAHDI_IFACE_HOOK_UPPER, NG_NODE_ID(node));
+ if (error) {
+ printf("dahdi_iface(%s): Error: NGM_MKPEER: error %d (%s)\n",
+ NG_NODE_NAME(node), error, NG_IFACE_NODE_TYPE);
+ goto error;
+ }
+ snprintf(iface->path, sizeof(iface->path), "%s.%s",
+ DAHDI_IFACE_HOOK_UPPER, NG_CISCO_HOOK_INET);
+
+ /* connect other hooks */
+ dahdi_iface_connect_node_path(node, DAHDI_IFACE_HOOK_UPPER,
+ NG_CISCO_HOOK_INET, NG_CISCO_HOOK_INET6, NG_IFACE_HOOK_INET6);
+ dahdi_iface_connect_node_path(node, DAHDI_IFACE_HOOK_UPPER,
+ NG_CISCO_HOOK_INET, NG_CISCO_HOOK_APPLETALK, NG_IFACE_HOOK_ATALK);
+ dahdi_iface_connect_node_path(node, DAHDI_IFACE_HOOK_UPPER,
+ NG_CISCO_HOOK_INET, NG_CISCO_HOOK_IPX, NG_IFACE_HOOK_IPX);
+
+ /* get iface name */
+ NG_MKMESSAGE(msg, NGM_IFACE_COOKIE, NGM_IFACE_GET_IFNAME, 0, M_WAITOK);
+ NG_SEND_MSG_PATH(error, node, msg, iface->path, NG_NODE_ID(node));
+ if (error) {
+ printf("dahdi_iface(%s): Error: NGM_MKPEER: error %d (%s)\n",
+ NG_NODE_NAME(node), error, NG_IFACE_NODE_TYPE);
+ goto error;
+ }
+
+ printf("dahdi_iface(%s): new netgraph node\n",
+ NG_NODE_NAME(node));
+
+ /* setup channel */
+ if (dahdi_net_chan_init(chan, DAHDI_DEFAULT_NUM_BUFS * 8)) {
+ printf("dahdi_iface(%s): Error: Failed to initialize channel\n",
+ NG_NODE_NAME(node));
+ goto error;
+ }
+
+ return (0);
+
+error:
+ if (iface != NULL) {
+ if (iface->node != NULL) {
+ dahdi_iface_shutdown_node_path(iface->node, iface->path);
+ NG_NODE_UNREF(iface->node);
+ iface->node = NULL;
+ }
+
+ dahdi_iface_free(iface);
+ chan->iface = NULL;
+ }
+ return (-1);
+}
+
+/**
+ * Destroy a netgraph node and ng_iface instance associated with it
+ */
+void
+dahdi_iface_destroy(struct dahdi_chan *chan)
+{
+ struct dahdi_iface *iface;
+
+ if ((iface = chan->iface) == NULL || iface->node == NULL)
+ return;
+
+ /* shutdown HDLC encapsulation layer peer node */
+ if (iface->upper != NULL) {
+ dahdi_iface_shutdown_node_path(iface->node, iface->path);
+ dahdi_iface_shutdown_node_path(iface->node, DAHDI_IFACE_HOOK_UPPER);
+ }
+
+ NG_NODE_REALLY_DIE(iface->node); /* Force real removal of node */
+ ng_rmnode_self(iface->node);
+
+ dahdi_net_chan_destroy(chan);
+ chan->iface = NULL;
+ chan->flags &= ~DAHDI_FLAG_NETDEV;
+}
+
+/**
+ * Enqueues a task to receive the data frame from the synchronous line
+ *
+ * It is not possible to send the received data frame from dahdi_receive()
+ * context because it can be run in the filter thread context and mbuf
+ * allocation is not possible because of that.
+ */
+void
+dahdi_iface_rx(struct dahdi_chan *chan)
+{
+ struct dahdi_iface *iface;
+ int oldreadbuf;
+
+ if ((iface = chan->iface) == NULL)
+ return;
+
+ /* switch buffers */
+ if ((oldreadbuf = chan->inreadbuf) >= 0) {
+ chan->inreadbuf = (chan->inreadbuf + 1) % chan->numbufs;
+ if (chan->inreadbuf == chan->outreadbuf)
+ chan->inreadbuf = -1; /* no more buffers to receive to */
+ if (chan->outreadbuf < 0)
+ chan->outreadbuf = oldreadbuf; /* new buffer to read from */
+ }
+
+ taskqueue_enqueue_fast(iface->rx_taskqueue, &iface->rx_task);
+}
+
+/**
+ * Receive data frame from the synchronous line
+ *
+ * Receives data frame from the synchronous line and sends it up to the upstream.
+ */
+static void
+dahdi_iface_rx_task(void *context, int pending)
+{
+ struct dahdi_chan *chan = context;
+ struct dahdi_iface *iface;
+ unsigned long flags;
+ int oldreadbuf;
+
+ if ((iface = chan->iface) == NULL)
+ return;
+
+ spin_lock_irqsave(&chan->lock, flags);
+ while ((oldreadbuf = chan->outreadbuf) >= 0) {
+ struct mbuf *m = NULL;
+
+ /* read frame */
+ if (iface->upper != NULL && chan->readn[chan->outreadbuf] > 1) {
+
+ /* Drop the FCS */
+ chan->readn[chan->outreadbuf] -= 2;
+
+ MGETHDR(m, M_NOWAIT, MT_DATA);
+ if (m != NULL) {
+ if (chan->readn[chan->outreadbuf] >= MINCLSIZE) {
+ MCLGET(m, M_NOWAIT);
+ }
+
+ /* copy data */
+ m_append(m, chan->readn[chan->outreadbuf], chan->readbuf[chan->outreadbuf]);
+ }
+ }
+
+ /* switch buffers */
+ chan->readn[chan->outreadbuf] = 0;
+ chan->readidx[chan->outreadbuf] = 0;
+ chan->outreadbuf = (chan->outreadbuf + 1) % chan->numbufs;
+ if (chan->outreadbuf == chan->inreadbuf)
+ chan->outreadbuf = -1; /* no more buffers to read from */
+ if (chan->inreadbuf < 0)
+ chan->inreadbuf = oldreadbuf; /* new buffer to read to */
+
+ if (m != NULL) {
+ int error;
+
+ spin_unlock_irqrestore(&chan->lock, flags);
+ NG_SEND_DATA_ONLY(error, iface->upper, m);
+ spin_lock_irqsave(&chan->lock, flags);
+ }
+ }
+ spin_unlock_irqrestore(&chan->lock, flags);
+}
+
+/**
+ * Abort receiving a data frame
+ */
+void
+dahdi_iface_abort(struct dahdi_chan *chan, int event)
+{
+ /* nothing to do */
+#if 0
+ module_printk(KERN_DEBUG, "%s: event %d\n", __func__, event);
+#endif
+}
+
+/**
+ * Wake up transmitter
+ */
+void
+dahdi_iface_wakeup_tx(struct dahdi_chan *chan)
+{
+ /* XXX not implemented */
+}
+
+/**
+ * Receive an incoming control message
+ */
+static int
+ng_dahdi_iface_rcvmsg(struct ng_node *node, struct ng_item *item, struct ng_hook *lasthook)
+{
+ /* struct dahdi_iface *iface = NG_NODE_PRIVATE(node); */
+ struct ng_mesg *msg, *resp = NULL;
+ int error = 0;
+
+ NGI_GET_MSG(item, msg);
+ switch (msg->header.typecookie) {
+ case NGM_IFACE_COOKIE:
+ switch (msg->header.cmd) {
+ case NGM_IFACE_GET_IFNAME:
+ printf("dahdi_iface(%s): interface %s\n",
+ NG_NODE_NAME(node), msg->data);
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+ NG_RESPOND_MSG(error, node, item, resp);
+ NG_FREE_MSG(msg);
+ return (error);
+}
+
+/**
+ * Shutdown node
+ *
+ * Reset the node but does not remove it unless the REALLY_DIE flag is set.
+ */
+static int
+ng_dahdi_iface_shutdown(struct ng_node *node)
+{
+ struct dahdi_iface *iface = NG_NODE_PRIVATE(node);
+
+ if (node->nd_flags & NGF_REALLY_DIE) {
+ /* destroy the node itself */
+ printf("dahdi_iface(%s): destroying netgraph node\n",
+ NG_NODE_NAME(node));
+ NG_NODE_SET_PRIVATE(node, NULL);
+ NG_NODE_UNREF(node);
+
+ /* destroy the iface */
+ dahdi_iface_free(iface);
+ return (0);
+ }
+
+ NG_NODE_REVIVE(node); /* Tell ng_rmnode we are persistent */
+ return (0);
+}
+
+/*
+ * Check for attaching a new hook
+ */
+static int
+ng_dahdi_iface_newhook(struct ng_node *node, struct ng_hook *hook, const char *name)
+{
+ struct dahdi_iface *iface = NG_NODE_PRIVATE(node);
+ struct ng_hook **hookptr;
+
+ if (strcmp(name, DAHDI_IFACE_HOOK_UPPER) == 0) {
+ hookptr = &iface->upper;
+ } else {
+ printf("dahdi_iface(%s): unsupported hook %s\n",
+ NG_NODE_NAME(iface->node), name);
+ return (EINVAL);
+ }
+
+ if (*hookptr != NULL) {
+ printf("dahdi_iface(%s): %s hook is already connected\n",
+ NG_NODE_NAME(iface->node), name);
+ return (EISCONN);
+ }
+
+ *hookptr = hook;
+ return (0);
+}
+
+/*
+ * Hook disconnection
+ */
+static int
+ng_dahdi_iface_disconnect(struct ng_hook *hook)
+{
+ struct ng_node *node = NG_HOOK_NODE(hook);
+ struct dahdi_iface *iface = NG_NODE_PRIVATE(node);
+
+ if (hook == iface->upper) {
+ iface->upper = NULL;
+ } else {
+ panic("dahdi_iface(%s): %s: weird hook", NG_NODE_NAME(iface->node), __func__);
+ }
+
+ return (0);
+}
+
+/**
+ * Receive data
+ *
+ * Receives data frame from the upstream and sends it down to the synchronous line.
+ */
+static int
+ng_dahdi_iface_rcvdata(struct ng_hook *hook, struct ng_item *item)
+{
+ struct ng_node *node = NG_HOOK_NODE(hook);
+ struct dahdi_iface *iface = NG_NODE_PRIVATE(node);
+ struct dahdi_chan *ss = iface->chan;
+ struct mbuf *m;
+ int retval = 0;
+ unsigned long flags;
+ unsigned char *data;
+ int data_len;
+
+ /* get mbuf */
+ NGI_GET_M(item, m);
+ NG_FREE_ITEM(item);
+ data_len = m_length(m, NULL);
+
+ /* see if we have any buffers */
+ spin_lock_irqsave(&ss->lock, flags);
+ if (data_len > ss->blocksize - 2) {
+ printf("dahdi_iface(%s): mbuf is too large (%d > %d)",
+ NG_NODE_NAME(iface->node), data_len, ss->blocksize - 2);
+ /* stats->tx_dropped++ */
+ retval = EINVAL;
+ goto out;
+ }
+ if (ss->inwritebuf < 0) {
+ /* no space */
+ retval = ENOBUFS;
+ goto out;
+ }
+
+ /* we have a place to put this packet */
+ data = ss->writebuf[ss->inwritebuf];
+ m_copydata(m, 0, data_len, data);
+ ss->writen[ss->inwritebuf] = data_len;
+ dahdi_net_chan_xmit(ss);
+
+out:
+ spin_unlock_irqrestore(&ss->lock, flags);
+
+ /* free memory */
+ NG_FREE_M(m);
+ return (retval);
+}
Index: freebsd/freebsd/dahdi/ng_dahdi_iface.h
===================================================================
--- freebsd/freebsd/dahdi/ng_dahdi_iface.h (revision 0)
+++ freebsd/freebsd/dahdi/ng_dahdi_iface.h (revision 10329)
@@ -0,0 +1,61 @@
+/*-
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Max Khon under sponsorship from UniqueSec HB.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+#ifndef _NG_DAHDI_IFACE_H_
+#define _NG_DAHDI_IFACE_H_
+
+/**
+ * Create a netgraph node and connect it to ng_iface instance
+ *
+ * @return 0 on success, -1 on error
+ */
+int dahdi_iface_create(struct dahdi_chan *chan);
+
+/**
+ * Destroy a netgraph node and ng_iface instance associated with it
+ */
+void dahdi_iface_destroy(struct dahdi_chan *chan);
+
+/**
+ * Process data frame received from the synchronous line
+ */
+void dahdi_iface_rx(struct dahdi_chan *chan);
+
+/**
+ * Abort receiving a data frame
+ */
+void dahdi_iface_abort(struct dahdi_chan *chan, int event);
+
+/**
+ * Wake up transmitter
+ */
+void dahdi_iface_wakeup_tx(struct dahdi_chan *chan);
+
+#endif /* _NG_DAHDI_IFACE_H_ */
Index: freebsd/freebsd/dahdi/Makefile
===================================================================
--- freebsd/freebsd/dahdi/Makefile (revision 10321)
+++ freebsd/freebsd/dahdi/Makefile (working copy)
@@ -3,7 +3,7 @@
.PATH: ${.CURDIR}/../../drivers/dahdi
KMOD= dahdi
-SRCS= dahdi-base.c bsd-compat.c version.h
+SRCS= dahdi-base.c ng_dahdi_iface.c bsd-compat.c version.h
SRCS+= device_if.h bus_if.h pci_if.h
CLEANFILES= version.h
INCS= user.h wctdm_user.h compat/types.h
Index: freebsd/drivers/dahdi/dahdi-base.c
===================================================================
--- freebsd/drivers/dahdi/dahdi-base.c (revision 10321)
+++ freebsd/drivers/dahdi/dahdi-base.c (working copy)
@@ -137,6 +137,8 @@
} ;
#if defined(__FreeBSD__)
+#include "ng_dahdi_iface.h"
+
MALLOC_DEFINE(M_DAHDI, "dahdi", "DAHDI interface data structures");
/*
@@ -2009,6 +2011,62 @@
}
#endif
+int dahdi_net_chan_init(struct dahdi_chan *ms, int numbufs)
+{
+ int res;
+
+ ms->txbufpolicy = DAHDI_POLICY_IMMEDIATE;
+ ms->rxbufpolicy = DAHDI_POLICY_IMMEDIATE;
+
+ res = dahdi_reallocbufs(ms, DAHDI_DEFAULT_MTU_MRU, numbufs);
+ if (res)
+ return res;
+
+ fasthdlc_init(&ms->rxhdlc, (ms->flags & DAHDI_FLAG_HDLC56) ? FASTHDLC_MODE_56 : FASTHDLC_MODE_64);
+ fasthdlc_init(&ms->txhdlc, (ms->flags & DAHDI_FLAG_HDLC56) ? FASTHDLC_MODE_56 : FASTHDLC_MODE_64);
+ ms->infcs = PPP_INITFCS;
+ return 0;
+}
+
+void dahdi_net_chan_destroy(struct dahdi_chan *ms)
+{
+ dahdi_reallocbufs(ms, 0, 0);
+}
+
+void dahdi_net_chan_xmit(struct dahdi_chan *ss)
+{
+ int x, oldbuf;
+ unsigned int fcs;
+ unsigned char *data = ss->writebuf[ss->inwritebuf];
+
+ ss->writeidx[ss->inwritebuf] = 0;
+ /* Calculate the FCS */
+ fcs = PPP_INITFCS;
+ for (x=0;x<ss->writen[ss->inwritebuf];x++)
+ fcs = PPP_FCS(fcs, data[x]);
+ /* Invert it */
+ fcs ^= 0xffff;
+ /* Send it out LSB first */
+ data[ss->writen[ss->inwritebuf]++] = (fcs & 0xff);
+ data[ss->writen[ss->inwritebuf]++] = (fcs >> 8) & 0xff;
+ /* Advance to next window */
+ oldbuf = ss->inwritebuf;
+ ss->inwritebuf = (ss->inwritebuf + 1) % ss->numbufs;
+
+ if (ss->inwritebuf == ss->outwritebuf) {
+ /* Whoops, no more space. */
+ ss->inwritebuf = -1;
+#if !defined(__FreeBSD__)
+ netif_stop_queue(ztchan_to_dev(ss));
+#endif
+ }
+ if (ss->outwritebuf < 0) {
+ /* Let the interrupt handler know there's
+ some space for us */
+ ss->outwritebuf = oldbuf;
+ }
+}
+
#ifdef CONFIG_DAHDI_NET
#ifdef NEW_HDLC_INTERFACE
static int dahdi_net_open(struct net_device *dev)
@@ -2037,17 +2095,11 @@
module_printk(KERN_NOTICE, "%s is not a net device!\n", ms->name);
return -EINVAL;
}
- ms->txbufpolicy = DAHDI_POLICY_IMMEDIATE;
- ms->rxbufpolicy = DAHDI_POLICY_IMMEDIATE;
- res = dahdi_reallocbufs(ms, DAHDI_DEFAULT_MTU_MRU, DAHDI_DEFAULT_NUM_BUFS);
+ res = dahdi_net_chan_init(ms);
if (res)
return res;
- fasthdlc_init(&ms->rxhdlc, (ms->flags & DAHDI_FLAG_HDLC56) ? FASTHDLC_MODE_56 : FASTHDLC_MODE_64);
- fasthdlc_init(&ms->txhdlc, (ms->flags & DAHDI_FLAG_HDLC56) ? FASTHDLC_MODE_56 : FASTHDLC_MODE_64);
- ms->infcs = PPP_INITFCS;
-
netif_start_queue(ztchan_to_dev(ms));
#ifdef CONFIG_DAHDI_DEBUG
@@ -2105,7 +2157,7 @@
}
/* Not much to do here. Just deallocate the buffers */
netif_stop_queue(ztchan_to_dev(ms));
- dahdi_reallocbufs(ms, 0, 0);
+ dahdi_net_chan_destroy(ms);
hdlc_close(dev);
#ifdef NEW_HDLC_INTERFACE
return 0;
@@ -2165,8 +2217,6 @@
struct net_device_stats *stats = &ss->hdlcnetdev->netdev.stats;
#endif
int retval = 1;
- int x,oldbuf;
- unsigned int fcs;
unsigned char *data;
unsigned long flags;
/* See if we have any buffers */
@@ -2181,31 +2231,7 @@
data = ss->writebuf[ss->inwritebuf];
memcpy(data, skb->data, skb->len);
ss->writen[ss->inwritebuf] = skb->len;
- ss->writeidx[ss->inwritebuf] = 0;
- /* Calculate the FCS */
- fcs = PPP_INITFCS;
- for (x=0;x<skb->len;x++)
- fcs = PPP_FCS(fcs, data[x]);
- /* Invert it */
- fcs ^= 0xffff;
- /* Send it out LSB first */
- data[ss->writen[ss->inwritebuf]++] = (fcs & 0xff);
- data[ss->writen[ss->inwritebuf]++] = (fcs >> 8) & 0xff;
- /* Advance to next window */
- oldbuf = ss->inwritebuf;
- ss->inwritebuf = (ss->inwritebuf + 1) % ss->numbufs;
-
- if (ss->inwritebuf == ss->outwritebuf) {
- /* Whoops, no more space. */
- ss->inwritebuf = -1;
-
- netif_stop_queue(ztchan_to_dev(ss));
- }
- if (ss->outwritebuf < 0) {
- /* Let the interrupt handler know there's
- some space for us */
- ss->outwritebuf = oldbuf;
- }
+ dahdi_net_chan_xmit(ss);
dev->trans_start = jiffies;
stats->tx_packets++;
stats->tx_bytes += ss->writen[oldbuf];
@@ -2347,6 +2373,10 @@
kfree(chan->hdlcnetdev);
chan->hdlcnetdev = NULL;
}
+#elif defined(__FreeBSD__)
+ if (chan->flags & DAHDI_FLAG_NETDEV) {
+ dahdi_iface_destroy(chan);
+ }
#endif
write_lock_irqsave(&chan_lock, flags);
if (test_bit(DAHDI_FLAGBIT_REGISTERED, &chan->flags)) {
@@ -4649,6 +4679,12 @@
chans[ch.chan]->hdlcnetdev = NULL;
chans[ch.chan]->flags &= ~DAHDI_FLAG_NETDEV;
}
+#elif defined(__FreeBSD__)
+ if (chans[ch.chan]->flags & DAHDI_FLAG_NETDEV) {
+ spin_unlock_irqrestore(&chans[ch.chan]->lock, flags);
+ dahdi_iface_destroy(chans[ch.chan]);
+ spin_lock_irqsave(&chans[ch.chan]->lock, flags);
+ }
#else
if (ch.sigtype == DAHDI_SIG_HDLCNET) {
spin_unlock_irqrestore(&chans[ch.chan]->lock, flags);
@@ -4774,6 +4808,16 @@
res = -1;
}
}
+#elif defined(__FreeBSD__)
+ if (!res &&
+ newmaster == chans[ch.chan] &&
+ chans[ch.chan]->sig == DAHDI_SIG_HDLCNET) {
+ spin_unlock_irqrestore(&chans[ch.chan]->lock, flags);
+ /* Briefly restore interrupts while we register the device */
+ if ((res = dahdi_iface_create(chans[ch.chan])) == 0)
+ chans[ch.chan]->flags |= DAHDI_FLAG_NETDEV;
+ spin_lock_irqsave(&chans[ch.chan]->lock, flags);
+ }
#endif
if ((chans[ch.chan]->sig == DAHDI_SIG_HDLCNET) &&
(chans[ch.chan] == newmaster) &&
@@ -7003,6 +7047,9 @@
#ifdef CONFIG_DAHDI_NET
if (ms->flags & DAHDI_FLAG_NETDEV)
netif_wake_queue(ztchan_to_dev(ms));
+#elif defined(__FreeBSD__)
+ if (ms->flags & DAHDI_FLAG_NETDEV)
+ dahdi_iface_wakeup_tx(ms);
#endif
#ifdef CONFIG_DAHDI_PPP
if (ms->flags & DAHDI_FLAG_PPP) {
@@ -8088,6 +8135,10 @@
ms->readn[ms->inreadbuf] = 0;
ms->readidx[ms->inreadbuf] = 0;
} else
+#elif defined(__FreeBSD__)
+ if (ms->flags & DAHDI_FLAG_NETDEV) {
+ dahdi_iface_rx(ms);
+ } else
#endif
{
/* This logic might confuse and astound. Basically we need to find
@@ -8173,6 +8224,10 @@
if (abort == DAHDI_EVENT_ABORT)
stats->rx_frame_errors++;
} else
+#elif defined(__FreeBSD__)
+ if (ms->flags & DAHDI_FLAG_NETDEV) {
+ dahdi_iface_abort(ms, abort);
+ } else
#endif
#ifdef CONFIG_DAHDI_PPP
if (ms->flags & DAHDI_FLAG_PPP) {
@@ -9351,6 +9406,7 @@
DAHDI_DEV_MODULE(dahdi);
MODULE_VERSION(dahdi, 1);
MODULE_DEPEND(dahdi, firmware, 1, 1, 1);
+
#ifdef CONFIG_DAHDI_CORE_TIMER
static int
dahdi_dummy_modevent(module_t mod, int cmd, void *arg)