aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHarald Welte <laforge@gnumonks.org>2011-08-13 16:10:01 +0200
committerHarald Welte <laforge@gnumonks.org>2011-08-13 16:10:01 +0200
commitf8a7b7ee9e22230eb23a94c955c5ec4a59966f5a (patch)
tree3fb96ab7ef6746d653efb770e449586049952b3b
parent8ea19c69675ae975cb59942109a71fcca6538882 (diff)
parentcda48bc32655546554062284e6c1fdd418a7ccbe (diff)
Merge remote-tracking branch 'rrlp/master' into camp2011
-rw-r--r--openbsc/include/openbsc/gsm_data.h2
-rw-r--r--openbsc/include/openbsc/osmo_msc.h2
-rw-r--r--openbsc/src/libbsc/bsc_init.c2
-rw-r--r--openbsc/src/libbsc/bsc_vty.c26
-rw-r--r--openbsc/src/libmsc/gsm_04_08.c8
-rw-r--r--openbsc/src/libmsc/rrlp.c284
-rw-r--r--openbsc/src/libmsc/silent_call.c3
-rw-r--r--openbsc/src/osmo-nitb/bsc_hack.c2
8 files changed, 324 insertions, 5 deletions
diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h
index 715ff1bdd..717d6f11a 100644
--- a/openbsc/include/openbsc/gsm_data.h
+++ b/openbsc/include/openbsc/gsm_data.h
@@ -271,6 +271,8 @@ struct gsm_network {
/* Radio Resource Location Protocol (TS 04.31) */
struct {
enum rrlp_mode mode;
+ int on_attach;
+ int on_paging;
} rrlp;
/* enable the DTXu and DTXd for this network */
diff --git a/openbsc/include/openbsc/osmo_msc.h b/openbsc/include/openbsc/osmo_msc.h
index beb3f5e4c..27ba45208 100644
--- a/openbsc/include/openbsc/osmo_msc.h
+++ b/openbsc/include/openbsc/osmo_msc.h
@@ -7,5 +7,7 @@
struct bsc_api *msc_bsc_api();
void msc_release_connection(struct gsm_subscriber_connection *conn);
+int send_rrlp_req(struct gsm_subscriber_connection *conn);
+
#endif
diff --git a/openbsc/src/libbsc/bsc_init.c b/openbsc/src/libbsc/bsc_init.c
index 1d885db37..4c92377df 100644
--- a/openbsc/src/libbsc/bsc_init.c
+++ b/openbsc/src/libbsc/bsc_init.c
@@ -464,7 +464,7 @@ int bsc_bootstrap_network(int (*mncc_recv)(struct gsm_network *, struct msgb *),
return rc;
}
- rc = telnet_init(tall_bsc_ctx, bsc_gsmnet, 4242);
+ rc = telnet_init(tall_bsc_ctx, bsc_gsmnet, 4342);
if (rc < 0)
return rc;
diff --git a/openbsc/src/libbsc/bsc_vty.c b/openbsc/src/libbsc/bsc_vty.c
index d4079f3e4..79697940b 100644
--- a/openbsc/src/libbsc/bsc_vty.c
+++ b/openbsc/src/libbsc/bsc_vty.c
@@ -575,6 +575,8 @@ static int config_write_net(struct vty *vty)
vty_out(vty, " paging any use tch %d%s", gsmnet->pag_any_tch, VTY_NEWLINE);
vty_out(vty, " rrlp mode %s%s", rrlp_mode_name(gsmnet->rrlp.mode),
VTY_NEWLINE);
+ vty_out(vty, " rrlp on attach %d%s", gsmnet->rrlp.on_attach, VTY_NEWLINE);
+ vty_out(vty, " rrlp on paging %d%s", gsmnet->rrlp.on_paging, VTY_NEWLINE);
vty_out(vty, " mm info %u%s", gsmnet->send_mm_info, VTY_NEWLINE);
vty_out(vty, " handover %u%s", gsmnet->handover.active, VTY_NEWLINE);
vty_out(vty, " handover window rxlev averaging %u%s",
@@ -1294,6 +1296,28 @@ DEFUN(cfg_net_rrlp_mode, cfg_net_rrlp_mode_cmd,
return CMD_SUCCESS;
}
+DEFUN(cfg_net_rrlp_on_attach, cfg_net_rrlp_on_attach_cmd,
+ "rrlp on attach (0|1)",
+ "Whether to perform a RRLP position request on SUBSCRIBER ATTACH")
+{
+ struct gsm_network *gsmnet = gsmnet_from_vty(vty);
+
+ gsmnet->rrlp.on_attach = atoi(argv[0]);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_net_rrlp_on_paging, cfg_net_rrlp_on_paging_cmd,
+ "rrlp on paging (0|1)",
+ "Whether to perform a RRLP position request on PAGING SUCCESS")
+{
+ struct gsm_network *gsmnet = gsmnet_from_vty(vty);
+
+ gsmnet->rrlp.on_paging = atoi(argv[0]);
+
+ return CMD_SUCCESS;
+}
+
DEFUN(cfg_net_mm_info, cfg_net_mm_info_cmd,
"mm info (0|1)",
"Whether to send MM INFO after LOC UPD ACCEPT")
@@ -2729,6 +2753,8 @@ int bsc_vty_init(const struct log_info *cat)
install_element(GSMNET_NODE, &cfg_net_encryption_cmd);
install_element(GSMNET_NODE, &cfg_net_neci_cmd);
install_element(GSMNET_NODE, &cfg_net_rrlp_mode_cmd);
+ install_element(GSMNET_NODE, &cfg_net_rrlp_on_attach_cmd);
+ install_element(GSMNET_NODE, &cfg_net_rrlp_on_paging_cmd);
install_element(GSMNET_NODE, &cfg_net_mm_info_cmd);
install_element(GSMNET_NODE, &cfg_net_handover_cmd);
install_element(GSMNET_NODE, &cfg_net_ho_win_rxlev_avg_cmd);
diff --git a/openbsc/src/libmsc/gsm_04_08.c b/openbsc/src/libmsc/gsm_04_08.c
index bd452ed99..ce8fd3d04 100644
--- a/openbsc/src/libmsc/gsm_04_08.c
+++ b/openbsc/src/libmsc/gsm_04_08.c
@@ -1147,6 +1147,14 @@ static int gsm48_rx_rr_app_info(struct gsm_subscriber_connection *conn, struct m
DEBUGP(DNM, "RX APPLICATION INFO id/flags=0x%02x apdu_len=%u apdu=%s",
apdu_id_flags, apdu_len, osmo_hexdump(apdu_data, apdu_len));
+#if 1 /* RRLP Server */
+ if(apdu_id_flags == 0x00) { /* RRLP */
+ extern int handle_rrlp(struct gsm_subscriber_connection *conn, uint8_t *data, int len);
+
+ handle_rrlp(conn, apdu_data, apdu_len);
+ }
+#endif
+
return db_apdu_blob_store(conn->subscr, apdu_id_flags, apdu_len, apdu_data);
}
diff --git a/openbsc/src/libmsc/rrlp.c b/openbsc/src/libmsc/rrlp.c
index 161456a06..138d865b8 100644
--- a/openbsc/src/libmsc/rrlp.c
+++ b/openbsc/src/libmsc/rrlp.c
@@ -26,6 +26,282 @@
#include <openbsc/gsm_subscriber.h>
#include <openbsc/chan_alloc.h>
+/* ----------------------------------------------- */
+
+/* TODO: move in a separate file ? */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#define RRLP_SERV_PORT 7890
+#define RRLP_SERV_IP "127.0.0.2" /* TODO: from config file */
+
+#define MAX_RRLP_DATA 256
+
+/* Server cmds */
+
+#define RRLP_CMD_MS_DATA 1 /* data from MS */
+#define RRLP_CMD_MS_DATA_SLOW 2 /* data from MS, slow channel */
+
+/* Server response */
+
+#define RRLP_RSP_ASSIST_DATA 1 /* assitance data, send to MS */
+#define RRLP_RSP_RRLP_ERROR 2 /* RRLP error */
+#define RRLP_RSP_RRLP_POSITION 3 /* RRLP position */
+#define RRLP_RSP_ERROR 4 /* something went wrong */
+
+/* TODO: adjust error messages, use logging */
+
+static int rrlp_serv_cmd(struct gsm_subscriber_connection *conn,
+ uint8_t cmd, uint8_t *data, int len_data,
+ uint8_t *cmd_reply, uint8_t *reply, int *len_reply)
+{
+ static int fd = -1;
+ static struct sockaddr_in sa;
+ int len;
+ uint8_t buf[2 + 1 + 8 + MAX_RRLP_DATA]; /* len, cmd, subscriber ID, data */
+ int len_pkt, offs;
+ int rc;
+ long long unsigned int id;
+ struct sockaddr_in from;
+ int from_len;
+ fd_set readset;
+ struct timeval tv;
+
+ if(len_data > MAX_RRLP_DATA) {
+ fprintf(stderr, "len_data > MAX_RRLP_DATA: %d\n", len_data);
+ return -1;
+ }
+ if(fd == -1) {
+ fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ if(fd < 0) {
+ fprintf(stderr, "socket() failed: (%d) %s\n", fd, strerror(errno));
+ return -1;
+ }
+
+ sa.sin_family = AF_INET;
+ sa.sin_port = htons(RRLP_SERV_PORT);
+ if(inet_aton(RRLP_SERV_IP, &sa.sin_addr) != 1) {
+ fprintf(stderr, "inet_aton() failed: %s\n", strerror(errno));
+ close(fd);
+ fd = -1;
+ return -1;
+ }
+
+ rc = connect(fd, (struct sockaddr *)&sa, sizeof(sa));
+ if(rc < 0) {
+ fprintf(stderr, "connect() failed: (%d) %s\n", rc, strerror(errno));
+ close(fd);
+ fd = -1;
+ return -1;
+ }
+ }
+
+ /* we are now connected */
+
+ id = conn->subscr->id;
+
+ /* build cmd packet */
+
+ len_pkt = 2 + 1 + 8 + len_data;
+ buf[0] = len_pkt & 0xFF;
+ buf[1] = (len_pkt >> 8) & 0xFF;
+
+ buf[2] = cmd;
+
+ buf[3] = id & 0xFF;
+ buf[4] = (id >> 8) & 0xFF;
+ buf[5] = (id >> 16) & 0xFF;
+ buf[6] = (id >> 24) & 0xFF;
+ buf[7] = (id >> 32) & 0xFF;
+ buf[8] = (id >> 40) & 0xFF;
+ buf[9] = (id >> 48) & 0xFF;
+ buf[10] = (id >> 56) & 0xFF;
+ /* data */
+ memcpy(&buf[11], data, len_data);
+
+ /* send cmd */
+
+ len = sendto(fd, buf, len_pkt, 0, (struct sockaddr*)&sa, sizeof(sa));
+ if(len < 0) {
+ fprintf(stderr, "sendto() failed: (%d) %s\n", len, strerror(errno));
+ close(fd);
+ fd = -1;
+ return -1;
+ }
+ if(len != len_pkt) {
+ fprintf(stderr, "sendto: len != len_pkt: %d %d\n", len, len_pkt);
+ close(fd);
+ fd = -1;
+ return -1;
+ }
+
+ /* wait at most 500 ms for a reply */
+
+ FD_ZERO(&readset);
+ FD_SET(fd, &readset);
+ tv.tv_sec = 0;
+ tv.tv_usec = 500 * 1000;
+
+ /* this creates another UDP socket on Cygwin !? */
+ rc = select(fd + 1, &readset, NULL, NULL, &tv);
+ if(rc < 0) {
+ fprintf(stderr, "select() failed: (%d) %s\n", rc, strerror(errno));
+ close(fd);
+ fd = -1;
+ return -1;
+ }
+
+ if(!FD_ISSET(fd, &readset)) {
+ fprintf(stderr, "timeout select()\n");
+ close(fd);
+ fd = -1;
+ return -1;
+ }
+
+ /* read packet */
+ from_len = sizeof(from);
+ len = recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr*)&from, &from_len);
+ if(len < 0) {
+ fprintf(stderr, "recvfrom() failed: (%d) %s\n", len, strerror(errno));
+ close(fd);
+ fd = -1;
+ return -1;
+ }
+ if(len < 2) {
+ fprintf(stderr, "len < 2: %d\n", len);
+ close(fd);
+ fd = -1;
+ return -1;
+ }
+ len_pkt = buf[0] + (buf[1] << 8);
+ if(len_pkt < 2 + 1) {
+ fprintf(stderr, "len_pkt < 2 + 1: %d\n", len_pkt);
+ close(fd);
+ fd = -1;
+ return -1;
+ }
+ if(len != len_pkt) {
+ fprintf(stderr, "recvfrom: len != len_pkt: %d %d\n", len, len_pkt);
+ close(fd);
+ fd = -1;
+ return -1;
+ }
+ len_pkt -= 2;
+ offs = 2;
+
+#if 0 /* dump packet */
+ {
+ int i;
+ for(i = 0; i < len_pkt; i++)
+ printf("%02X ", buf[offs + i]);
+ printf("\n");
+ }
+#endif
+
+ /* process packet */
+
+ *len_reply = len_pkt - 1;
+ *cmd_reply = buf[offs];
+ memcpy(reply, &buf[offs + 1], *len_reply);
+
+ return 0;
+}
+
+/* ----------------------------------------------- */
+
+int send_rrlp_req(struct gsm_subscriber_connection *conn);
+
+/* TODO: adjust error messages, use logging */
+
+int handle_rrlp(struct gsm_subscriber_connection *conn, uint8_t *data, int len)
+{
+ struct gsm_network *net = conn->bts->network;
+ int rc;
+ uint8_t cmd_reply;
+ uint8_t reply[MAX_RRLP_DATA];
+ int len_reply;
+ uint8_t cmd;
+
+ if (net->rrlp.mode == RRLP_MODE_NONE)
+ return 0;
+
+ if(len > MAX_RRLP_DATA) {
+ fprintf(stderr, "too many data for handle_rrlp (%d)\n", len);
+ return -1;
+ }
+
+ /* TODO: decide if channel is slow (SDCCH), for slow channels
+ only short assistance data should be sent */
+
+ if(1)
+ cmd = RRLP_CMD_MS_DATA;
+ else
+ cmd = RRLP_CMD_MS_DATA_SLOW;
+
+ rc = rrlp_serv_cmd(conn, cmd, data, len, &cmd_reply, reply, &len_reply);
+ if(rc != 0) {
+ fprintf(stderr, "rrlp_serv_cmd failed (%d)\n", rc);
+ return rc;
+ }
+
+ if(cmd_reply == RRLP_RSP_ERROR) {
+ printf("RRLP Server error (general): %s\n", reply);
+ return 0;
+ }
+
+ if(cmd_reply == RRLP_RSP_RRLP_ERROR) {
+ printf("RRLP Server error (RRLP): %s\n", reply);
+ return 0;
+ }
+
+ if(cmd_reply == RRLP_RSP_RRLP_POSITION) {
+ long latitude;
+ long longitude;
+ long altitude;
+
+ if(len_reply != 12) {
+ fprintf(stderr, "invalid RRLP position length (%d)\n", len_reply);
+ return -1;
+ }
+
+ latitude = reply[0] + (reply[1] << 8) + (reply[2] << 16) + (reply[3] << 24);
+ longitude = reply[4] + (reply[5] << 8) + (reply[6] << 16) + (reply[7] << 24);
+ altitude = reply[8] + (reply[9] << 8) + (reply[10] << 16) + (reply[11] << 24);
+
+ /* TODO: do something useful with the position */
+
+ printf("RRLP Server position: ");
+ printf("latitude = %f ", ((double)latitude * 90.0) / 0x800000L);
+ printf("longitude = %f ", ((double)longitude * 360.0) / 0x1000000L);
+ printf("altitude = %ld\n", altitude);
+
+ return 0;
+ }
+
+ if(cmd_reply == RRLP_RSP_ASSIST_DATA) {
+ printf("Assistance data, len %d\n", len_reply);
+
+ /*
+ If there are assistance data, send them. If there are no more,
+ repeat the measurement request
+ */
+
+ if(len_reply)
+ return gsm48_send_rr_app_info(conn, 0x00, len_reply, reply);
+ else
+ send_rrlp_req(conn);
+ }
+
+ return 0;
+}
+
/* RRLP msPositionReq, nsBased,
* Accuracy=60, Method=gps, ResponseTime=2, oneSet */
static const uint8_t ms_based_pos_req[] = { 0x40, 0x01, 0x78, 0xa8 };
@@ -38,7 +314,7 @@ static const uint8_t ms_pref_pos_req[] = { 0x40, 0x02, 0x79, 0x50 };
Accuracy=60, Method=gpsOrEOTD, ResponseTime=5, multipleSets */
static const uint8_t ass_pref_pos_req[] = { 0x40, 0x03, 0x79, 0x50 };
-static int send_rrlp_req(struct gsm_subscriber_connection *conn)
+int send_rrlp_req(struct gsm_subscriber_connection *conn)
{
struct gsm_network *net = conn->bts->network;
const uint8_t *req;
@@ -75,7 +351,8 @@ static int subscr_sig_cb(unsigned int subsys, unsigned int signal,
conn = connection_for_subscr(subscr);
if (!conn)
break;
- send_rrlp_req(conn);
+ if (conn->bts->network->rrlp.on_attach)
+ send_rrlp_req(conn);
break;
}
return 0;
@@ -89,7 +366,8 @@ static int paging_sig_cb(unsigned int subsys, unsigned int signal,
switch (signal) {
case S_PAGING_SUCCEEDED:
/* A subscriber has attached. */
- send_rrlp_req(psig_data->conn);
+ if (psig_data->conn->bts->network->rrlp.on_paging)
+ send_rrlp_req(psig_data->conn);
break;
case S_PAGING_EXPIRED:
break;
diff --git a/openbsc/src/libmsc/silent_call.c b/openbsc/src/libmsc/silent_call.c
index 6a188c892..f02a3e804 100644
--- a/openbsc/src/libmsc/silent_call.c
+++ b/openbsc/src/libmsc/silent_call.c
@@ -57,6 +57,8 @@ static int paging_cb_silent(unsigned int hooknum, unsigned int event,
conn->silent_call = 1;
/* increment lchan reference count */
osmo_signal_dispatch(SS_SCALL, S_SCALL_SUCCESS, &sigdata);
+ if (conn->bts->network->rrlp.on_paging)
+ send_rrlp_req(conn);
break;
case GSM_PAGING_EXPIRED:
case GSM_PAGING_BUSY:
@@ -88,6 +90,7 @@ struct msg_match {
static const struct msg_match silent_call_accept[] = {
{ GSM48_PDISC_MM, GSM48_MT_MM_LOC_UPD_REQUEST },
{ GSM48_PDISC_MM, GSM48_MT_MM_CM_SERV_REQ },
+ { GSM48_PDISC_RR, GSM48_MT_RR_APP_INFO}, // for RRLP
};
/* decide if we need to reroute a message as part of a silent call */
diff --git a/openbsc/src/osmo-nitb/bsc_hack.c b/openbsc/src/osmo-nitb/bsc_hack.c
index 9693dc476..9f50b27bb 100644
--- a/openbsc/src/osmo-nitb/bsc_hack.c
+++ b/openbsc/src/osmo-nitb/bsc_hack.c
@@ -250,7 +250,7 @@ int main(int argc, char **argv)
exit(1);
bsc_api_init(bsc_gsmnet, msc_bsc_api());
- controlif_setup(bsc_gsmnet, 4249);
+ controlif_setup(bsc_gsmnet, 4349);
/* seed the PRNG */
srand(time(NULL));