Index: include/dahdi/dahdi_config.h =================================================================== --- include/dahdi/dahdi_config.h (revision 9481) +++ include/dahdi/dahdi_config.h (working copy) @@ -184,4 +184,9 @@ */ /* #define DAHDI_AUDIO_NOTIFY */ +/* + * Creates an interface for mirroring the raw channel data out to a pseudo-chan + */ +/* #define CONFIG_DAHDI_MIRROR */ + #endif Index: include/dahdi/user.h =================================================================== --- include/dahdi/user.h (revision 9481) +++ include/dahdi/user.h (working copy) @@ -37,6 +37,7 @@ #include #include +#include #ifndef ELAST #define ELAST 500 @@ -1076,6 +1077,14 @@ #define DAHDI_ECHOCANCEL_FAX_MODE _IOW(DAHDI_CODE, 102, int) +/* + * Defines which channel to receive mirrored traffic from + */ +#ifdef CONFIG_DAHDI_MIRROR +#define DAHDI_RXMIRROR _IOW(DAHDI_CODE, 103, int) +#define DAHDI_TXMIRROR _IOW(DAHDI_CODE, 104, int) +#endif /* CONFIG_DAHDI_MIRROR */ + /* Get current status IOCTL */ /* Defines for Radio Status (dahdi_radio_stat.radstat) bits */ Index: include/dahdi/kernel.h =================================================================== --- include/dahdi/kernel.h (revision 9481) +++ include/dahdi/kernel.h (working copy) @@ -444,6 +444,11 @@ struct file *file; /*!< File structure */ +#ifdef CONFIG_DAHDI_MIRROR + struct dahdi_chan *rxmirror; /*!< channel we mirror reads to */ + struct dahdi_chan *txmirror; /*!< channel we mirror writes to */ + struct dahdi_chan *srcmirror; /*!< channel we mirror from */ +#endif /* CONFIG_DAHDI_MIRROR */ struct dahdi_span *span; /*!< Span we're a member of */ int sig; /*!< Signalling */ int sigcap; /*!< Capability for signalling */ Index: drivers/dahdi/dahdi-base.c =================================================================== --- drivers/dahdi/dahdi-base.c (revision 9481) +++ drivers/dahdi/dahdi-base.c (working copy) @@ -2799,9 +2799,36 @@ if (chan) { /* Chan lock protects contents against potentially non atomic accesses. * So if the pointer setting is not atomic, we should protect */ +#ifdef CONFIG_DAHDI_MIRROR + if (chan->srcmirror) { + struct dahdi_chan *const srcmirror = chan->srcmirror; + spin_lock_irqsave(&srcmirror->lock, flags); + if (chan == srcmirror->txmirror) { + module_printk(KERN_INFO, "Chan %d tx mirror " \ + "to %d stopped\n", + srcmirror->txmirror->channo, + srcmirror->channo); + srcmirror->txmirror = NULL; + } + + if (chan == srcmirror->rxmirror) { + module_printk(KERN_INFO, "Chan %d rx mirror " \ + "to %d stopped\n", + srcmirror->rxmirror->channo, + srcmirror->channo); + chan->srcmirror->rxmirror = NULL; + } + spin_unlock_irqrestore(&chan->srcmirror->lock, flags); + } +#endif /* CONFIG_DAHDI_MIRROR */ + spin_lock_irqsave(&chan->lock, flags); chan->file = NULL; file->private_data = NULL; +#ifdef CONFIG_DAHDI_MIRROR + chan->srcmirror = NULL; +#endif /* CONFIG_DAHDI_MIRROR */ + spin_unlock_irqrestore(&chan->lock, flags); close_channel(chan); clear_bit(DAHDI_FLAGBIT_OPEN, &chan->flags); @@ -5017,6 +5044,95 @@ return ret; } +#ifdef CONFIG_DAHDI_MIRROR +static int dahdi_ioctl_rxmirror(struct file *file, unsigned long data) +{ + int res; + int i; + unsigned long flags; + struct dahdi_chan *const chan = chan_from_file(file); + struct dahdi_chan *srcmirror; + + if (!chan || chan->srcmirror) + return -ENODEV; + + res = get_user(i, (int __user *)data); + if (res) + return res; + + srcmirror = chan_from_num(i); + if (!srcmirror) + return -EINVAL; + + module_printk(KERN_INFO, "Chan %d rx mirrored to %d\n", + srcmirror->channo, chan->channo); + + spin_lock_irqsave(&srcmirror->lock, flags); + if (srcmirror->rxmirror == NULL) + srcmirror->rxmirror = chan; + + spin_unlock_irqrestore(&srcmirror->lock, flags); + if (srcmirror->rxmirror != chan) { + module_printk(KERN_INFO, "Chan %d cannot be rxmirrored, " \ + "already in use\n", srcmirror->channo); + return -EFAULT; + } + + spin_lock_irqsave(&chan->lock, flags); + chan->srcmirror = srcmirror; + chan->flags = srcmirror->flags; + chan->sig = srcmirror->sig; + clear_bit(DAHDI_FLAGBIT_OPEN, &chan->flags); + spin_unlock_irqrestore(&chan->lock, flags); + + return 0; +} + +static int dahdi_ioctl_txmirror(struct file *file, unsigned long data) +{ + int res; + int i; + unsigned long flags; + struct dahdi_chan *const chan = chan_from_file(file); + struct dahdi_chan *srcmirror; + + if (!chan || chan->srcmirror) + return -ENODEV; + + res = get_user(i, (int __user *)data); + if (res) + return res; + + srcmirror = chan_from_num(i); + if (!srcmirror) + return -EINVAL; + + module_printk(KERN_INFO, "Chan %d tx mirrored to %d\n", + srcmirror->channo, chan->channo); + + spin_lock_irqsave(&srcmirror->lock, flags); + srcmirror->txmirror = chan; + if (srcmirror->txmirror == NULL) + srcmirror->txmirror = chan; + spin_unlock_irqrestore(&srcmirror->lock, flags); + + if (srcmirror->txmirror != chan) { + module_printk(KERN_INFO, "Chan %d cannot be txmirrored, " \ + "already in use\n", i); + return -EFAULT; + } + + spin_lock_irqsave(&chan->lock, flags); + chan->srcmirror = srcmirror; + chan->flags = srcmirror->flags; + chan->sig = srcmirror->sig; + clear_bit(DAHDI_FLAGBIT_OPEN, &chan->flags); + spin_unlock_irqrestore(&chan->lock, flags); + + return 0; +} +#endif /* CONFIG_DAHDI_MIRROR */ + static int dahdi_chanandpseudo_ioctl(struct file *file, unsigned int cmd, unsigned long data) @@ -5033,6 +5149,14 @@ if (!chan) return -EINVAL; switch(cmd) { +#ifdef CONFIG_DAHDI_MIRROR + case DAHDI_RXMIRROR: + return dahdi_ioctl_rxmirror(file, data); + + case DAHDI_TXMIRROR: + return dahdi_ioctl_txmirror(file, data); +#endif /* CONFIG_DAHDI_MIRROR */ + case DAHDI_DIALING: spin_lock_irqsave(&chan->lock, flags); j = chan->dialing; @@ -6543,8 +6667,17 @@ txb[x] = ms->txgain[txb[x]]; } +static void __putbuf_chunk(struct dahdi_chan *ss, unsigned char *rxb, + int bytes); + static inline void __dahdi_getbuf_chunk(struct dahdi_chan *ss, unsigned char *txb) { + + +#ifdef CONFIG_DAHDI_MIRROR + unsigned char *orig_txb = txb; +#endif /* CONFIG_DAHDI_MIRROR */ + /* Called with ss->lock held */ /* We transmit data from our master channel */ struct dahdi_chan *ms = ss->master; @@ -6706,6 +6839,14 @@ bytes = 0; } } + +#ifdef CONFIG_DAHDI_MIRROR + if (ss->txmirror) { + spin_lock(&ss->txmirror->lock); + __putbuf_chunk(ss->txmirror, orig_txb, DAHDI_CHUNKSIZE); + spin_unlock(&ss->txmirror->lock); + } +#endif /* CONFIG_DAHDI_MIRROR */ } static inline void rbs_itimer_expire(struct dahdi_chan *chan) @@ -7584,7 +7725,7 @@ } /* HDLC (or other) receiver buffer functions for read side */ -static inline void __putbuf_chunk(struct dahdi_chan *ss, unsigned char *rxb, int bytes) +static void __putbuf_chunk(struct dahdi_chan *ss, unsigned char *rxb, int bytes) { /* We transmit data from our master channel */ /* Called with ss->lock held */ @@ -7601,7 +7742,6 @@ int res; int left, x; - while(bytes) { #if defined(CONFIG_DAHDI_NET) || defined(CONFIG_DAHDI_PPP) skb = NULL; @@ -7871,11 +8011,20 @@ } #endif } + } static inline void __dahdi_putbuf_chunk(struct dahdi_chan *ss, unsigned char *rxb) { __putbuf_chunk(ss, rxb, DAHDI_CHUNKSIZE); + +#ifdef CONFIG_DAHDI_MIRROR + if (ss->rxmirror) { + spin_lock(&ss->rxmirror->lock); + __putbuf_chunk(ss->rxmirror, rxb, DAHDI_CHUNKSIZE); + spin_unlock(&ss->rxmirror->lock); + } +#endif /* CONFIG_DAHDI_MIRROR */ } static void __dahdi_hdlc_abort(struct dahdi_chan *ss, int event) @@ -8373,8 +8522,16 @@ list_for_each_entry(pseudo, &pseudo_chans, node) { unsigned char tmp[DAHDI_CHUNKSIZE]; spin_lock(&pseudo->chan.lock); - __dahdi_getempty(&pseudo->chan, tmp); - __dahdi_receive_chunk(&pseudo->chan, tmp); +#ifdef CONFIG_DAHDI_MIRROR + // if this is a mirroring don't generate garbage + if(!pseudo->chan.srcmirror) + { +#endif /* CONFIG_DAHDI_MIRROR */ + __dahdi_getempty(&pseudo->chan, tmp); + __dahdi_receive_chunk(&pseudo->chan, tmp); +#ifdef CONFIG_DAHDI_MIRROR + } +#endif /* CONFIG_DAHDI_MIRROR */ spin_unlock(&pseudo->chan.lock); }