summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHarald Welte <laforge@gnumonks.org>2012-07-13 14:16:11 +0200
committerHarald Welte <laforge@gnumonks.org>2015-11-15 14:15:19 +0100
commit6758fb50314cd5f8cc84d76ea1dbdef98ad2d084 (patch)
tree38d3cc8de7e20b055447a48f1deb658ac9dc5bd5
parent958c473bb0b23d6933f01266df7b7be8fe1e29d8 (diff)
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.
-rw-r--r--openbsc/src/osmo-ganc/ganc_data.h5
-rw-r--r--openbsc/src/osmo-ganc/ganc_server.c50
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 54993e9..f312277 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 d447552..b568965 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);