Ethereal-dev: [Ethereal-dev] Patch to support vISDN

Note: This archive is from the project's previous web site, ethereal.com. This list is no longer active.

From: Daniele Orlandi <daniele@xxxxxxxxxxx>
Date: Mon, 20 Feb 2006 13:58:08 +0100
Hello,

The attached patch adds support for LAPD frames captured using vISDN thru 
libpcap. The support has already been included in libpcap.

The patch adds a new wiretap encapsulation, the necessary glue to decode 
SLL-encapsulated frames, and some minor change in the LAPD dissector in order 
to support the remote-to-remote frames captured on the ISDN E-Channel.

Please apply ethereal-encap-table.diff before, as it fixes a misalignment in 
the encapsulation names table.

Let me know if the patch needs some adjustment.

Thank you,
Bye,

-- 
  Daniele Orlandi
diff -ur ethereal/wiretap/wtap.c ethereal-encap-table/wiretap/wtap.c
--- ethereal/wiretap/wtap.c	2006-02-20 11:58:18.000000000 +0100
+++ ethereal-encap-table/wiretap/wtap.c	2006-02-20 12:40:33.000000000 +0100
@@ -286,6 +286,9 @@
 	/* WTAP_ENCAP_NETTL_RAW_ICMPV6 */
 	{ "Raw ICMPv6 with nettl headers", "raw-icmpv6-nettl" },
 
+	/* UNUSED */
+	{ "", "" },
+
 	/* WTAP_ENCAP_GPRS_LLC */
 	{ "GPRS LLC", "gprs-llc" },
 
@@ -328,6 +331,9 @@
 	/* WTAP_ENCAP_NETTL_X25 */
 	{ "X25 with nettl headers", "x25-nettl" },
 
+	/* WTAP_ENCAP_K12 */
+	{ "K12 protocol analyzer", "k12" },
+
 	/* WTAP_ENCAP_JUNIPER_MLPPP */
 	{ "Juniper MLPPP", "juniper-mlppp" },
 
diff -ur ethereal-encap-table/capture-wpcap.c ethereal-visdn/capture-wpcap.c
--- ethereal-encap-table/capture-wpcap.c	2006-02-20 11:58:22.000000000 +0100
+++ ethereal-visdn/capture-wpcap.c	2006-02-20 12:03:29.000000000 +0100
@@ -359,6 +359,9 @@
 #ifdef DLT_LINUX_IRDA
 	DLT_CHOICE(DLT_LINUX_IRDA, "Linux IrDA"),
 #endif
+#ifdef DLT_LINUX_LAPD
+	DLT_CHOICE(DLT_LINUX_LAPD, "Linux vISDN LAPD"),
+#endif
 #ifdef DLT_LANE8023
 	DLT_CHOICE(DLT_LANE8023, "Linux 802.3 LANE"),
 #endif
diff -ur ethereal-encap-table/epan/column.c ethereal-visdn/epan/column.c
--- ethereal-encap-table/epan/column.c	2006-02-20 11:57:58.000000000 +0100
+++ ethereal-visdn/epan/column.c	2006-02-20 12:07:17.000000000 +0100
@@ -50,7 +50,7 @@
 	"%rd", "%ud", "%hd", "%rhd", "%uhd", "%nd", "%rnd",
 	"%und", "%S", "%rS", "%uS", "%D", "%rD", "%uD", "%p",
 	"%i", "%L", "%B", "%XO", "%XR", "%I", "%c", "%Xs", 
-	"%Xd", "%V", "%x", "%e", "%H", "%P", "%y", "%v"
+	"%Xd", "%V", "%x", "%e", "%H", "%P", "%y", "%v", "%E"
 };
                      
   if (fmt < 0 || fmt >= NUM_COL_FMTS)
@@ -109,6 +109,7 @@
 	"HP-UX Device ID",
 	"DCE/RPC call (cn_call_id / dg_seqnum)",
        "802.1Q VLAN id",
+	"TEI",
 };
 
 const gchar *
@@ -209,6 +210,9 @@
     case COL_8021Q_VLAN_ID:
       fmt_list[COL_8021Q_VLAN_ID] = TRUE;
       break;
+    case COL_TEI:
+      fmt_list[COL_TEI] = TRUE;
+      break;
     default:
       break;
   }
@@ -429,6 +433,9 @@
     case COL_8021Q_VLAN_ID:
       return "0000";
       break;
+    case COL_TEI:
+      return "127";
+      break;
     default: /* COL_INFO */
       return "Source port: kerberos-master  Destination port: kerberos-master";
       break;
@@ -578,6 +585,9 @@
       case 'v':
 	return COL_8021Q_VLAN_ID;
 	break;
+      case 'E':
+	return COL_TEI;
+	break;
     }
     cptr++;
   }
diff -ur ethereal-encap-table/epan/column_info.h ethereal-visdn/epan/column_info.h
--- ethereal-encap-table/epan/column_info.h	2006-02-20 11:57:59.000000000 +0100
+++ ethereal-visdn/epan/column_info.h	2006-02-20 12:08:13.000000000 +0100
@@ -99,6 +99,7 @@
   COL_HPUX_DEVID,     /* HP-UX Nettl Device ID */
   COL_DCE_CALL,       /* DCE/RPC call id OR datagram sequence number */
   COL_8021Q_VLAN_ID,  /* 802.1Q vlan ID */
+  COL_TEI,            /* q.921 TEI */
   NUM_COL_FMTS        /* Should always be last */
 };
 
diff -ur ethereal-encap-table/epan/dissectors/packet-frame.c ethereal-visdn/epan/dissectors/packet-frame.c
--- ethereal-encap-table/epan/dissectors/packet-frame.c	2006-02-20 11:57:56.000000000 +0100
+++ ethereal-visdn/epan/dissectors/packet-frame.c	2006-02-20 12:03:29.000000000 +0100
@@ -141,6 +141,13 @@
 			pinfo->p2p_dir = pinfo->pseudo_header->isdn.uton ?
 			    P2P_DIR_SENT : P2P_DIR_RECV;
 			break;
+
+		case WTAP_ENCAP_LINUX_LAPD:
+			pinfo->p2p_dir = (pinfo->pseudo_header->lapd.pkttype == 3 ||
+				pinfo->pseudo_header->lapd.pkttype == 4) ?
+				P2P_DIR_SENT : P2P_DIR_RECV;
+			break;
+
 		case WTAP_ENCAP_MTP2_WITH_PHDR:
 			pinfo->p2p_dir = pinfo->pseudo_header->mtp2.sent ?
 			    P2P_DIR_SENT : P2P_DIR_RECV;
Only in ethereal-visdn/epan/dissectors: packet-frame.c.orig
diff -ur ethereal-encap-table/epan/dissectors/packet-lapd.c ethereal-visdn/epan/dissectors/packet-lapd.c
--- ethereal-encap-table/epan/dissectors/packet-lapd.c	2006-02-20 11:57:56.000000000 +0100
+++ ethereal-visdn/epan/dissectors/packet-lapd.c	2006-02-20 12:03:29.000000000 +0100
@@ -80,6 +80,7 @@
 #define	LAPD_CR		0x0200	/* Command/Response bit */
 #define	LAPD_EA1	0x0100	/* First Address Extension bit */
 #define	LAPD_TEI	0x00fe	/* Terminal Endpoint Identifier */
+#define LAPD_TEI_SHIFT	1
 #define	LAPD_EA2	0x0001	/* Second Address Extension bit */
 
 static const value_string lapd_sapi_vals[] = {
@@ -123,9 +124,11 @@
 	proto_item	*lapd_ti, *addr_ti;
 	guint16		control;
 	int		lapd_header_len;
-	guint16		address, cr, sapi;
-	gboolean	is_response;
+	guint16		address, cr, sapi, tei;
+	gboolean	is_response = 0;
 	tvbuff_t	*next_tvb;
+	char		*srcname = "?";
+	char		*dstname = "?";
 
 	if (check_col(pinfo->cinfo, COL_PROTOCOL))
 		col_set_str(pinfo->cinfo, COL_PROTOCOL, "LAPD");
@@ -134,25 +137,61 @@
 
 	address = tvb_get_ntohs(tvb, 0);
 	cr = address & LAPD_CR;
+	tei = (address & LAPD_TEI) >> LAPD_TEI_SHIFT;
 	sapi = (address & LAPD_SAPI) >> LAPD_SAPI_SHIFT;
 	lapd_header_len = 2;	/* address */
 
-	if (pinfo->p2p_dir == P2P_DIR_SENT) {
-		is_response = cr ? TRUE : FALSE;
-		if(check_col(pinfo->cinfo, COL_RES_DL_DST))
-			col_set_str(pinfo->cinfo, COL_RES_DL_DST, "Network");
-		if(check_col(pinfo->cinfo, COL_RES_DL_SRC))
-			col_set_str(pinfo->cinfo, COL_RES_DL_SRC, "User");
+	if (check_col(pinfo->cinfo, COL_TEI))
+		col_add_fstr(pinfo->cinfo, COL_TEI, "%u", tei);
+
+	if (pinfo->fd->lnk_t == WTAP_ENCAP_LINUX_LAPD) {
+		/* frame is captured via libpcap */
+		if (pinfo->pseudo_header->lapd.pkttype == 4 /*PACKET_OUTGOING*/) {
+			if (pinfo->pseudo_header->lapd.we_network) {
+				is_response = cr ? FALSE : TRUE;
+				srcname = "Local Network";
+				dstname = "Remote User";
+			} else {
+				srcname = "Local User";
+				dstname = "Remote Network";
+			}
+		}
+		else if (pinfo->pseudo_header->lapd.pkttype == 3 /*PACKET_OTHERHOST*/) {
+			// We must be a TE, sniffing what other TE transmit
+
+			is_response = cr ? TRUE : FALSE;
+			srcname = "Remote User";
+			dstname = "Remote Network";
+		}
+		else {
+			// The frame is incoming
+			if (pinfo->pseudo_header->lapd.we_network) {
+				is_response = cr ? TRUE : FALSE;
+				srcname = "Remote User";
+				dstname = "Local Network";
+			} else {
+				is_response = cr ? FALSE : TRUE;
+				srcname = "Remote Network";
+				dstname = "Local User";
+			}
+		}
 	}
-	else {
-		/* XXX - what if the direction is unknown? */
+	else if (pinfo->p2p_dir == P2P_DIR_SENT) {
 		is_response = cr ? FALSE : TRUE;
-		if(check_col(pinfo->cinfo, COL_RES_DL_DST))
-		    col_set_str(pinfo->cinfo, COL_RES_DL_DST, "User");
-		if(check_col(pinfo->cinfo, COL_RES_DL_SRC))
-		    col_set_str(pinfo->cinfo, COL_RES_DL_SRC, "Network");
+		srcname = "Network";
+		dstname = "User";
+	}
+	else if (pinfo->p2p_dir == P2P_DIR_RECV) {
+		is_response = cr ? TRUE : FALSE;
+		srcname = "User";
+		dstname = "Network";
 	}
 
+	if(check_col(pinfo->cinfo, COL_RES_DL_SRC))
+	    col_set_str(pinfo->cinfo, COL_RES_DL_SRC, srcname);
+	if(check_col(pinfo->cinfo, COL_RES_DL_DST))
+	    col_set_str(pinfo->cinfo, COL_RES_DL_DST, dstname);
+
 	if (tree) {
 		lapd_ti = proto_tree_add_item(tree, proto_lapd, tvb, 0, -1,
 		    FALSE);
@@ -293,4 +332,9 @@
 {
 	data_handle = find_dissector("data");
 	tei_handle = find_dissector("tei");
+
+	dissector_handle_t lapd_handle;
+
+	lapd_handle = create_dissector_handle(dissect_lapd, proto_lapd);
+	dissector_add("wtap_encap", WTAP_ENCAP_LINUX_LAPD, lapd_handle);
 }
diff -ur ethereal-encap-table/wiretap/libpcap.c ethereal-visdn/wiretap/libpcap.c
--- ethereal-encap-table/wiretap/libpcap.c	2006-02-20 11:58:18.000000000 +0100
+++ ethereal-visdn/wiretap/libpcap.c	2006-02-20 12:38:41.000000000 +0100
@@ -81,6 +81,21 @@
 	guint16 link_number;
 };
 
+#ifndef ETH_P_LAPD
+#define ETH_P_LAPD 0x0030
+#endif
+
+/*
+ * The fake link-layer header of LAPD packets 
+ */
+struct lapd_sll_hdr {
+    guint16 sll_pkttype;    /* packet type */
+    guint16 sll_hatype;
+    guint16 sll_halen;
+    guint8 sll_addr[8];
+    guint16 sll_protocol;   /* protocol, should be ETH_P_LAPD */
+};
+
 /* See source to the "libpcap" library for information on the "libpcap"
    file format. */
 
@@ -119,6 +134,10 @@
     union wtap_pseudo_header *pseudo_header);
 static gboolean libpcap_read_mtp2_pseudoheader(FILE_T fh,
     union wtap_pseudo_header *pseudo_header, int *err, gchar **err_info);
+static gboolean libpcap_get_lapd_pseudoheader(const struct lapd_sll_hdr *lapd_phdr,
+    union wtap_pseudo_header *pseudo_header, int *err, gchar **err_info);
+static gboolean libpcap_read_lapd_pseudoheader(FILE_T fh,
+    union wtap_pseudo_header *pseudo_header, int *err, gchar **err_info);
 static gboolean libpcap_read_rec_data(FILE_T fh, guchar *pd, int length,
     int *err);
 static void libpcap_close(wtap *wth);
@@ -379,6 +398,8 @@
 	{ 172,		WTAP_GCOM_TIE1 },
 	{ 173,		WTAP_GCOM_SERIAL },
 
+	{ 177,		WTAP_ENCAP_LINUX_LAPD },
+
         /* Ethernet frames prepended with meta-information */
         { 178,          WTAP_ENCAP_JUNIPER_ETHER },
         /* PPP frames prepended with meta-information */
@@ -1296,6 +1317,29 @@
 		packet_size -= sizeof (struct mtp2_hdr);
 		wth->data_offset += sizeof (struct mtp2_hdr);
 		break;
+
+	case WTAP_ENCAP_LINUX_LAPD:
+		if (packet_size < sizeof (struct lapd_sll_hdr)) {
+			/*
+			 * Uh-oh, the packet isn't big enough to even
+			 * have a pseudo-header.
+			 */
+			*err = WTAP_ERR_BAD_RECORD;
+			*err_info = g_strdup_printf("libpcap: LAPD file has a %u-byte packet, too small to have even a LAPD pseudo-header\n",
+			    packet_size);
+			return FALSE;
+		}
+		if (!libpcap_read_lapd_pseudoheader(wth->fh, &wth->pseudo_header,
+		    err, err_info))
+			return FALSE;	/* Read error */
+
+		/*
+		 * Don't count the pseudo-header as part of the packet.
+		 */
+		orig_size -= sizeof (struct lapd_sll_hdr);
+		packet_size -= sizeof (struct lapd_sll_hdr);
+		wth->data_offset += sizeof (struct lapd_sll_hdr);
+		break;
 	}
 
 	buffer_assure_space(wth->frame_buffer, packet_size);
@@ -1406,6 +1450,14 @@
 			return FALSE;
 		}
 		break;
+
+	case WTAP_ENCAP_LINUX_LAPD:
+		if (!libpcap_read_lapd_pseudoheader(wth->random_fh, pseudo_header,
+		    err, err_info)) {
+			/* Read error */
+			return FALSE;
+		}
+		break;
 	}
 
 	/*
@@ -1760,6 +1812,43 @@
 }
 
 static gboolean
+libpcap_get_lapd_pseudoheader(const struct lapd_sll_hdr *lapd_phdr,
+    union wtap_pseudo_header *pseudo_header, int *err, gchar **err_info)
+{
+	if (pntohs(&lapd_phdr->sll_protocol) != ETH_P_LAPD) {
+		*err = WTAP_ERR_BAD_RECORD;
+		if (err_info != NULL)
+			*err_info = g_strdup("libpcap: LAPD capture has a packet with an invalid sll_protocol field\n");
+		return FALSE;
+	}
+
+	pseudo_header->lapd.pkttype = pntohs(&lapd_phdr->sll_pkttype);
+	pseudo_header->lapd.we_network = !!lapd_phdr->sll_addr[0];
+
+	return TRUE;
+}
+
+static gboolean
+libpcap_read_lapd_pseudoheader(FILE_T fh, union wtap_pseudo_header *pseudo_header,
+    int *err, gchar **err_info)
+{
+	struct lapd_sll_hdr lapd_phdr;
+	int	bytes_read;
+
+	errno = WTAP_ERR_CANT_READ;
+	bytes_read = file_read(&lapd_phdr, 1, sizeof (struct lapd_sll_hdr), fh);
+	if (bytes_read != sizeof (struct lapd_sll_hdr)) {
+		*err = file_error(fh);
+		if (*err == 0)
+			*err = WTAP_ERR_SHORT_READ;
+		return FALSE;
+	}
+
+	return libpcap_get_lapd_pseudoheader(&lapd_phdr, pseudo_header, err,
+	    err_info);
+}
+
+static gboolean
 libpcap_read_rec_data(FILE_T fh, guchar *pd, int length, int *err)
 {
 	int	bytes_read;
@@ -1944,6 +2033,28 @@
 		whdr->caplen -= sizeof (struct mtp2_hdr);
 		pd += sizeof (struct mtp2_hdr);
 	}
+	else if (linktype == WTAP_ENCAP_LINUX_LAPD) {
+		if (whdr->caplen < sizeof (struct lapd_sll_hdr)) {
+			/*
+			 * Uh-oh, the packet isn't big enough to even
+			 * have a pseudo-header.
+			 */
+			g_message("libpcap: LAPD capture has a %u-byte packet, too small to have even an LAPD pseudo-header\n",
+			    whdr->caplen);
+			*err = WTAP_ERR_BAD_RECORD;
+			return NULL;
+		}
+		if (!libpcap_get_lapd_pseudoheader((const struct lapd_sll_hdr *)pd,
+			pseudo_header, err, NULL))
+			return NULL;
+
+		/*
+		 * Don't count the pseudo-header as part of the packet.
+		 */
+		whdr->len -= sizeof (struct lapd_sll_hdr);
+		whdr->caplen -= sizeof (struct lapd_sll_hdr);
+		pd += sizeof (struct lapd_sll_hdr);
+	}
 	return pd;
 }
 #endif
@@ -2056,6 +2167,7 @@
 	size_t nwritten;
 	struct sunatm_hdr atm_hdr;
 	struct irda_sll_hdr irda_hdr;
+	struct lapd_sll_hdr lapd_hdr;
 	struct mtp2_hdr mtp2_hdr;
 	int hdrsize;
 
@@ -2063,6 +2175,8 @@
 		hdrsize = sizeof (struct sunatm_hdr);
 	else if (wdh->encap == WTAP_ENCAP_IRDA)
 		hdrsize = sizeof (struct irda_sll_hdr);
+	else if (wdh->encap == WTAP_ENCAP_LINUX_LAPD)
+		hdrsize = sizeof (struct lapd_sll_hdr);
 	else
 		hdrsize = 0;
 
@@ -2224,6 +2338,24 @@
 		}
 		wdh->bytes_dumped += sizeof(mtp2_hdr);
 	}
+	else if (wdh->encap == WTAP_ENCAP_LINUX_LAPD) {
+		/*
+		 * Write the LAPD header.
+		 */
+		memset(&lapd_hdr, 0, sizeof(lapd_hdr));
+		lapd_hdr.sll_pkttype  = phtons(&pseudo_header->lapd.pkttype);
+		lapd_hdr.sll_protocol = g_htons(ETH_P_LAPD);
+		lapd_hdr.sll_addr[0] = pseudo_header->lapd.we_network?0x01:0x00;
+		nwritten = fwrite(&lapd_hdr, 1, sizeof(lapd_hdr), wdh->fh);
+		if (nwritten != sizeof(lapd_hdr)) {
+			if (nwritten == 0 && ferror(wdh->fh))
+				*err = errno;
+			else
+				*err = WTAP_ERR_SHORT_WRITE;
+			return FALSE;
+		}
+		wdh->bytes_dumped += sizeof(lapd_hdr);
+	}
 
 	nwritten = wtap_dump_file_write(wdh, pd, phdr->caplen);
 	if (nwritten != phdr->caplen) {
diff -ur ethereal-encap-table/wiretap/wtap.c ethereal-visdn/wiretap/wtap.c
--- ethereal-encap-table/wiretap/wtap.c	2006-02-20 12:40:33.000000000 +0100
+++ ethereal-visdn/wiretap/wtap.c	2006-02-20 12:03:29.000000000 +0100
@@ -351,6 +351,9 @@
 
 	/* WTAP_ENCAP_JUNIPER_CHDLC */
 	{ "Juniper C-HDLC", "juniper-chdlc" },
+
+ 	/* WTAP_ENCAP_LINUX_LAPD */
+ 	{ "LAPD", "lapd" },
 };
 
 /* Name that should be somewhat descriptive. */
diff -ur ethereal-encap-table/wiretap/wtap.h ethereal-visdn/wiretap/wtap.h
--- ethereal-encap-table/wiretap/wtap.h	2006-02-20 11:58:18.000000000 +0100
+++ ethereal-visdn/wiretap/wtap.h	2006-02-20 12:04:31.000000000 +0100
@@ -178,9 +178,10 @@
 #define WTAP_ENCAP_JUNIPER_FRELAY               86
 #define WTAP_ENCAP_JUNIPER_CHDLC                87
 #define WTAP_ENCAP_JUNIPER_GGSN                 88
+#define WTAP_ENCAP_LINUX_LAPD			89
 
 /* last WTAP_ENCAP_ value + 1 */
-#define WTAP_NUM_ENCAP_TYPES			89
+#define WTAP_NUM_ENCAP_TYPES			90
 
 /* File types that can be read by wiretap.
    We support writing some many of these file types, too, so we
@@ -496,6 +497,11 @@
 #define K12_PORT_DS1       0x00100008
 #define K12_PORT_ATMPVC    0x01020000
 
+struct lapd_phdr {
+	guint16 pkttype;    /* packet type */
+	guint8 we_network;
+};
+
 union wtap_pseudo_header {
 	struct eth_phdr		eth;
 	struct x25_phdr		x25;
@@ -509,6 +515,7 @@
 	struct nettl_phdr	nettl;
 	struct mtp2_phdr        mtp2;
 	struct k12_phdr		k12;
+	struct lapd_phdr	lapd;
 };
 
 struct wtap_nstime {