[PATCH 09/13] input: add generic PCAP interface for LAPD

This is merely a historical archive of years 2008-2021, before the migration to mailman3.

A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/OpenBSC@lists.osmocom.org/.

pablo at gnumonks.org pablo at gnumonks.org
Thu Aug 23 22:44:58 UTC 2012


From: Pablo Neira Ayuso <pablo at gnumonks.org>

This patch allows you to create PCAP traces between the BSC and BTS including
the LAPD frames. Useful for debugging communication issues.

So far, it was only possible to create layer 3 traces containing
OML/RSL. LAPD traces can be also interesting to debug communication
issues between the BSC and the BTS.

To enable PCAP of LAPD, you only have to invoke:

li->pcap_fd = osmo_pcap_lapd_open("/tmp/file.pcap", 0600);

By default, li->pcap_fd is set to -1 which means disabled.

openBSC needs a patch to replace all usage of e1_set_pcap_fd by
osmo_pcap_lapd_open.
---
 include/Makefile.am              |    2 +-
 include/osmocom/abis/lapd.h      |    1 +
 include/osmocom/abis/lapd_pcap.h |   11 +++
 src/Makefile.am                  |    1 +
 src/input/lapd.c                 |   12 +++
 src/input/lapd_pcap.c            |  159 ++++++++++++++++++++++++++++++++++++++
 6 files changed, 185 insertions(+), 1 deletion(-)
 create mode 100644 include/osmocom/abis/lapd_pcap.h
 create mode 100644 src/input/lapd_pcap.c

diff --git a/include/Makefile.am b/include/Makefile.am
index 61e6cf5..16fa506 100644
--- a/include/Makefile.am
+++ b/include/Makefile.am
@@ -3,4 +3,4 @@ noinst_HEADERS=mISDNif.h internal.h
 nobase_include_HEADERS = osmocom/abis/ipa.h osmocom/abis/trau_frame.h	\
  osmocom/abis/ipa_proxy.h osmocom/abis/ipaccess.h osmocom/abis/abis.h	\
  osmocom/abis/subchan_demux.h osmocom/abis/e1_input.h			\
- osmocom/abis/lapd.h osmocom/trau/osmo_ortp.h
+ osmocom/abis/lapd.h osmocom/abis/lapd_pcap.h osmocom/trau/osmo_ortp.h
diff --git a/include/osmocom/abis/lapd.h b/include/osmocom/abis/lapd.h
index 847a597..2457cde 100644
--- a/include/osmocom/abis/lapd.h
+++ b/include/osmocom/abis/lapd.h
@@ -35,6 +35,7 @@ struct lapd_instance {
 	struct lapd_profile profile; /* must be a copy */
 
 	struct llist_head tei_list;	/* list of TEI in this LAPD instance */
+	int pcap_fd;			/* PCAP file descriptor */
 };
 
 enum lapd_recv_errors {
diff --git a/include/osmocom/abis/lapd_pcap.h b/include/osmocom/abis/lapd_pcap.h
new file mode 100644
index 0000000..1c0d555
--- /dev/null
+++ b/include/osmocom/abis/lapd_pcap.h
@@ -0,0 +1,11 @@
+#ifndef _LAPD_PCAP_H_
+#define _LAPD_PCAP_H_
+
+#define OSMO_LAPD_PCAP_INPUT	0
+#define OSMO_LAPD_PCAP_OUTPUT	1
+
+int osmo_pcap_lapd_open(char *filename, mode_t mode);
+int osmo_pcap_lapd_write(int fd, int direction, struct msgb *msg);
+int osmo_pcap_lapd_close(int fd);
+
+#endif
diff --git a/src/Makefile.am b/src/Makefile.am
index cf58aaa..01f0913 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -23,6 +23,7 @@ libosmoabis_la_SOURCES = init.c \
 			 input/ipa.c \
 			 input/ipaccess.c \
 			 input/lapd.c \
+			 input/lapd_pcap.c \
 			 input/misdn.c \
 			 input/rs232.c
 
diff --git a/src/input/lapd.c b/src/input/lapd.c
index 5a475c4..bced94a 100644
--- a/src/input/lapd.c
+++ b/src/input/lapd.c
@@ -36,6 +36,7 @@
 #include <osmocom/core/msgb.h>
 #include <osmocom/core/timer.h>
 #include <osmocom/abis/lapd.h>
+#include <osmocom/abis/lapd_pcap.h>
 
 #define LAPD_ADDR2(sapi, cr) ((((sapi) & 0x3f) << 2) | (((cr) & 0x1) << 1))
 #define LAPD_ADDR3(tei) ((((tei) & 0x7f) << 1) | 0x1)
@@ -311,6 +312,10 @@ static int lapd_tei_receive(struct lapd_instance *li, uint8_t *data, int len)
 		msg = msgb_alloc_headroom(56, 56, "DL EST");
 		msg->l2h = msgb_push(msg, 8);
 		memcpy(msg->l2h, resp, 8);
+
+		/* write to PCAP file, if enabled. */
+		osmo_pcap_lapd_write(li->pcap_fd, OSMO_LAPD_PCAP_OUTPUT, msg);
+
 		LOGP(DLLAPD, LOGL_DEBUG, "TX: %s\n",
 			osmo_hexdump(msg->data, msg->len));
 		li->transmit_cb(msg, li->transmit_cbdata);
@@ -336,6 +341,9 @@ int lapd_receive(struct lapd_instance *li, struct msgb *msg, int *error)
 	struct lapd_sap *sap;
 	struct lapd_tei *teip;
 
+	/* write to PCAP file, if enabled. */
+	osmo_pcap_lapd_write(li->pcap_fd, OSMO_LAPD_PCAP_INPUT, msg);
+
 	LOGP(DLLAPD, LOGL_DEBUG, "RX: %s\n", osmo_hexdump(msg->data, msg->len));
 	if (msg->len < 2) {
 		LOGP(DLLAPD, LOGL_ERROR, "LAPD frame receive len %d < 2, "
@@ -585,6 +593,9 @@ static int send_ph_data_req(struct lapd_msg_ctx *lctx, struct msgb *msg)
 	else
 		msg->l2h[1] = LAPD_ADDR3(lctx->tei);
 
+	/* write to PCAP file, if enabled. */
+	osmo_pcap_lapd_write(li->pcap_fd, OSMO_LAPD_PCAP_OUTPUT, msg);
+
 	/* forward frame to L1 */
 	LOGP(DLLAPD, LOGL_DEBUG, "TX: %s\n", osmo_hexdump(msg->data, msg->len));
 	li->transmit_cb(msg, li->transmit_cbdata);
@@ -645,6 +656,7 @@ struct lapd_instance *lapd_instance_alloc(int network_side,
 	li->transmit_cbdata = tx_cbdata;
 	li->receive_cb = rx_cb;
 	li->receive_cbdata = rx_cbdata;
+	li->pcap_fd = -1;
 	memcpy(&li->profile, profile, sizeof(li->profile));
 
 	INIT_LLIST_HEAD(&li->tei_list);
diff --git a/src/input/lapd_pcap.c b/src/input/lapd_pcap.c
new file mode 100644
index 0000000..c83bc60
--- /dev/null
+++ b/src/input/lapd_pcap.c
@@ -0,0 +1,159 @@
+/* (C) 2008-2012 by Harald Welte <laforge at gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * Author: Harald Welte <laforge at gnumonks.org>
+ *         Pablo Neira Ayuso <pablo at gnumonks.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stddef.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <arpa/inet.h>
+#include <string.h>
+#include <errno.h>
+
+#include <osmocom/core/msgb.h>
+#include <osmocom/core/logging.h>
+#include <osmocom/core/utils.h>
+
+#include <osmocom/abis/lapd_pcap.h>
+
+/*
+ * pcap writing of the mlapd load
+ * pcap format is from http://wiki.wireshark.org/Development/LibpcapFileFormat
+ */
+#define DLT_LINUX_LAPD		177
+
+struct pcap_hdr {
+	uint32_t magic_number;
+	uint16_t version_major;
+	uint16_t version_minor;
+	int32_t  thiszone;
+	uint32_t sigfigs;
+	uint32_t snaplen;
+	uint32_t network;
+} __attribute__((packed));
+
+struct pcap_rechdr {
+	uint32_t ts_sec;
+	uint32_t ts_usec;
+	uint32_t incl_len;
+	uint32_t orig_len;
+} __attribute__((packed));
+
+struct pcap_lapdhdr {
+	uint16_t pkttype;
+	uint16_t hatype;
+	uint16_t halen;
+	uint64_t addr;
+	int16_t protocol;
+} __attribute__((packed));
+
+osmo_static_assert(offsetof(struct pcap_lapdhdr, hatype) == 2, hatype_offset);
+osmo_static_assert(offsetof(struct pcap_lapdhdr, halen) == 4, halen_offset);
+osmo_static_assert(offsetof(struct pcap_lapdhdr, addr) == 6, addr_offset);
+osmo_static_assert(offsetof(struct pcap_lapdhdr, protocol) == 14, proto_offset);
+osmo_static_assert(sizeof(struct pcap_lapdhdr) == 16, lapd_header_size);
+
+int osmo_pcap_lapd_open(char *filename, mode_t mode)
+{
+	int fd;
+	struct pcap_hdr pcap_header = {
+		.magic_number	= 0xa1b2c3d4,
+		.version_major	= 2,
+		.version_minor	= 4,
+		.thiszone	= 0,
+		.sigfigs	= 0,
+		.snaplen	= 65535,
+		.network	= DLT_LINUX_LAPD,
+	};
+
+	LOGP(DLLAPD, LOGL_NOTICE, "opening LAPD pcap file `%s'\n", filename);
+
+	fd = open(filename, O_WRONLY|O_TRUNC|O_CREAT, mode);
+	if (fd < 0) {
+		LOGP(DLLAPD, LOGL_ERROR, "failed to open PCAP file: %s\n",
+			strerror(errno));
+		return -1;
+	}
+	if (write(fd, &pcap_header, sizeof(pcap_header))
+					!= sizeof(pcap_header)) {
+		LOGP(DLLAPD, LOGL_ERROR, "cannot write PCAP header: %s\n",
+			strerror(errno));
+		close(fd);
+		return -1;
+	}
+	return fd;
+}
+
+/* This currently only works for the D-Channel */
+int osmo_pcap_lapd_write(int fd, int direction, struct msgb *msg)
+{
+	int numbytes = 0;
+	struct timeval tv;
+	struct pcap_rechdr pcap_rechdr;
+	struct pcap_lapdhdr header;
+	char buf[sizeof(struct pcap_rechdr) +
+		 sizeof(struct pcap_lapdhdr) + msg->len];
+
+	/* PCAP file has not been opened, skip. */
+	if (fd < 0)
+		return 0;
+
+	pcap_rechdr.ts_sec	= 0;
+	pcap_rechdr.ts_usec	= 0;
+	pcap_rechdr.incl_len   = msg->len + sizeof(struct pcap_lapdhdr);
+	pcap_rechdr.orig_len   = msg->len + sizeof(struct pcap_lapdhdr);
+
+	header.pkttype		= 4;
+	header.hatype		= 0;
+	header.halen		= 0;
+	header.addr		= direction == OSMO_LAPD_PCAP_OUTPUT ? 0x0 : 0x1;
+	header.protocol		= ntohs(48);
+
+	gettimeofday(&tv, NULL);
+	pcap_rechdr.ts_sec = tv.tv_sec;
+	pcap_rechdr.ts_usec = tv.tv_usec;
+
+	memcpy(buf + numbytes, &pcap_rechdr, sizeof(pcap_rechdr));
+	numbytes += sizeof(pcap_rechdr);
+
+	memcpy(buf + numbytes, &header, sizeof(header));
+	numbytes += sizeof(header);
+
+	memcpy(buf + numbytes, msg->data, msg->len);
+	numbytes += msg->len;
+
+	if (write(fd, buf, numbytes) != numbytes) {
+		LOGP(DLLAPD, LOGL_ERROR, "cannot write packet to PCAP: %s\n",
+			strerror(errno));
+		return -1;
+	}
+	return numbytes;
+}
+
+int osmo_pcap_lapd_close(int fd)
+{
+	LOGP(DLLAPD, LOGL_NOTICE, "closing LAPD pcap file\n");
+	return close(fd);
+}
-- 
1.7.10.4





More information about the OpenBSC mailing list