From b59902a1873a40d9726040dfc95e32174c18dc10 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Fri, 13 Jul 2012 14:16:11 +0200 Subject: ganc: Make sure to close tcp socket when closing ganc / track REG state We now track if a peer is REGISTERED or not, and only page him if he is registered. Furthermore, we look for old stale peer records and remove them, if we get a REGISTER on a new TCP connection. --- openbsc/src/osmo-ganc/ganc_data.h | 5 ++++ openbsc/src/osmo-ganc/ganc_server.c | 50 +++++++++++++++++++++++++++++++++---- 2 files changed, 50 insertions(+), 5 deletions(-) diff --git a/openbsc/src/osmo-ganc/ganc_data.h b/openbsc/src/osmo-ganc/ganc_data.h index 54993e9b5..f3122772a 100644 --- a/openbsc/src/osmo-ganc/ganc_data.h +++ b/openbsc/src/osmo-ganc/ganc_data.h @@ -38,6 +38,7 @@ struct gan_peer { uint8_t gan_release; /* UMA/GAN release version */ enum ganc_state csr_state; + uint32_t flags; char imsi[16+1]; uint8_t gan_classmark[2]; uint8_t cm2[3]; @@ -52,6 +53,10 @@ struct gan_peer { struct osmo_bsc_sccp_con *sccp_con; }; +enum gan_peer_flag { + GAN_PF_REGISTERED = 0x00000001, +}; + struct ganc_net { uint16_t country_code; uint16_t network_code; diff --git a/openbsc/src/osmo-ganc/ganc_server.c b/openbsc/src/osmo-ganc/ganc_server.c index d447552ba..b56896598 100644 --- a/openbsc/src/osmo-ganc/ganc_server.c +++ b/openbsc/src/osmo-ganc/ganc_server.c @@ -48,6 +48,22 @@ static void push_rc_csr_hdr(struct msgb *msg, uint8_t pdisc, uint8_t msgt) gh->msg_type = msgt; } +/* Find the matching gan_peer from the specified IMSI, if any */ +static struct gan_peer *gan_peer_by_imsi_f(const char *imsi, uint32_t flag) +{ + struct gan_peer *peer; + + llist_for_each_entry(peer, &g_ganc_bts->net->peers, entry) { + if (strlen(peer->imsi) && !strcmp(peer->imsi, imsi)) { + if (!flag || (peer->flags & flag)) + return peer; + } + } + + return NULL; +} + +/* destroy a peer, including anything that may hang off it */ static void gan_peer_destroy(struct gan_peer *peer) { if (!peer) @@ -55,6 +71,12 @@ static void gan_peer_destroy(struct gan_peer *peer) osmo_timer_del(&peer->keepalive_timer); llist_del(&peer->entry); + + if (peer->conn) { + osmo_conn_close(peer->conn); + peer->conn = NULL; + } + talloc_free(peer); } @@ -310,15 +332,27 @@ static int rx_rc_register_req(struct gan_peer *peer, struct msgb *msg, struct tlv_parsed *tp) { if (TLVP_PRESENT(tp, GA_IE_MI)) { - gsm48_mi_to_string(peer->imsi, sizeof(peer->imsi), + struct gan_peer *stale_peer; + char imsi[sizeof(peer->imsi)]; + gsm48_mi_to_string(imsi, sizeof(imsi), TLVP_VAL(tp, GA_IE_MI), TLVP_LEN(tp, GA_IE_MI)); - printf("\tfrom %s\n", peer->imsi); + printf("\tfrom %s\n", imsi); + + /* find any old/stale peer for the same imsi */ + stale_peer = gan_peer_by_imsi_f(imsi, GAN_PF_REGISTERED); + if (stale_peer) { + printf("\t destroying stale old gan_peer\n"); + gan_peer_destroy(stale_peer); + } + + memcpy(peer->imsi, imsi, sizeof(peer->imsi)); } if (TLVP_PRESENT(tp, GA_IE_GAN_RELEASE_IND)) peer->gan_release = *TLVP_VAL(tp, GA_IE_GAN_RELEASE_IND); if (TLVP_PRESENT(tp, GA_IE_GAN_CM) && TLVP_LEN(tp, GA_IE_GAN_CM) >=2) memcpy(peer->gan_classmark, TLVP_VAL(tp, GA_IE_GAN_CM), 2); + peer->flags |= GAN_PF_REGISTERED; peer->bts = select_bts(peer); osmo_timer_schedule(&peer->keepalive_timer, peer->bts->net->timer[TU3906]*2, 0); @@ -367,6 +401,7 @@ static int rx_rc_deregister(struct gan_peer *peer, struct msgb *msg, struct tlv_parsed *tp) { /* Release all resources, MS will TCP disconnect */ + peer->flags &= ~GAN_PF_REGISTERED; /* not all MS really close the TPC connection, we have to * release the TCP connection locally by release_timer! */ @@ -477,8 +512,10 @@ static int unc_read_cb(struct osmo_conn *conn) rc = read(conn->queue.bfd.fd, msg->data, 2); if (rc <= 0) { msgb_free(msg); - gan_peer_destroy(conn->priv); - osmo_conn_close(conn); + if (conn->priv) + gan_peer_destroy(conn->priv); + else + osmo_conn_close(conn); return rc; } else if (rc != 2) { msgb_free(msg); @@ -493,7 +530,10 @@ static int unc_read_cb(struct osmo_conn *conn) rc = read(conn->queue.bfd.fd, msg->data+2, len); if (rc < 0) { msgb_free(msg); - osmo_conn_close(conn); + if (conn->priv) + gan_peer_destroy(conn->priv); + else + osmo_conn_close(conn); return rc; } else if (rc != len) { msgb_free(msg); -- cgit v1.2.3