Hi,

I don't know if something similar exists already but I've created a
patch to add the ability to do pcap capturing on dahdi cards. So I'm
posting it here just in case it might be useful to someone. It
consists of 2 parts

1. changes to the dahdi driver to add ioctls to mirror reads/writes
from a signaling channel to a pseudo channel
2. a corresponding user app to set up the mirroring and record the
traffic in a pcap

This seems to work though I'm not sure if it's the best solution design-wise.
I might be abusing the pseudo channel concept and wanted to ask if you ever
felt the need for similar functionality.



to compile the app do the following
gcc dahdi_pcap.c -o dahdi_pcap -lpcap

and the syntax to run it is
./dahdi_pcap chan1  [chan2]* pcap.pcap

e.g.
./dahdi_pcap 16 47 test.pcap


Regards,
Torrey
#include <stdio.h>
#include <fcntl.h>
#include <dahdi/user.h>
#include <sys/time.h>
#include <time.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <pcap.h>
#include <sys/types.h>
#include <arpa/inet.h>


#define BLOCK_SIZE 512

struct mtp2_phdr {
        u_int8_t  sent;
        u_int8_t  annex_a_used;
        u_int16_t link_number;
};


struct chan_fds {
	int rfd;
	int tfd;
	int chan_id;
};

int make_mirror(long type, int chan)
{
	int res = 0;
	int fd = 0;	
	int x = BLOCK_SIZE;
	struct dahdi_bufferinfo bi;
	fd = open("/dev/dahdi/pseudo", O_RDONLY);

	memset(&bi, 0, sizeof(bi));
        bi.txbufpolicy = DAHDI_POLICY_IMMEDIATE;
        bi.rxbufpolicy = DAHDI_POLICY_IMMEDIATE;
        bi.numbufs = 32;
        bi.bufsize = BLOCK_SIZE;

	ioctl(fd, DAHDI_SET_BUFINFO, &bi);

	res = ioctl(fd, type, &chan);
	if(res)
	{
		printf("error setting channel err=%d!\n", res);
		return -1;
	}
	
	return fd;
}

void log_packet(struct chan_fds * fd, char is_read, pcap_dumper_t * dump)
{
	char buf[BLOCK_SIZE * 4];
	int res = 0;

	struct pcap_pkthdr hdr;
	struct mtp2_phdr * mtp2 = (struct mtp2_phdr *)buf;
	memset(buf, 0, sizeof(buf));
	if(is_read)
	{
		res = read(fd->rfd, buf+sizeof(struct mtp2_phdr), sizeof(buf)-sizeof(struct mtp2_phdr));
	}
	else
	{
		res = read(fd->tfd, buf+sizeof(struct mtp2_phdr), sizeof(buf)-sizeof(struct mtp2_phdr));
	}

	gettimeofday(&hdr.ts, NULL);

	

	
	if(res > 0)
	{
		hdr.caplen = res+sizeof(struct mtp2_phdr);
		hdr.len = res+sizeof(struct mtp2_phdr);
		
		int i = 0;
		if(is_read)
		{
			mtp2->sent = 0;
        		mtp2->annex_a_used = 0;
		}
		else
		{
			mtp2->sent = 1;
        		mtp2->annex_a_used = 0;
		}
        	mtp2->link_number = htons(fd->chan_id);
		pcap_dump((u_char*)dump, &hdr, buf);
		pcap_dump_flush(dump);
	}
}

int main(int argc, char *argv[])
{
	struct chan_fds chans[10];
	int num_chans = argc - 2;
	int max_fd = 0;

	int i;	
	for(i = 0; i < num_chans; i++)
	{
		int chan = atoi(argv[i+1]);

		chans[i].tfd = make_mirror(DAHDI_TXMIRROR, chan);
		chans[i].rfd = make_mirror(DAHDI_RXMIRROR, chan);
		chans[i].chan_id = chan;
		if(chans[i].tfd > max_fd)
		{
			max_fd = chans[i].tfd;
		}
		if(chans[i].rfd > max_fd)
		{
			max_fd = chans[i].rfd;
		}
	}
	max_fd++;
	

	pcap_t * pcap = pcap_open_dead(DLT_MTP2_WITH_PHDR, BLOCK_SIZE*4);
	pcap_dumper_t * dump = pcap_dump_open(pcap, argv[argc - 1]);
	while(1)
	{
		fd_set rd_set;
		FD_ZERO(&rd_set);
		for(i = 0; i < num_chans; i++)
		{
			FD_SET(chans[i].tfd, &rd_set);
			FD_SET(chans[i].rfd, &rd_set);
		}

		select(max_fd, &rd_set, NULL, NULL, NULL);

		for(i = 0; i < num_chans; i++)
		{
			if(FD_ISSET(chans[i].rfd, &rd_set))
			{
				log_packet(&chans[i], 1, dump);
			}
			if(FD_ISSET(chans[i].tfd, &rd_set))
			{
				log_packet(&chans[i], 0, dump);
			}
		}
	}

	return 0;
}
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,56 @@
 	if (!chan)
 		return -EINVAL;
 	switch(cmd) {
+	
+	case DAHDI_RXMIRROR:
+		get_user(i,  (int*)data);
+		if(i > 0 && i < DAHDI_MAX_CHANNELS)
+		{
+			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);
+		}
+		break;
+	case DAHDI_TXMIRROR:
+		get_user(i,  (int*)data);
+		if(i > 0 && i < DAHDI_MAX_CHANNELS)
+		{
+			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);
+		}
+		break;
 	case DAHDI_DIALING:
 		spin_lock_irqsave(&chan->lock, flags);
 		j = chan->dialing;
@@ -6229,8 +6298,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 +6466,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 +7362,6 @@
 	int res;
 	int left, x;
 
-
 	while(bytes) {
 #if defined(CONFIG_DAHDI_NET)  || defined(CONFIG_DAHDI_PPP)
 		skb = NULL;
@@ -7554,11 +7634,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)
-- 
_____________________________________________________________________
-- Bandwidth and Colocation Provided by http://www.api-digital.com --

asterisk-ss7 mailing list
To UNSUBSCRIBE or update options visit:
   http://lists.digium.com/mailman/listinfo/asterisk-ss7

Reply via email to