diff --git a/tests/Makefile.am b/tests/Makefile.am
index af8a9cf..c8b8996 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -5,7 +5,8 @@ AM_LDFLAGS = $(COVERAGE_LDFLAGS)
 check_PROGRAMS = e1inp_ipa_bsc_test	\
 		  e1inp_ipa_bts_test	\
 		  ipa_proxy_test	\
-		  subchan_demux/subchan_demux_test
+		  subchan_demux/subchan_demux_test \
+		  ipa_recv/ipa_recv_test
 
 e1inp_ipa_bsc_test_SOURCES = e1inp_ipa_bsc_test.c
 e1inp_ipa_bsc_test_LDADD = $(top_builddir)/src/libosmoabis.la \
@@ -25,6 +26,11 @@ subchan_demux_subchan_demux_test_LDADD = $(top_builddir)/src/libosmoabis.la \
 			$(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) \
 			$(LIBOSMOVTY_LIBS)
 
+ipa_recv_ipa_recv_test_SOURCES = ipa_recv/ipa_recv_test.c
+ipa_recv_ipa_recv_test_LDADD = $(top_builddir)/src/libosmoabis.la \
+			$(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) \
+			$(LIBOSMOVTY_LIBS)
+
 # boilerplate for the tests
 # The `:;' works around a Bash 3.2 bug when the output is not writeable.
 $(srcdir)/package.m4: $(top_srcdir)/configure.ac
@@ -45,7 +51,8 @@ $(srcdir)/package.m4: $(top_srcdir)/configure.ac
              } >'$(srcdir)/package.m4'
 
 EXTRA_DIST = testsuite.at $(srcdir)/package.m4 $(TESTSUITE) \
-	subchan_demux/subchan_demux_test.ok
+	subchan_demux/subchan_demux_test.ok \
+	ipa_recv/ipa_recv_test.ok
 
 TESTSUITE = $(srcdir)/testsuite
 
diff --git a/tests/ipa_recv/ipa_recv_test.c b/tests/ipa_recv/ipa_recv_test.c
new file mode 100644
index 0000000..7b26259
--- /dev/null
+++ b/tests/ipa_recv/ipa_recv_test.c
@@ -0,0 +1,247 @@
+/* IPA receive test */
+
+/* (C) 2014 by On-Waves
+ *
+ * All Rights Reserved
+ *
+ * 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 <osmocom/abis/e1_input.h>
+
+#include <osmocom/abis/ipa.h>
+#include <osmocom/core/utils.h>
+#include <osmocom/core/msgb.h>
+#include <osmocom/core/logging.h>
+#include <osmocom/core/application.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <err.h>
+
+#if 0
+/* IPA protocol ip.access, type: RSL */
+static const unsigned char gsm_ipa_chanrqd[13] = {
+	0x00, 0x0a, 0x00, 0x0c, 0x13, 0x01, 0x88, 0x13,
+	0x4e, 0x42, 0x93, 0x11, 0x00
+};
+
+/* IPA protocol ip.access, type: RSL */
+static const unsigned char gsm_ipa_chanactivack[10] = {
+	0x00, 0x07, 0x00, 0x08, 0x22, 0x01, 0x12, 0x08,
+	0x43, 0x81
+};
+
+/* IPA protocol ip.access, type: RSL */
+static const unsigned char gsm_ipa_data[40] = {
+	0x00, 0x25, 0x00, 0x08, 0x28, 0x01, 0x12, 0x1b,
+	0x00, 0x19, 0x03, 0x3b, 0x3b, 0x00, 0x04, 0x00,
+	0x0a, 0x38, 0x00, 0x0b, 0x00, 0x12, 0x06, 0x15,
+	0x35, 0x40, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+#endif
+
+static const char *ipa_test_messages[] = {
+	"Hello IPA",
+	"A longer test message. ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz",
+	"Hello again IPA",
+	"",
+	"Next is empty",
+	NULL,
+	"Bye",
+	"Bye",
+};
+
+static void append_ipa_message(struct msgb *msg, int proto, const char *text)
+{
+	int len = 0;
+	unsigned char *l2;
+
+	if (text)
+		len = strlen(text) + 1;
+
+	msgb_put_u16(msg, len);
+	msgb_put_u8(msg, proto);
+
+	l2 = msgb_put(msg, len);
+	if (text)
+		strcpy((char *)l2, text);
+}
+
+static int receive_messages(int fd)
+{
+	struct msgb *msg;
+	char dummy;
+	int rc;
+	while (1) {
+		if (recv(fd, &dummy, 1, MSG_PEEK) < 1) {
+			rc = -EAGAIN;
+			break;
+		}
+		msg = NULL;
+		rc = ipa_msg_recv(fd, &msg);
+		if (rc == -1)
+			rc = -errno;
+		fprintf(stderr,
+			"ipa_msg_recv: %d, msg %s NULL\n",
+			rc, msg ? "!=" : "==");
+		if (rc == -EAGAIN)
+			printf( "got msg %s NULL, "
+				"returned: %s\n",
+				msg ?  "!=" : "==",
+				rc == 0 ? "EOF" :
+				rc > 0 ? "OK" :
+				strerror(-rc));
+		if (rc == 0)
+			return 0;
+		if (rc == -EAGAIN)
+			break;
+		if (rc < 0) {
+			printf("ipa_msg_recv failed with: %s\n", strerror(-rc));
+			return rc;
+		}
+		printf("got IPA message, size=%d, proto=%d, text=\"%s\"\n",
+		       rc, msg->data[2], msg->l2h);
+		msgb_free(msg);
+	};
+
+	return rc;
+}
+
+static int slurp_data(int fd) {
+	int rc;
+	char buf[256];
+	int count = 0;
+
+	do {
+		rc = recv(fd, buf, sizeof(buf), 0);
+		if (rc <= 0)
+			break;
+
+		count += rc;
+	} while (1);
+
+	return count;
+};
+
+static void test_complete_recv(void)
+{
+	int sv[2];
+	struct msgb *msg_out = msgb_alloc(4096, "msg_out");
+	int rc, i;
+
+	printf("Testing IPA recv with complete messages.\n");
+
+	if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == -1)
+		err(1, "socketpair");
+
+	fcntl(sv[0], F_SETFL, O_NONBLOCK);
+
+	for (i=0; i < ARRAY_SIZE(ipa_test_messages); i++)
+		append_ipa_message(msg_out, 200, ipa_test_messages[i]);
+
+	while (msg_out->len > 0) {
+		rc = write(sv[1], msg_out->data, msg_out->len);
+		if (rc == -1)
+			err(1, "write");
+		msgb_pull(msg_out, rc);
+	}
+
+	for (i=0; i < ARRAY_SIZE(ipa_test_messages); i++) {
+		rc = receive_messages(sv[0]);
+		if (rc == 0)
+			break;
+
+		if (rc < 0 && rc != -EAGAIN)
+			break;
+	}
+
+	rc = slurp_data(sv[0]);
+	printf("done: unread %d, unsent %d\n", rc, msg_out->len);
+
+	close(sv[1]);
+	close(sv[0]);
+
+	msgb_free(msg_out);
+}
+
+
+static void test_partial_recv(void)
+{
+	int sv[2];
+	struct msgb *msg_out = msgb_alloc(4096, "msg_out");
+	int rc, i;
+
+	printf("Testing IPA recv with partitioned messages.\n");
+
+	if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == -1)
+		err(1, "socketpair");
+
+	fcntl(sv[0], F_SETFL, O_NONBLOCK);
+
+	for (i=0; i < ARRAY_SIZE(ipa_test_messages); i++)
+		append_ipa_message(msg_out, 200, ipa_test_messages[i]);
+
+	while (msg_out->len > 0) {
+		int len = 5;
+		if (len > msg_out->len)
+			len = msg_out->len;
+		if (write(sv[1], msg_out->data, len) == -1)
+			err(1, "write");
+		msgb_pull(msg_out, len);
+
+		if (msg_out->len == 0)
+			shutdown(sv[1], SHUT_WR);
+
+		rc = receive_messages(sv[0]);
+
+		if (rc == 0)
+			break;
+
+		if (rc < 0 && rc != -EAGAIN)
+			break;
+	}
+	rc = slurp_data(sv[0]);
+	printf("done: unread %d, unsent %d\n", rc, msg_out->len);
+
+	close(sv[1]);
+	close(sv[0]);
+
+	msgb_free(msg_out);
+}
+
+static struct log_info info = {};
+
+int main(int argc, char **argv)
+{
+	osmo_init_logging(&info);
+	log_set_all_filter(osmo_stderr_target, 1);
+	log_set_log_level(osmo_stderr_target, LOGL_INFO);
+
+	printf("Testing the IPA layer.\n");
+
+	/* run the tests */
+	test_complete_recv();
+	test_partial_recv();
+
+	printf("No crashes.\n");
+	return 0;
+}
diff --git a/tests/ipa_recv/ipa_recv_test.ok b/tests/ipa_recv/ipa_recv_test.ok
new file mode 100644
index 0000000..4144d47
--- /dev/null
+++ b/tests/ipa_recv/ipa_recv_test.ok
@@ -0,0 +1,12 @@
+Testing the IPA layer.
+Testing IPA recv with complete messages.
+got IPA message, size=10, proto=200, text="Hello IPA"
+got IPA message, size=86, proto=200, text="A longer test message. ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz"
+got IPA message, size=16, proto=200, text="Hello again IPA"
+got IPA message, size=1, proto=200, text=""
+got IPA message, size=14, proto=200, text="Next is empty"
+done: unread 14, unsent 0
+Testing IPA recv with partitioned messages.
+ipa_msg_recv failed with: Input/output error
+done: unread 0, unsent 154
+No crashes.
diff --git a/tests/testsuite.at b/tests/testsuite.at
index 04193c5..ff550b0 100644
--- a/tests/testsuite.at
+++ b/tests/testsuite.at
@@ -11,8 +11,15 @@ AT_BANNER([Regression tests.])
 # AT_CHECK([$abs_top_builddir/tests/NAME/NAME_test], [], [expout])
 # AT_CLEANUP
 
+AT_SETUP([ipa_recv])
+AT_KEYWORDS([ipa_recv])
+cat $abs_srcdir/ipa_recv/ipa_recv_test.ok > expout
+AT_CHECK([$abs_top_builddir/tests/ipa_recv/ipa_recv_test], [], [expout],[ignore])
+AT_CLEANUP
+
 AT_SETUP([subchan_demux])
 AT_KEYWORDS([subchan_demux])
 cat $abs_srcdir/subchan_demux/subchan_demux_test.ok > expout
 AT_CHECK([$abs_top_builddir/tests/subchan_demux/subchan_demux_test], [], [expout])
 AT_CLEANUP
+
