ensure unique CellIDs in HNB-GW
If we receive a HNB-REGISTER-REQ with a cell ID which is already used by another registered NNB, log an error and send HNB-REGISTER-REJECT. Tested manually by running two 'hnb-test' programs concurrently (they need to listen on different telnet ports; this port is hard-coded so I compiled two different hnb-test binaries). Then I issued the 'hnbap hnb register' command on the telnet interface of each, and verified that the correct action is logged by osmo-hnbgw. Both hnb-test programs can connect, but only one of them can register at a time. Killing a registered 'hnb-test' program terminates its connection and allows the previously rejected one to register. The new rejection log message looks like this: hnbgw_hnbap.c:429 rejecting HNB-REGISTER-REQ with duplicate cell identity MCC=901,MNC=99,LAC=49406,RAC=66,SAC=43947,CID=182250155 from (r=127.0.0.1:42828<->l=127.0.0.1:29169) This change depends on a new API in libosmo-netif, which is added in https://gerrit.osmocom.org/#/c/6844/ Change-Id: Iffd441eb2b6b75dfbe001b49b01bea015ca6e11c Depends: I8ed78fe39c463e9018756700d13ee5ebe003b57f Related: OS#2789
This commit is contained in:
parent
e1c01a0262
commit
c964a2cfa1
|
@ -97,6 +97,10 @@ struct hnb_context {
|
||||||
/*! SCTP stream ID for RUA */
|
/*! SCTP stream ID for RUA */
|
||||||
uint16_t rua_stream;
|
uint16_t rua_stream;
|
||||||
|
|
||||||
|
/*! True if a HNB-REGISTER-REQ from this HNB has been accepted. Note that
|
||||||
|
* this entire data structure is freed if the HNB sends HNB-DE-REGISTER-REQ. */
|
||||||
|
bool hnb_registered;
|
||||||
|
|
||||||
/* linked list of hnbgw_context_map */
|
/* linked list of hnbgw_context_map */
|
||||||
struct llist_head map_list;
|
struct llist_head map_list;
|
||||||
};
|
};
|
||||||
|
@ -157,7 +161,7 @@ struct ue_context *ue_context_alloc(struct hnb_context *hnb, const char *imsi,
|
||||||
void ue_context_free(struct ue_context *ue);
|
void ue_context_free(struct ue_context *ue);
|
||||||
|
|
||||||
struct hnb_context *hnb_context_alloc(struct hnb_gw *gw, struct osmo_stream_srv_link *link, int new_fd);
|
struct hnb_context *hnb_context_alloc(struct hnb_gw *gw, struct osmo_stream_srv_link *link, int new_fd);
|
||||||
void hnb_context_release(struct hnb_context *ctx);
|
void hnb_context_release(struct hnb_context *ctx, bool destroy_conn);
|
||||||
|
|
||||||
void hnbgw_vty_init(struct hnb_gw *gw, void *tall_ctx);
|
void hnbgw_vty_init(struct hnb_gw *gw, void *tall_ctx);
|
||||||
int hnbgw_vty_go_parent(struct vty *vty);
|
int hnbgw_vty_go_parent(struct vty *vty);
|
||||||
|
|
16
src/hnbgw.c
16
src/hnbgw.c
|
@ -204,6 +204,12 @@ void ue_context_free(struct ue_context *ue)
|
||||||
}
|
}
|
||||||
static int hnb_close_cb(struct osmo_stream_srv *conn)
|
static int hnb_close_cb(struct osmo_stream_srv *conn)
|
||||||
{
|
{
|
||||||
|
struct hnb_context *hnb = osmo_stream_srv_get_data(conn);
|
||||||
|
|
||||||
|
/* This connection is about to be closed. Destroy the HNB context now. */
|
||||||
|
if (hnb)
|
||||||
|
hnb_context_release(hnb, false);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -228,10 +234,10 @@ static int hnb_read_cb(struct osmo_stream_srv *conn)
|
||||||
} else if (rc < 0) {
|
} else if (rc < 0) {
|
||||||
LOGP(DMAIN, LOGL_ERROR, "Error during sctp_recvmsg()\n");
|
LOGP(DMAIN, LOGL_ERROR, "Error during sctp_recvmsg()\n");
|
||||||
/* FIXME: clean up after disappeared HNB */
|
/* FIXME: clean up after disappeared HNB */
|
||||||
hnb_context_release(hnb);
|
hnb_context_release(hnb, true);
|
||||||
goto out;
|
goto out;
|
||||||
} else if (rc == 0) {
|
} else if (rc == 0) {
|
||||||
hnb_context_release(hnb);
|
hnb_context_release(hnb, true);
|
||||||
rc = -1;
|
rc = -1;
|
||||||
|
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -288,7 +294,7 @@ struct hnb_context *hnb_context_alloc(struct hnb_gw *gw, struct osmo_stream_srv_
|
||||||
return ctx;
|
return ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
void hnb_context_release(struct hnb_context *ctx)
|
void hnb_context_release(struct hnb_context *ctx, bool destroy_conn)
|
||||||
{
|
{
|
||||||
struct hnbgw_context_map *map, *map2;
|
struct hnbgw_context_map *map, *map2;
|
||||||
|
|
||||||
|
@ -305,7 +311,9 @@ void hnb_context_release(struct hnb_context *ctx)
|
||||||
context_map_deactivate(map);
|
context_map_deactivate(map);
|
||||||
}
|
}
|
||||||
ue_context_free_by_hnb(ctx->gw, ctx);
|
ue_context_free_by_hnb(ctx->gw, ctx);
|
||||||
osmo_stream_srv_destroy(ctx->conn);
|
|
||||||
|
if (destroy_conn)
|
||||||
|
osmo_stream_srv_destroy(ctx->conn);
|
||||||
|
|
||||||
talloc_free(ctx);
|
talloc_free(ctx);
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
|
|
||||||
#include <osmocom/core/msgb.h>
|
#include <osmocom/core/msgb.h>
|
||||||
#include <osmocom/core/utils.h>
|
#include <osmocom/core/utils.h>
|
||||||
|
#include <osmocom/core/socket.h>
|
||||||
#include <osmocom/gsm/gsm48.h>
|
#include <osmocom/gsm/gsm48.h>
|
||||||
#include <osmocom/netif/stream.h>
|
#include <osmocom/netif/stream.h>
|
||||||
|
|
||||||
|
@ -48,6 +49,45 @@ static int hnbgw_hnbap_tx(struct hnb_context *ctx, struct msgb *msg)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int hnbgw_tx_hnb_register_rej(struct hnb_context *ctx)
|
||||||
|
{
|
||||||
|
HNBRegisterReject_t reject_out;
|
||||||
|
HNBRegisterRejectIEs_t reject;
|
||||||
|
struct msgb *msg;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
reject.presenceMask = 0,
|
||||||
|
reject.cause.present = Cause_PR_radioNetwork;
|
||||||
|
reject.cause.choice.radioNetwork = CauseRadioNetwork_unspecified;
|
||||||
|
|
||||||
|
/* encode the Information Elements */
|
||||||
|
memset(&reject_out, 0, sizeof(reject_out));
|
||||||
|
rc = hnbap_encode_hnbregisterrejecties(&reject_out, &reject);
|
||||||
|
if (rc < 0) {
|
||||||
|
LOGP(DHNBAP, LOGL_ERROR, "Failure to encode HNB-REGISTER-REJECT to %s: rc=%d\n",
|
||||||
|
ctx->identity_info, rc);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* generate a successfull outcome PDU */
|
||||||
|
msg = hnbap_generate_unsuccessful_outcome(ProcedureCode_id_HNBRegister,
|
||||||
|
Criticality_reject,
|
||||||
|
&asn_DEF_HNBRegisterReject,
|
||||||
|
&reject_out);
|
||||||
|
|
||||||
|
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_HNBRegisterReject, &reject_out);
|
||||||
|
|
||||||
|
rc = hnbgw_hnbap_tx(ctx, msg);
|
||||||
|
if (rc == 0) {
|
||||||
|
/* Tell libosmo-netif to destroy this connection when it is done
|
||||||
|
* sending our HNB-REGISTER-REJECT response. */
|
||||||
|
osmo_stream_srv_set_flush_and_destroy(ctx->conn);
|
||||||
|
} else {
|
||||||
|
/* The message was not queued. Destroy the connection right away. */
|
||||||
|
hnb_context_release(ctx, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int hnbgw_tx_hnb_register_acc(struct hnb_context *ctx)
|
static int hnbgw_tx_hnb_register_acc(struct hnb_context *ctx)
|
||||||
{
|
{
|
||||||
HNBRegisterAccept_t accept_out;
|
HNBRegisterAccept_t accept_out;
|
||||||
|
@ -361,13 +401,14 @@ static int hnbgw_rx_hnb_deregister(struct hnb_context *ctx, ANY_t *in)
|
||||||
hnbap_cause_str(&ies.cause));
|
hnbap_cause_str(&ies.cause));
|
||||||
|
|
||||||
hnbap_free_hnbde_registeries(&ies);
|
hnbap_free_hnbde_registeries(&ies);
|
||||||
hnb_context_release(ctx);
|
hnb_context_release(ctx, true);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int hnbgw_rx_hnb_register_req(struct hnb_context *ctx, ANY_t *in)
|
static int hnbgw_rx_hnb_register_req(struct hnb_context *ctx, ANY_t *in)
|
||||||
{
|
{
|
||||||
|
struct hnb_context *hnb;
|
||||||
HNBRegisterRequestIEs_t ies;
|
HNBRegisterRequestIEs_t ies;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
|
@ -387,6 +428,20 @@ static int hnbgw_rx_hnb_register_req(struct hnb_context *ctx, ANY_t *in)
|
||||||
ctx->id.cid = asn1bitstr_to_u28(&ies.cellIdentity);
|
ctx->id.cid = asn1bitstr_to_u28(&ies.cellIdentity);
|
||||||
gsm48_mcc_mnc_from_bcd(ies.plmNidentity.buf, &ctx->id.mcc, &ctx->id.mnc);
|
gsm48_mcc_mnc_from_bcd(ies.plmNidentity.buf, &ctx->id.mcc, &ctx->id.mnc);
|
||||||
|
|
||||||
|
llist_for_each_entry(hnb, &ctx->gw->hnb_list, list) {
|
||||||
|
if (hnb->hnb_registered && ctx != hnb && memcmp(&ctx->id, &hnb->id, sizeof(ctx->id)) == 0) {
|
||||||
|
struct osmo_fd *ofd = osmo_stream_srv_get_ofd(ctx->conn);
|
||||||
|
char *name = osmo_sock_get_name(ctx, ofd->fd);
|
||||||
|
LOGP(DHNBAP, LOGL_ERROR, "rejecting HNB-REGISTER-REQ with duplicate cell identity "
|
||||||
|
"MCC=%u,MNC=%u,LAC=%u,RAC=%u,SAC=%u,CID=%u from %s\n",
|
||||||
|
ctx->id.mcc, ctx->id.mnc, ctx->id.lac, ctx->id.rac, ctx->id.sac, ctx->id.cid, name);
|
||||||
|
talloc_free(name);
|
||||||
|
return hnbgw_tx_hnb_register_rej(ctx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->hnb_registered = true;
|
||||||
|
|
||||||
DEBUGP(DHNBAP, "HNB-REGISTER-REQ from %s\n", ctx->identity_info);
|
DEBUGP(DHNBAP, "HNB-REGISTER-REQ from %s\n", ctx->identity_info);
|
||||||
|
|
||||||
/* Send HNBRegisterAccept */
|
/* Send HNBRegisterAccept */
|
||||||
|
|
Loading…
Reference in New Issue