aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHarald Welte <laforge@gnumonks.org>2015-08-29 21:47:39 +0200
committerHarald Welte <laforge@gnumonks.org>2015-08-29 21:47:39 +0200
commita2e6a7a05ef5ffa4fdbcebf28425d7e0b1eb5d6c (patch)
tree27f12669a2596bbdb1fef0f9fee9535fc304f188
parent6392710f84a9f79818a93434ed567443021506d4 (diff)
further tiny steps of progress on the hnb-gw infrastructure
-rw-r--r--src/hnbgw.c97
-rw-r--r--src/hnbgw.h42
-rw-r--r--src/hnbgw_hnbap.c47
3 files changed, 176 insertions, 10 deletions
diff --git a/src/hnbgw.c b/src/hnbgw.c
new file mode 100644
index 0000000..fc26d0d
--- /dev/null
+++ b/src/hnbgw.c
@@ -0,0 +1,97 @@
+
+#include <osmocom/core/select.h>
+#include <osmocom/core/socket.h>
+#include <osmocom/core/linuxlist.h>
+
+#include "hnbgw.h"
+
+struct hnb_gw g_hnb_gw = {
+ .config = {
+ .iuh_listen_port = IUH_DEFAULT_SCTP_PORT,
+ },
+};
+
+static int hnb_socket_cb(struct osmo_fd *fd, unsigned int what)
+{
+ struct hnb_context *hnb = fd->data;
+ struct sctp_sndrcvinfo sinfo;
+ struct msgb *msg = msgb_alloc(IUH_MSGB_SIZE, "Iuh rx");
+ int flags;
+ int rc;
+
+ if (!msg)
+ return -ENOMEM;
+
+ rc = sctp_recvmsg(fd->fd, msgb_data(msg), msgb_tailroom(msg),
+ NULL, NULL, &sinfo, &flags);
+ if (rc < 0) {
+ LOGP(DMAIN, LOGL_ERROR, "Error during sctp_recvmsg()\n");
+ return rc;
+ } else
+ msgb_put(msg, rc);
+
+ switch (sinfo.sinfo_ppid) {
+ case IUH_PPI_HNBAP:
+ rc = hnbgw_hnbap_rx(hnb, msg);
+ break;
+ case IUH_PPI_RUA:
+ rc = hnbgw_rua_rx(hnb, msg);
+ break;
+ case IUH_PPI_SABP:
+ case IUH_PPI_RNA:
+ case IUH_PPI_PUA:
+ LOGP(DMAIN, LOGL_ERROR, "Unimplemented SCTP PPID=%u received\n",
+ sinfo.sinfo_ppid);
+ rc = 0;
+ break;
+ default:
+ LOGP(DMAIN, LOGL_ERROR, "Unknown SCTP PPID=%u received\n",
+ sinfo.sinfo_ppid);
+ rc = 0;
+ break;
+ }
+
+ return rc;
+}
+
+/*! call-back when the listen FD has something to read */
+static int listen_fd_cb(struct osmo_fd *fd, unsigned int what)
+{
+ struct hnb_gw *gw = fd->data;
+ struct hmb_context *ctx;
+ struct sokaddr_storage sockaddr;
+ socklen_t len = sizeof(sockaddr);
+
+ int new_fd = accept(fd->fd, (struct sockaddr *)&sockaddr, &len);
+ if (new_fd < 0) {
+ LOGP(DMAIN, LOGL_ERROR, "Iuh accept() failed\n");
+ return new_fd;
+ }
+
+ LOGP(DMAIN, LOGL_INFO, "SCTP Connection accept()ed\n");
+
+ ctx = talloc_zero(tall_hnb_ctx, struct hnb_context);
+ if (!ctx)
+ return -ENOMEM;
+
+ ctx->gw = gw;
+ ctx->socket.data = ctx;
+ ctx->socket.fd = new_fd;
+ ctx->socket.when = BSC_FD_READ;
+ ctx->socket.cb = hnb_socket_cb;
+ osmo_fd_register(&cttx->socket);
+
+ return 0;
+}
+
+
+
+{
+ g_hnb_gw.listen_fd.cb = listen_fd_cb;
+ g_hnb_gw.listen_fd.when = BSC_FD_READ;
+ g_hnb_gw.listen_fd.data = &g_hnb_gw;
+
+ osmo_sock_init_ofd(&g_hnb_gw.listen_fd, AF_INET, SOCK_STREAM,
+ IPPROTO_SCTP, "127.0.0.1",
+ g_hnb_gw.config.iuh_listen_port, OSMO_SOCK_F_BIND);
+}
diff --git a/src/hnbgw.h b/src/hnbgw.h
index 87a5a2f..7b69a10 100644
--- a/src/hnbgw.h
+++ b/src/hnbgw.h
@@ -3,27 +3,63 @@
#include <osmocom/core/select.h>
#include <osmocom/core/linuxlist.h>
+/* 25.467 Section 7.1 */
+#define IUH_DEFAULT_SCTP_PORT 29169
+#define RNA_DEFAULT_SCTP_PORT 25471
+
+#define IUH_PPI_RUA 19
+#define IUH_PPI_HNBAP 20
+#define IUH_PPI_SABP 31
+#define IUH_PPI_RNA 42
+#define IUH_PPI_PUA 55
+
+#define IHU_MSGB_SIZE 2048
+
+struct umts_cell_id {
+ uint16_t mcc; /*!< Mobile Country Code */
+ uint16_t mnc; /*!< Mobile Network Code */
+ uint16_t lac; /*!< Locaton Area Code */
+ uint16_t rac; /*!< Routing Area Code */
+ uint16_t sac; /*!< Service Area Code */
+ uint32_t cid; /*!< Cell ID */
+};
+
+struct hnb_gw;
+
struct hnb_context {
/*! Entry in HNB-global list of HNB */
struct llist_head list;
+ /*! HNB-GW we are part of */
+ struct hnb_gw *gw;
/*! SCTP socket for Iuh to this specific HNB */
struct osmo_fd socket;
-
- /*! copied from HNB-Identity-Info */
- char identity[256];
+ /*! copied from HNB-Identity-Info IE */
+ char identity_info[256];
+ /*! copied from Cell Identity IE */
+ struct umts_cell_id id;
};
struct ue_context {
+ /*! Entry in the HNB-global list of UE */
struct llist_head list;
+ /*! Unique Context ID for this UE */
uint32_t context_id;
+ /*! UE is serviced via this HNB */
+ struct hnb_context *hnb;
};
struct hnb_gw {
struct {
/*! SCTP port for Iuh listening */
uint16_t iuh_listen_port;
+ /*! The UDP port where we receive multiplexed CS user
+ * plane traffic from HNBs */
+ uint16_t iuh_cs_mux_port;
+ uint16_t rnc_id;
} config;
/*! SCTP listen socket for incoming connections */
struct osmo_fd listen_fd;
struct llist_head hnb_list;
};
+
+extern struct hnb_gw g_hnb_gw;
diff --git a/src/hnbgw_hnbap.c b/src/hnbgw_hnbap.c
index 9b674ad..ce41222 100644
--- a/src/hnbgw_hnbap.c
+++ b/src/hnbgw_hnbap.c
@@ -29,7 +29,31 @@ struct ProtocolIE_Field_1 *find_ie(const struct ProtocolIE_Container_1 *cont, Pr
return NULL;
}
-static int hnbgw_rx_hnb_register_req(struct HNBRegisterRequest *req)
+static inline uint16_t asn1str_to_u16(ASN1String *as)
+{
+ if (as->len < 2)
+ return 0;
+ else
+ return *(uint16_t *)as->buf;
+}
+
+static inline uint8_t asn1str_to_u8(ASN1String *as)
+{
+ if (as->len < 1)
+ return 0;
+ else
+ return *(uint8_t *)as->buf;
+}
+
+static inline uint8_t asn1bitstr_to_u32(ASN1BitString *as)
+{
+ if (as->len < 25)
+ return 0;
+ else
+ return *(uint32_t *)as->buf;
+}
+
+static int hnbgw_rx_hnb_register_req(struct hnb_context *ctx, struct HNBRegisterRequest *req)
{
HNB_Identity *identity =
FIND_IE(req->protocolIEs, HNBAP_IEI_HNB_Identity);
@@ -47,10 +71,19 @@ static int hnbgw_rx_hnb_register_req(struct HNBRegisterRequest *req)
if(!identity || !loc || !plmn_id || !cell_id || !lac || !rac || !sac)
return -1;
+ /* copy all identity parameters from the message to ctx */
+ strncpy(ctx->identity_info, sizeof(ctx->identity_info, identity_info->buf);
+ ctx->id.lac = asn1str_to_u16(lac);
+ ctx->id.sac = asn1str_to_u16(sac);
+ ctx->id.rac = asn1str_to_u8(rac);
+ ctx->id.cid = asn1bitstr_to_u32(cell_id);
+ ctx->id.mcc FIXME
+ ctx->id.mnc FIXME
+
/* FIXME: Send HNBRegisterAccept */
}
-static int hnbgw_rx_ue_register_req(struct UERegisterRequest *req)
+static int hnbgw_rx_ue_register_req(struct hnb_context *ctx, struct UERegisterRequest *req)
{
UE_Identity *id =
FIND_IE(req->protocolIEs, HNBAP_IEI_UE_Identity);
@@ -65,7 +98,7 @@ static int hnbgw_rx_ue_register_req(struct UERegisterRequest *req)
/* FIXME: Send UERegisterAccept */
}
-static int hnbgw_rx_initiating_msg(struct InitiatingMessage *msg)
+static int hnbgw_rx_initiating_msg(struct hnb_context *hnb, struct InitiatingMessage *msg)
{
int rc;
@@ -73,14 +106,14 @@ static int hnbgw_rx_initiating_msg(struct InitiatingMessage *msg)
case HNBAP_PC_HNBRegister: /* 8.2 */
if (msg->value.type != asn1_type_HNBRegisterRequest)
return -1;
- rc = hnbgw_rx_hnb_register_req();
+ rc = hnbgw_rx_hnb_register_req(hnb, FIXME);
break;
case HNBAP_PC_HNBDe_Register: /* 8.3 */
break;
case HNBAP_PC_UERegister: /* 8.4 */
if (msg->value.type != asn1_type_UERegisterRequest)
return -1;
- rc = hnbgw_rx_ue_register_req();
+ rc = hnbgw_rx_ue_register_req(hnb, FIXME);
break;
case HNBAP_PC_UEDe_Register: /* 8.5 */
break;
@@ -107,7 +140,7 @@ static int hnbgw_rx_unsuccessful_outcome_msg(struct UnsuccessfulOutcome *msg)
}
-static int _hnbgw_hnbap_rx(struct HNBAP_PDU *pdu)
+static int _hnbgw_hnbap_rx(struct hnb_context *hnb, struct HNBAP_PDU *pdu)
{
/* it's a bit odd that we can't dispatch on procedure code, but
* that's not possible */
@@ -126,7 +159,7 @@ static int _hnbgw_hnbap_rx(struct HNBAP_PDU *pdu)
}
}
-int hnbgw_hnbap_rx(struct msgb *msg)
+int hnbgw_hnbap_rx(struct hnb_context *hnb, struct msgb *msg)
{
/* FIXME: decode and handle to _hnbgw_hnbap_rx() */
}