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 +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include + +#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;xwriten[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;xlen;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)