From 12bc4afab3096c60554cd6d43fa11840bd76228c Mon Sep 17 00:00:00 2001 From: Pau Espin Pedrol Date: Thu, 29 Sep 2022 16:44:50 +0200 Subject: [PATCH] Workaround bug where old hnb_context from same remote addr+port is kept Under some circumstancies not yet fully known, which seems to involve bad link quality and high latencies and some specific hNodeB which reuse its local IP addr+port, it is seen that a 2nd SCTP connection is created from the same HNB while locally we still keep the old SCTP connection and its related hnb_context. Hence, when the hNodeB tries to register again with this new conn, it is rejected all the time by the HNBGW. Related: SYS#6113 Change-Id: I33ae901cc37646eca90bf06953e44fcc25f4d6c6 --- src/osmo-hnbgw/hnbgw_hnbap.c | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/src/osmo-hnbgw/hnbgw_hnbap.c b/src/osmo-hnbgw/hnbgw_hnbap.c index 1c51b63..23d1f48 100644 --- a/src/osmo-hnbgw/hnbgw_hnbap.c +++ b/src/osmo-hnbgw/hnbgw_hnbap.c @@ -395,7 +395,7 @@ static int hnbgw_rx_hnb_deregister(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; + struct hnb_context *hnb, *tmp; HNBAP_HNBRegisterRequestIEs_t ies; int rc; struct osmo_plmn_id plmn; @@ -422,8 +422,35 @@ static int hnbgw_rx_hnb_register_req(struct hnb_context *ctx, ANY_t *in) ctx->id.mcc = plmn.mcc; ctx->id.mnc = plmn.mnc; - llist_for_each_entry(hnb, &ctx->gw->hnb_list, list) { + llist_for_each_entry_safe(hnb, tmp, &ctx->gw->hnb_list, list) { if (hnb->hnb_registered && ctx != hnb && memcmp(&ctx->id, &hnb->id, sizeof(ctx->id)) == 0) { + /* If it's coming from the same remote IP addr+port, then it must be our internal + * fault (bug), and we release the old context to keep going... */ + struct osmo_fd *other_fd = osmo_stream_srv_get_ofd(hnb->conn); + struct osmo_sockaddr other_osa = {}; + struct osmo_sockaddr cur_osa = {}; + socklen_t len = sizeof(other_osa); + if (getpeername(other_fd->fd, &other_osa.u.sa, &len) < 0) { + LOGHNB(ctx, DHNBAP, LOGL_ERROR, "BUG! Found old registered HNB with invalid socket, releasing it\n"); + hnb_context_release(hnb); + continue; + } + len = sizeof(cur_osa); + if (getpeername(ofd->fd, &cur_osa.u.sa, &len) < 0) { + LOGHNB(ctx, DHNBAP, LOGL_ERROR, "Error getpeername(): %s\n", strerror(errno)); + if (osmo_sockaddr_cmp(&cur_osa, &other_osa) == 0) { + LOGHNB(ctx, DHNBAP, LOGL_ERROR, "BUG! Found old registered HNB with same remote address, releasing it\n"); + hnb_context_release(hnb); + continue; + } + } else if (osmo_sockaddr_cmp(&cur_osa, &other_osa) == 0) { + LOGHNB(ctx, DHNBAP, LOGL_ERROR, "BUG! Found old registered HNB with same remote address, releasing it\n"); + hnb_context_release(hnb); + continue; + } /* else: addresses are different, we continue below */ + + /* If new conn registering same HNB is from anoter remote addr+port, let's reject it to avoid + * misconfigurations or someone trying to impersonate an already working HNB: */ LOGHNB(ctx, 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);