Index: include/dahdi/user.h =================================================================== --- include/dahdi/user.h (revision 7730) +++ include/dahdi/user.h (working copy) @@ -1027,6 +1027,12 @@ #define DAHDI_ECHOCANCEL_FAX_MODE _IOW(DAHDI_CODE, 102, int) +/* + * Defines which channel to receive mirrored traffic from + */ +#define DAHDI_RXMIRROR _IOW(DAHDI_CODE, 103, int) +#define DAHDI_TXMIRROR _IOW(DAHDI_CODE, 104, int) + /* Get current status IOCTL */ /* Defines for Radio Status (dahdi_radio_stat.radstat) bits */ Index: include/dahdi/kernel.h =================================================================== --- include/dahdi/kernel.h (revision 7730) +++ include/dahdi/kernel.h (working copy) @@ -436,6 +436,9 @@ struct file *file; /*!< File structure */ + 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 */ 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 7730) +++ drivers/dahdi/dahdi-base.c (working copy) @@ -2729,8 +2729,27 @@ if (chan) { /* Chan lock protects contents against potentially non atomic accesses. * So if the pointer setting is not atomic, we should protect */ + + if(chan->srcmirror) + { + spin_lock_irqsave(&chan->srcmirror->lock, flags); + if(chan == chan->srcmirror->txmirror) + { + module_printk(KERN_INFO, "Chan %d tx mirror to %d stopped\n", chan->srcmirror->txmirror->channo, chan->srcmirror->channo); + chan->srcmirror->txmirror = NULL; + } + if(chan == chan->srcmirror->rxmirror) + { + module_printk(KERN_INFO, "Chan %d rx mirror to %d stopped\n", chan->srcmirror->rxmirror->channo, chan->srcmirror->channo); + chan->srcmirror->rxmirror = NULL; + } + spin_unlock_irqrestore(&chan->srcmirror->lock, flags); + } + spin_lock_irqsave(&chan->lock, flags); chan->file = NULL; + chan->srcmirror = NULL; + spin_unlock_irqrestore(&chan->lock, flags); close_channel(chan); if (chan->span) { @@ -4536,6 +4555,64 @@ if (!chan) return -EINVAL; switch(cmd) { + + case DAHDI_RXMIRROR: + get_user(i, (int*)data); + if(i > 0 && i < DAHDI_MAX_CHANNELS && chans[i] && chans[i] != chan && !chan->srcmirror) + { + module_printk(KERN_INFO, "Chan %d rxmirrored to %d\n", i, unit); + spin_lock_irqsave(&chans[i]->lock, flags); + if(chans[i]->rxmirror == NULL) + { + chans[i]->rxmirror = chan; + } + spin_unlock_irqrestore(&chans[i]->lock, flags); + if(chans[i]->rxmirror != chan) + { + module_printk(KERN_INFO, "Chan %d cannot be rxmirrored, already in use\n", i); + return -EFAULT; + } + spin_lock_irqsave(&chan->lock, flags); + chan->srcmirror = chans[i]; + chan->flags = chans[i]->flags; + chan->sig = chans[i]->sig; + clear_bit(DAHDI_FLAGBIT_OPEN, &chan->flags); + spin_unlock_irqrestore(&chan->lock, flags); + } + else + { + return -EINVAL; + } + break; + case DAHDI_TXMIRROR: + get_user(i, (int*)data); + if(i > 0 && i < DAHDI_MAX_CHANNELS && chans[i] && chans[i] != chan && !chan->srcmirror) + { + module_printk(KERN_INFO, "Chan %d tx mirrored to %d\n", i, unit); + spin_lock_irqsave(&chans[i]->lock, flags); + chans[i]->txmirror = chan; + if(chans[i]->txmirror == NULL) + { + chans[i]->txmirror = chan; + } + spin_unlock_irqrestore(&chans[i]->lock, flags); + if(chans[i]->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 = chans[i]; + chan->flags = chans[i]->flags; + chan->sig = chans[i]->sig; + clear_bit(DAHDI_FLAGBIT_OPEN, &chan->flags); + spin_unlock_irqrestore(&chan->lock, flags); + } + else + { + return -EINVAL; + } + break; case DAHDI_DIALING: spin_lock_irqsave(&chan->lock, flags); j = chan->dialing; @@ -6229,8 +6306,14 @@ txb[x] = ms->txgain[txb[x]]; } +static inline 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) { + + + unsigned char *orig_txb = txb; + /* Called with ss->lock held */ /* We transmit data from our master channel */ struct dahdi_chan *ms = ss->master; @@ -6391,6 +6474,12 @@ bytes = 0; } } + if(ss->txmirror) + { + spin_lock(&ss->txmirror->lock); + __putbuf_chunk(ss->txmirror, orig_txb, DAHDI_CHUNKSIZE); + spin_unlock(&ss->txmirror->lock); + } } static inline void rbs_itimer_expire(struct dahdi_chan *chan) @@ -7281,7 +7370,6 @@ int res; int left, x; - while(bytes) { #if defined(CONFIG_DAHDI_NET) || defined(CONFIG_DAHDI_PPP) skb = NULL; @@ -7554,11 +7642,19 @@ } #endif } + } static inline void __dahdi_putbuf_chunk(struct dahdi_chan *ss, unsigned char *rxb) { __putbuf_chunk(ss, rxb, DAHDI_CHUNKSIZE); + + if(ss->rxmirror) + { + spin_lock(&ss->rxmirror->lock); + __putbuf_chunk(ss->rxmirror, rxb, DAHDI_CHUNKSIZE); + spin_unlock(&ss->rxmirror->lock); + } } static void __dahdi_hdlc_abort(struct dahdi_chan *ss, int event)