diff options
author | Max Khon <fjoe@FreeBSD.org> | 2011-11-07 17:22:34 +0000 |
---|---|---|
committer | Max Khon <fjoe@FreeBSD.org> | 2011-11-07 17:22:34 +0000 |
commit | c2ec7913675c5b9e7901ca8f2ec272a1fd99ed4f (patch) | |
tree | 0333cbc86cccf0c73bce70a713d8a0799fb0e64d /misc/dahdi-kmod | |
parent | 26336485a24470d50ea1da957f48ff4a564c3b33 (diff) | |
download | ports-c2ec7913675c5b9e7901ca8f2ec272a1fd99ed4f.tar.gz ports-c2ec7913675c5b9e7901ca8f2ec272a1fd99ed4f.zip |
Implement nethdlc with Cisco HDLC encapsulation: when a span is configured
in nethdlc mode ngX network interface is created.
Notes
Notes:
svn path=/head/; revision=285244
Diffstat (limited to 'misc/dahdi-kmod')
-rw-r--r-- | misc/dahdi-kmod/Makefile | 2 | ||||
-rw-r--r-- | misc/dahdi-kmod/files/patch-dahdi-iface | 916 |
2 files changed, 917 insertions, 1 deletions
diff --git a/misc/dahdi-kmod/Makefile b/misc/dahdi-kmod/Makefile index 32a1d4c2fdb9..9d583cdc642d 100644 --- a/misc/dahdi-kmod/Makefile +++ b/misc/dahdi-kmod/Makefile @@ -7,7 +7,7 @@ PORTNAME= dahdi-kmod PORTVERSION= ${DAHDI_VERSION:S/-//g} -PORTREVISION= 0 +PORTREVISION= 1 CATEGORIES= misc kld MASTER_SITES= ${MASTER_SITE_LOCAL}\ http://downloads.digium.com/pub/telephony/firmware/releases/:firmware diff --git a/misc/dahdi-kmod/files/patch-dahdi-iface b/misc/dahdi-kmod/files/patch-dahdi-iface new file mode 100644 index 000000000000..66ed552ebf6f --- /dev/null +++ b/misc/dahdi-kmod/files/patch-dahdi-iface @@ -0,0 +1,916 @@ +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 10326) +@@ -0,0 +1,584 @@ ++/*- ++ * 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)) { ++ 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; ++ ++ if ((iface = chan->iface) == NULL) ++ return; ++ ++ 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; ++ ++ if ((iface = chan->iface) == NULL) ++ return; ++ ++ /* ++ * Our network receiver logic is MUCH different. ++ * We actually only use a single buffer ++ */ ++ spin_lock_irqsave(&chan->lock, flags); ++ if (iface->upper != NULL && chan->readn[chan->inreadbuf] > 1) { ++ struct mbuf *m; ++ ++ /* Drop the FCS */ ++ chan->readn[chan->inreadbuf] -= 2; ++ ++ MGETHDR(m, M_NOWAIT, MT_DATA); ++ if (m != NULL) { ++ int error; ++ ++ if (chan->readn[chan->inreadbuf] >= MINCLSIZE) { ++ MCLGET(m, M_NOWAIT); ++ } ++ ++ /* copy data */ ++ m_append(m, chan->readn[chan->inreadbuf], chan->readbuf[chan->inreadbuf]); ++ NG_SEND_DATA_ONLY(error, iface->upper, m); ++ } ++ } ++ ++ /* We don't cycle through buffers, just reuse the same one */ ++ chan->readn[chan->inreadbuf] = 0; ++ chan->readidx[chan->inreadbuf] = 0; ++ 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 = ENXIO; ++ 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 10325) +@@ -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/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); ++void dahdi_net_chan_destroy(struct dahdi_chan *chan); ++void dahdi_net_chan_xmit(struct dahdi_chan *chan); ++ + #endif /* _DAHDI_KERNEL_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 res; ++ ++ ms->txbufpolicy = DAHDI_POLICY_IMMEDIATE; ++ ms->rxbufpolicy = DAHDI_POLICY_IMMEDIATE; ++ ++ res = dahdi_reallocbufs(ms, DAHDI_DEFAULT_MTU_MRU, DAHDI_DEFAULT_NUM_BUFS); ++ 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,10 @@ + chans[ch.chan]->hdlcnetdev = NULL; + chans[ch.chan]->flags &= ~DAHDI_FLAG_NETDEV; + } ++#elif defined(__FreeBSD__) ++ if (chans[ch.chan]->flags & DAHDI_FLAG_NETDEV) { ++ dahdi_iface_destroy(chans[ch.chan]); ++ } + #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) |