aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPablo Neira Ayuso <pablo@gnumonks.org>2011-10-17 19:49:33 +0200
committerPablo Neira Ayuso <pablo@netfilter.org>2011-10-17 22:12:42 +0200
commit20c660caecc95b03489f870945ae9fe91c839bd3 (patch)
tree77a64e776b56212768574aa8e3bd2a48136969eb
parent1434e40951a4eda107e2e81425f99a2d5de23975 (diff)
ipa: initial addition of helper functions and examples
This patch adds IPA helper function that can be use on top of stream sockets. The current API is just a copy and paste from libosmo-abis, it will change in follow up patches to improve it.
-rw-r--r--examples/Makefile.am12
-rw-r--r--examples/ipa-stream-client.c185
-rw-r--r--examples/ipa-stream-server.c121
-rw-r--r--include/osmocom/netif/Makefile.am1
-rw-r--r--include/osmocom/netif/ipa.h52
-rw-r--r--src/Makefile.am1
-rw-r--r--src/ipa.c73
7 files changed, 444 insertions, 1 deletions
diff --git a/examples/Makefile.am b/examples/Makefile.am
index 39e7207..be4ecde 100644
--- a/examples/Makefile.am
+++ b/examples/Makefile.am
@@ -2,11 +2,21 @@ INCLUDES = $(all_includes) -I$(top_srcdir)/include
AM_CFLAGS=-Wall -g $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOABIS_CFLAGS) $(COVERAGE_CFLAGS)
AM_LDFLAGS = $(COVERAGE_LDFLAGS)
-noinst_PROGRAMS = lapd-over-datagram-user \
+noinst_PROGRAMS = ipa-stream-client \
+ ipa-stream-server \
+ lapd-over-datagram-user \
lapd-over-datagram-network \
stream-client \
stream-server
+ipa_stream_client_SOURCES = ipa-stream-client.c
+ipa_stream_client_LDADD = $(top_builddir)/src/libosmonetif.la \
+ $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS)
+
+ipa_stream_server_SOURCES = ipa-stream-server.c
+ipa_stream_server_LDADD = $(top_builddir)/src/libosmonetif.la \
+ $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS)
+
lapd_over_datagram_user_SOURCES = lapd-over-datagram-user.c
lapd_over_datagram_user_LDADD = $(top_builddir)/src/libosmonetif.la \
$(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) \
diff --git a/examples/ipa-stream-client.c b/examples/ipa-stream-client.c
new file mode 100644
index 0000000..2b90f2c
--- /dev/null
+++ b/examples/ipa-stream-client.c
@@ -0,0 +1,185 @@
+/* IPA stream client example. */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sys/time.h>
+#include <arpa/inet.h>
+
+#include <osmocom/core/select.h>
+#include <osmocom/core/talloc.h>
+#include <osmocom/core/msgb.h>
+#include <osmocom/core/logging.h>
+#include <osmocom/core/application.h>
+
+#include <osmocom/netif/stream.h>
+#include <osmocom/netif/ipa.h>
+
+static LLIST_HEAD(msg_sent_list);
+
+struct msg_sent {
+ struct llist_head head;
+ struct msgb *msg;
+ int num;
+ struct timeval tv;
+};
+
+#define DIPATEST 0
+
+struct log_info_cat osmo_stream_client_test_cat[] = {
+ [DIPATEST] = {
+ .name = "DIPATEST",
+ .description = "STREAMCLIENT-mode test",
+ .color = "\033[1;35m",
+ .enabled = 1, .loglevel = LOGL_NOTICE,
+ },
+};
+
+const struct log_info osmo_stream_client_test_log_info = {
+ .filter_fn = NULL,
+ .cat = osmo_stream_client_test_cat,
+ .num_cat = ARRAY_SIZE(osmo_stream_client_test_cat),
+};
+
+static struct osmo_stream_client_conn *conn;
+
+void sighandler(int foo)
+{
+ LOGP(DIPATEST, LOGL_NOTICE, "closing stream.\n");
+ exit(EXIT_SUCCESS);
+}
+
+static int connect_cb(struct osmo_stream_client_conn *conn)
+{
+ int *__num_msgs = osmo_stream_client_conn_get_data(conn);
+ int num_msgs = *__num_msgs, i;
+
+ LOGP(DIPATEST, LOGL_NOTICE, "connected\n");
+
+ for (i=0; i<num_msgs; i++) {
+ struct msgb *msg;
+ struct msg_sent *msg_sent;
+ char *ptr;
+ int x;
+
+ msg = osmo_ipa_msg_alloc(0);
+ if (msg == NULL) {
+ LOGP(DLINP, LOGL_ERROR, "cannot alloc msg\n");
+ return -1;
+ }
+ ptr = (char *)msgb_put(msg, sizeof(int));
+ x = htonl(i);
+ memcpy(ptr, &x, sizeof(int));
+
+ msg_sent = talloc_zero(NULL, struct msg_sent);
+ if (msg_sent == NULL) {
+ LOGP(DLINP, LOGL_ERROR, "can't alloc struct\n");
+ return -1;
+ }
+ msg_sent->msg = msg;
+ gettimeofday(&msg_sent->tv, NULL);
+ msg_sent->num = i;
+ llist_add(&msg_sent->head, &msg_sent_list);
+
+ osmo_ipa_msg_push_header(msg, IPAC_PROTO_OSMO);
+
+ osmo_stream_client_conn_send(conn, msg);
+
+ LOGP(DIPATEST, LOGL_DEBUG, "enqueueing msg %d of "
+ "%d bytes to be sent\n", i, msg->len);
+ }
+ return 0;
+}
+
+static int read_cb(struct osmo_stream_client_conn *conn)
+{
+ struct msgb *msg;
+ struct osmo_fd *ofd = osmo_stream_client_conn_get_ofd(conn);
+
+ LOGP(DIPATEST, LOGL_DEBUG, "received message from stream\n");
+
+ msg = osmo_ipa_msg_alloc(0);
+ if (msg == NULL) {
+ LOGP(DIPATEST, LOGL_ERROR, "cannot allocate message\n");
+ return 0;
+ }
+ if (osmo_ipa_msg_recv(ofd->fd, msg) <= 0) {
+ LOGP(DIPATEST, LOGL_ERROR, "cannot receive message\n");
+ return 0;
+ }
+
+ int num;
+ struct msg_sent *cur, *tmp, *found = NULL;
+
+ num = ntohl(*((int *)(msg->data + sizeof(struct ipa_head))));
+ LOGP(DLINP, LOGL_DEBUG, "received msg number %d\n", num);
+
+ llist_for_each_entry_safe(cur, tmp, &msg_sent_list, head) {
+ if (cur->num == num) {
+ llist_del(&cur->head);
+ found = cur;
+ break;
+ }
+ }
+ if (found) {
+ struct timeval tv, diff;
+
+ gettimeofday(&tv, NULL);
+ timersub(&tv, &found->tv, &diff);
+
+ LOGP(DLINP, LOGL_NOTICE, "message %d replied "
+ "in %lu.%.6lu\n", num, diff.tv_sec, diff.tv_usec);
+ talloc_free(found);
+ } else {
+ LOGP(DLINP, LOGL_ERROR,
+ "message %d not found!\n", num);
+ }
+ return 0;
+}
+
+static void *tall_test;
+
+int main(int argc, char *argv[])
+{
+ int num_msgs;
+
+ signal(SIGINT, sighandler);
+
+ if (argc != 2) {
+ printf("Usage: %s [num_msgs]\n", argv[0]);
+ exit(EXIT_FAILURE);
+ }
+ num_msgs = atoi(argv[1]);
+
+ tall_test = talloc_named_const(NULL, 1, "osmo_stream_client_test");
+
+ osmo_init_logging(&osmo_stream_client_test_log_info);
+ log_set_log_level(osmo_stderr_target, LOGL_NOTICE);
+
+ /*
+ * initialize stream client.
+ */
+
+ conn = osmo_stream_client_conn_create(tall_test);
+ if (conn == NULL) {
+ fprintf(stderr, "cannot create client\n");
+ exit(EXIT_FAILURE);
+ }
+ osmo_stream_client_conn_set_addr(conn, "127.0.0.1");
+ osmo_stream_client_conn_set_port(conn, 10000);
+ osmo_stream_client_conn_set_connect_cb(conn, connect_cb);
+ osmo_stream_client_conn_set_read_cb(conn, read_cb);
+ osmo_stream_client_conn_set_data(conn, &num_msgs);
+
+ if (osmo_stream_client_conn_open(conn) < 0) {
+ fprintf(stderr, "cannot open client\n");
+ exit(EXIT_FAILURE);
+ }
+
+ LOGP(DIPATEST, LOGL_NOTICE, "Entering main loop\n");
+
+ while(1) {
+ osmo_select_main(0);
+ }
+}
diff --git a/examples/ipa-stream-server.c b/examples/ipa-stream-server.c
new file mode 100644
index 0000000..5264dab
--- /dev/null
+++ b/examples/ipa-stream-server.c
@@ -0,0 +1,121 @@
+/* IPA stream server example */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <osmocom/core/select.h>
+#include <osmocom/core/talloc.h>
+#include <osmocom/core/msgb.h>
+#include <osmocom/core/logging.h>
+#include <osmocom/core/application.h>
+
+#include <osmocom/netif/stream.h>
+#include <osmocom/netif/ipa.h>
+
+static void *tall_test;
+
+#define DSTREAMTEST 0
+
+struct log_info_cat osmo_stream_server_test_cat[] = {
+ [DSTREAMTEST] = {
+ .name = "DSTREAMTEST",
+ .description = "STREAMSERVER-mode test",
+ .color = "\033[1;35m",
+ .enabled = 1, .loglevel = LOGL_NOTICE,
+ },
+};
+
+const struct log_info osmo_stream_server_test_log_info = {
+ .filter_fn = NULL,
+ .cat = osmo_stream_server_test_cat,
+ .num_cat = ARRAY_SIZE(osmo_stream_server_test_cat),
+};
+
+static struct osmo_stream_server_link *server;
+static struct osmo_stream_server_conn *conn;
+
+void sighandler(int foo)
+{
+ LOGP(DSTREAMTEST, LOGL_NOTICE, "closing STREAMSERVER.\n");
+ exit(EXIT_SUCCESS);
+}
+
+int read_cb(struct osmo_stream_server_conn *conn)
+{
+ struct msgb *msg;
+ struct osmo_fd *ofd = osmo_stream_server_conn_get_ofd(conn);
+
+ LOGP(DSTREAMTEST, LOGL_DEBUG, "received message from stream\n");
+
+ msg = osmo_ipa_msg_alloc(0);
+ if (msg == NULL) {
+ LOGP(DSTREAMTEST, LOGL_ERROR, "cannot allocate message\n");
+ return 0;
+ }
+ if (osmo_ipa_msg_recv(ofd->fd, msg) <= 0) {
+ LOGP(DSTREAMTEST, LOGL_ERROR, "cannot receive message\n");
+ osmo_stream_server_conn_destroy(conn);
+ msgb_free(msg);
+ return 0;
+ }
+ osmo_stream_server_conn_send(conn, msg);
+ return 0;
+}
+
+static int close_cb(struct osmo_stream_server_conn *dummy)
+{
+ conn = NULL;
+ return 0;
+}
+
+static int accept_cb(struct osmo_stream_server_link *server, int fd)
+{
+ if (conn != NULL) {
+ LOGP(DSTREAMTEST, LOGL_ERROR, "Sorry, this example only "
+ "support one client simultaneously\n");
+ return -1;
+ }
+
+ conn = osmo_stream_server_conn_create(tall_test, server, fd,
+ read_cb, close_cb, NULL);
+ if (conn == NULL) {
+ LOGP(DSTREAMTEST, LOGL_ERROR,
+ "error while creating connection\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+int main(void)
+{
+ tall_test = talloc_named_const(NULL, 1, "osmo_stream_server_test");
+
+ osmo_init_logging(&osmo_stream_server_test_log_info);
+ log_set_log_level(osmo_stderr_target, LOGL_NOTICE);
+
+ /*
+ * initialize stream server.
+ */
+
+ server = osmo_stream_server_link_create(tall_test);
+ if (server == NULL) {
+ fprintf(stderr, "cannot create client\n");
+ exit(EXIT_FAILURE);
+ }
+ osmo_stream_server_link_set_addr(server, "127.0.0.1");
+ osmo_stream_server_link_set_port(server, 10000);
+ osmo_stream_server_link_set_accept_cb(server, accept_cb);
+
+ if (osmo_stream_server_link_open(server) < 0) {
+ fprintf(stderr, "cannot open client\n");
+ exit(EXIT_FAILURE);
+ }
+
+ LOGP(DSTREAMTEST, LOGL_NOTICE, "Entering main loop\n");
+
+ while(1) {
+ osmo_select_main(0);
+ }
+}
diff --git a/include/osmocom/netif/Makefile.am b/include/osmocom/netif/Makefile.am
index afab204..4e63846 100644
--- a/include/osmocom/netif/Makefile.am
+++ b/include/osmocom/netif/Makefile.am
@@ -1,4 +1,5 @@
osmonetif_HEADERS = datagram.h \
+ ipa.h \
stream.h
osmonetifdir = $(includedir)/osmocom/netif
diff --git a/include/osmocom/netif/ipa.h b/include/osmocom/netif/ipa.h
new file mode 100644
index 0000000..5b53b3a
--- /dev/null
+++ b/include/osmocom/netif/ipa.h
@@ -0,0 +1,52 @@
+#ifndef _OSMO_NETIF_IPA_H_
+#define _OSMO_NETIF_IPA_H_
+
+struct ipa_head {
+ uint16_t len; /* network byte order */
+ uint8_t proto;
+ uint8_t data[0];
+} __attribute__ ((packed));
+
+/* IPA protocols. */
+#define IPAC_PROTO_RSL 0x00
+#define IPAC_PROTO_IPACCESS 0xfe
+#define IPAC_PROTO_SCCP 0xfd
+#define IPAC_PROTO_OML 0xff
+#define IPAC_PROTO_OSMO 0xee /* OpenBSC extension. */
+#define IPAC_PROTO_MGCP_OLD 0xfc /* OpenBSC extension. */
+
+struct ipa_head_ext {
+ uint8_t proto;
+ uint8_t data[0];
+} __attribute__ ((packed));
+
+/* Protocol extensions. */
+#define IPAC_PROTO_EXT_CTRL 0x00
+#define IPAC_PROTO_EXT_MGCP 0x01
+#define IPAC_PROTO_EXT_LAC 0x02
+
+/* Message types. */
+#define IPAC_MSGT_PING 0x00
+#define IPAC_MSGT_PONG 0x01
+#define IPAC_MSGT_ID_GET 0x04
+#define IPAC_MSGT_ID_RESP 0x05
+#define IPAC_MSGT_ID_ACK 0x06
+#define IPAC_MSGT_SCCP_OLD 0xff /* OpenBSC extension */
+
+enum ipaccess_id_tags {
+ IPAC_IDTAG_SERNR = 0x00,
+ IPAC_IDTAG_UNITNAME = 0x01,
+ IPAC_IDTAG_LOCATION1 = 0x02,
+ IPAC_IDTAG_LOCATION2 = 0x03,
+ IPAC_IDTAG_EQUIPVERS = 0x04,
+ IPAC_IDTAG_SWVERSION = 0x05,
+ IPAC_IDTAG_IPADDR = 0x06,
+ IPAC_IDTAG_MACADDR = 0x07,
+ IPAC_IDTAG_UNIT = 0x08,
+};
+
+struct msgb *osmo_ipa_msg_alloc(int headroom);
+void osmo_ipa_msg_push_header(struct msgb *msg, uint8_t proto);
+int osmo_ipa_msg_recv(int fd, struct msgb *msg);
+
+#endif
diff --git a/src/Makefile.am b/src/Makefile.am
index bf2d60a..c501a57 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -9,4 +9,5 @@ AM_LDFLAGS = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOVTY_LIBS) $(COVERAG
lib_LTLIBRARIES = libosmonetif.la
libosmonetif_la_SOURCES = datagram.c \
+ ipa.c \
stream.c
diff --git a/src/ipa.c b/src/ipa.c
new file mode 100644
index 0000000..335c830
--- /dev/null
+++ b/src/ipa.c
@@ -0,0 +1,73 @@
+#include <stdlib.h>
+#include <arpa/inet.h>
+#include <errno.h>
+
+#include <osmocom/core/logging.h>
+#include <osmocom/core/msgb.h>
+#include <osmocom/netif/ipa.h>
+
+#define IPA_ALLOC_SIZE 1200
+
+struct msgb *osmo_ipa_msg_alloc(int headroom)
+{
+ struct msgb *msg;
+
+ headroom += sizeof(struct ipa_head);
+
+ msg = msgb_alloc_headroom(IPA_ALLOC_SIZE + headroom, headroom, "IPA");
+ if (msg == NULL) {
+ LOGP(DLINP, LOGL_ERROR, "cannot allocate message\n");
+ return NULL;
+ }
+ return msg;
+}
+
+void osmo_ipa_msg_push_header(struct msgb *msg, uint8_t proto)
+{
+ struct ipa_head *hh;
+
+ msg->l2h = msg->data;
+ hh = (struct ipa_head *) msgb_push(msg, sizeof(*hh));
+ hh->proto = proto;
+ hh->len = htons(msgb_l2len(msg));
+}
+
+int osmo_ipa_msg_recv(int fd, struct msgb *msg)
+{
+ struct ipa_head *hh;
+ int len, ret;
+
+ /* first read our 3-byte header */
+ hh = (struct ipa_head *) msg->data;
+ ret = recv(fd, msg->data, sizeof(*hh), 0);
+ if (ret <= 0) {
+ return ret;
+ } else if (ret != sizeof(*hh)) {
+ LOGP(DLINP, LOGL_ERROR, "too small message received\n");
+ return -EIO;
+ }
+ msgb_put(msg, ret);
+
+ /* then read the length as specified in header */
+ msg->l2h = msg->data + sizeof(*hh);
+ len = ntohs(hh->len);
+
+ if (len < 0 || IPA_ALLOC_SIZE < len + sizeof(*hh)) {
+ LOGP(DLINP, LOGL_ERROR, "bad message length of %d bytes, "
+ "received %d bytes\n", len, ret);
+ msgb_free(msg);
+ return -EIO;
+ }
+
+ ret = recv(fd, msg->l2h, len, 0);
+ if (ret <= 0) {
+ msgb_free(msg);
+ return ret;
+ } else if (ret < len) {
+ LOGP(DLINP, LOGL_ERROR, "trunked message received\n");
+ msgb_free(msg);
+ return -EIO;
+ }
+ msgb_put(msg, ret);
+ return ret;
+}