aboutsummaryrefslogtreecommitdiffstats
path: root/openbsc/src/osmo-ganc/ganc_server.c
diff options
context:
space:
mode:
authorHarald Welte <laforge@ganesha.gnumonks.org>2012-06-24 19:22:17 +0200
committerHarald Welte <laforge@ganesha.gnumonks.org>2012-06-24 19:22:17 +0200
commit83849feeb0311e0f96488c10aded1d0ff8f6e324 (patch)
tree0a9f129c3e76a667b32e57b53bf28229acca2270 /openbsc/src/osmo-ganc/ganc_server.c
parentdf4ea4f0e93b070af4b4c0e3566d62dc597d2e47 (diff)
ganc: Correctly return DISCOVERY ACCEPT and REGISTRATION ACCEPT
Diffstat (limited to 'openbsc/src/osmo-ganc/ganc_server.c')
-rw-r--r--openbsc/src/osmo-ganc/ganc_server.c117
1 files changed, 102 insertions, 15 deletions
diff --git a/openbsc/src/osmo-ganc/ganc_server.c b/openbsc/src/osmo-ganc/ganc_server.c
index 3a937b239..fa3b5fb3a 100644
--- a/openbsc/src/osmo-ganc/ganc_server.c
+++ b/openbsc/src/osmo-ganc/ganc_server.c
@@ -15,6 +15,15 @@
#include "conn.h"
#include "ganc_data.h"
+static void push_rc_csr_hdr(struct msgb *msg, uint8_t pdisc, uint8_t msgt)
+{
+ struct gan_rc_csr_hdr *gh =
+ (struct gan_rc_csr_hdr *) msgb_push(msg, sizeof(*gh));
+
+ gh->pdisc = pdisc;
+ gh->msg_type = msgt;
+}
+
static struct msgb *unc_msgb_alloc(void)
{
return msgb_alloc_headroom(1024+128, 128, "GANC Tx");
@@ -27,28 +36,91 @@ static int unc_peer_tx(struct gan_peer *peer, struct msgb *msg)
/* compute and fill-in length */
msg->l2h = msg->data;
gh->len = htons(msgb_l2len(msg)-2);
+
+ if (peer->gan_release == 0) {
+ /* shomehow old pre-GAN UMA doesn't like RC */
+ if (gh->pdisc == GA_PDISC_RC)
+ gh->pdisc = GA_PDISC_CSR;
+ }
return osmo_conn_enqueue(peer->conn, msg);
}
+static uint8_t *msgb_tlv_be16_put(struct msgb *msg, uint8_t tag, uint16_t val)
+{
+ uint16_t _val = htons(val);
+ return msgb_tlv_put(msg, tag, 2, (uint8_t *) &_val);
+}
+
+static void build_gan_cch_desc(struct gan_cch_desc_ie *ie, struct ganc_bts *bts)
+{
+ struct ganc_net *net = bts->net;
+
+ ie->ecmc = 0; /* Early Classmark allowed */
+ ie->nmo = 0; /* NMO 1 */
+ if (net->gprs.mode != 0)
+ ie->gprs = 0;
+ else
+ ie->gprs = 1; /* No GPRS */
+ ie->dtm = 0; /* No Dual Transfer Mode */
+ ie->att = 1; /* IMSI attach/detach shall be used */
+ ie->mscr = 1; /* Release 99 onwards */
+ ie->t3212 = net->timer[T3212];
+ ie->rac = bts->routing_area_code;
+ ie->sgsnr = 1; /* Release 99 onwards */
+ ie->ecmp = net->emergency_gan_preferred;
+ ie->re = 1; /* No call re-esetablishment */
+ ie->pfcfm = 0; /* No PFC */
+ ie->tgecs = 1; /* Permit UTRAN classmark change */
+ if (!net->emergency_gan_preferred)
+ ie->access_class[0] |= 0x4; /* No emergency calls */
+}
+
+/* FIXME: move to libosmocore */
+static void gsm48_cell_desc(struct gsm48_cell_desc *cd, uint8_t bsic, uint16_t arfcn)
+{
+ cd->ncc = (bsic >> 3) & 0x07;
+ cd->bcc = bsic & 0x07;
+ cd->arfcn_hi = arfcn >> 8;
+ cd->arfcn_lo = arfcn & 0xff;
+}
+
static int tx_unc_reg_acc(struct gan_peer *peer)
{
struct msgb *msg = unc_msgb_alloc();
- struct gan_rc_csr_hdr *gh = (struct gan_rc_csr_hdr*) msg->data;
+ struct gsm48_loc_area_id lai;
+ struct gsm48_cell_desc cd;
+ struct gan_cch_desc_ie ie;
+ struct ganc_bts *bts = peer->bts;
+ struct ganc_net *net = bts->net;
+ uint8_t gan_band = 0x02; /* GSM 1800 */
+
+ printf("<- GA-RC REGISTER ACCEPT\n");
if (!msg)
return -ENOMEM;
- gh->pdisc = GA_PDISC_RC;
- gh->msg_type = GA_MT_RC_REGISTER_ACCEPT;
+ gsm48_cell_desc(&cd, bts->bsic, bts->arfcn);
+ gsm48_generate_lai(&lai, net->country_code, net->network_code,
+ bts->location_area_code);
+ build_gan_cch_desc(&ie, bts);
+
+ push_rc_csr_hdr(msg, GA_PDISC_RC, GA_MT_RC_REGISTER_ACCEPT);
+
+ msgb_tlv_be16_put(msg, GA_IE_GERAN_CELL_ID, bts->cell_identity);
+ msgb_tlv_put(msg, GA_IE_LAC, sizeof(lai), (uint8_t *) &lai);
+ msgb_tlv_put(msg, GA_IE_GANC_CTRL_CH_DESC, sizeof(ie), (uint8_t *) &ie);
+ msgb_tlv_be16_put(msg, GA_IE_TU3910_TIMER, net->timer[TU3910]);
+ msgb_tlv_be16_put(msg, GA_IE_TU3906_TIMER, net->timer[TU3906]);
+ msgb_tlv_put(msg, GA_IE_GAN_BAND, 1, &gan_band);
+ msgb_tlv_be16_put(msg, GA_IE_TU3920_TIMER, net->timer[TU3920]);
+ msgb_tlv_put(msg, GA_IE_GANC_CELL_DESC, sizeof(cd), (uint8_t *) &cd);
+
+ if (net->gprs.mode != 0) {
+ msgb_tlv_be16_put(msg, GA_IE_TU4001_TIMER, net->timer[TU4001]);
+ msgb_tlv_be16_put(msg, GA_IE_TU4003_TIMER, net->timer[TU4003]);
+ }
-#if 0
- msgb_tlv_put(msg, GA_IE_GERAN_CELL_ID,,);
- msgb_tlv_put(msg, GA_IE_LAC,,);
- msgb_tlv_put(msg, GA_IE_GANC_CTRL_CH_DESC,,);
- msgb_tlv_put(msg, GA_IE_TU3910_TIMER,,);
- msgb_tlv_put(msg, GA_IE_TU3906_TIMER,,);
-#endif
return unc_peer_tx(peer, msg);
}
@@ -56,13 +128,13 @@ static int tx_unc_disco_acc(struct gan_peer *peer, const char *segw_host,
const char *ganc_host)
{
struct msgb *msg = unc_msgb_alloc();
- struct gan_rc_csr_hdr *gh = (struct gan_rc_csr_hdr*) msg->data;
+
+ printf("<- GA-RC DISCOVERY ACCEPT\n");
if (!msg)
return -ENOMEM;
- gh->pdisc = GA_PDISC_RC;
- gh->msg_type = GA_MT_RC_DISCOVERY_ACCEPT;
+ push_rc_csr_hdr(msg, GA_PDISC_RC, GA_MT_RC_DISCOVERY_ACCEPT);
msgb_tlv_put(msg, GA_IE_DEF_SEGW_FQDN, strlen(segw_host)+1, (uint8_t *) segw_host);
msgb_tlv_put(msg, GA_IE_DEF_GANC_FQDN, strlen(ganc_host)+1, (uint8_t *) ganc_host);
@@ -74,8 +146,12 @@ static int rx_unc_discovery_req(struct gan_peer *peer, struct msgb *msg,
struct gan_rc_csr_hdr *gh)
{
struct tlv_parsed tp;
+ int rc;
- tlv_parse(&tp, &tvlv_att_def, gh->data, htons(gh->len), 0, 0);
+ printf("-> GA-RC DISCOVERY REQUEST\n");
+ rc = tlv_parse(&tp, &tvlv_att_def, gh->data, htons(gh->len), 0, 0);
+ if (rc < 0)
+ fprintf(stderr, "error %d during tlv_parse\n", rc);
if (TLVP_PRESENT(&tp, GA_IE_MI)) {
char mi_string[32];
@@ -86,7 +162,15 @@ static int rx_unc_discovery_req(struct gan_peer *peer, struct msgb *msg,
}
return tx_unc_disco_acc(peer, "segw.uma.sysmocom.de",
- "ganc.uma.sysmocom.de");
+ "laforge.gnumonks.org");
+}
+
+static int rx_unc_register_req(struct gan_peer *peer, struct msgb *msg,
+ struct gan_rc_csr_hdr *gh)
+{
+ printf("-> GA-RC REGISTER REQUEST\n");
+
+ return tx_unc_reg_acc(peer);
}
static int rx_unc_rc(struct gan_peer *peer, struct msgb *msg, struct gan_rc_csr_hdr *gh)
@@ -95,6 +179,7 @@ static int rx_unc_rc(struct gan_peer *peer, struct msgb *msg, struct gan_rc_csr_
case GA_MT_RC_DISCOVERY_REQUEST:
return rx_unc_discovery_req(peer, msg, gh);
case GA_MT_RC_REGISTER_REQUEST:
+ return rx_unc_register_req(peer, msg, gh);
case GA_MT_RC_DEREGISTER:
break;
}
@@ -165,6 +250,8 @@ static void unc_accept_cb(struct osmo_conn *conn)
struct gan_peer *peer = talloc_zero(conn, struct gan_peer);
printf("accepted connection\n");
+ /* FIXME: later we may have different BTS with different ARFCN/BSIC/... */
+ peer->bts = g_ganc_bts;
peer->conn = conn;
conn->priv = peer;
}