summaryrefslogtreecommitdiff
path: root/src/util/cell_log.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/util/cell_log.c')
-rw-r--r--src/util/cell_log.c434
1 files changed, 434 insertions, 0 deletions
diff --git a/src/util/cell_log.c b/src/util/cell_log.c
new file mode 100644
index 0000000..59d8942
--- /dev/null
+++ b/src/util/cell_log.c
@@ -0,0 +1,434 @@
+/* libgsmd tool
+ *
+ * (C) 2006-2007 by OpenMoko, Inc.
+ * Written by Harald Welte <laforge@openmoko.org>
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <time.h>
+#include <syslog.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <libgsmd/libgsmd.h>
+#include <libgsmd/voicecall.h>
+#include <libgsmd/misc.h>
+#include <libgsmd/phonebook.h>
+#include <libgsmd/sms.h>
+#include <libgsmd/pin.h>
+#include <gsmd/usock.h>
+#include <gsmd/ts0705.h>
+#include <common/linux_list.h>
+
+#ifndef __GSMD__
+#define __GSMD__
+#include <gsmd/talloc.h>
+#undef __GSMD__
+#endif
+
+#define STDIN_BUF_SIZE 1024
+
+static int pending_responses = 0;
+
+
+
+/* BTS RF_LOCK */
+
+#define MIN_NO_NET_SECS 60
+#define OUR_MCC 901
+#define OUR_MNC 99
+#define LOCK_PATH "/var/lock/bts_rf_lock"
+
+static time_t last_network_seen;
+unsigned int rf_lock_active = 0;
+
+static void bts_rf_lock(int on)
+{
+ int fd;
+
+ /* only print message on status change */
+ if (rf_lock_active != on)
+ syslog(LOG_NOTICE, "RF_LOCK: %sabling lock\n", on ? "En" : "Dis");
+
+ /* for safety, always update the actual file on disk */
+ if (on == 1) {
+ struct stat st;
+ if (stat(LOCK_PATH, &st) != 0) {
+ fd = open(LOCK_PATH, O_WRONLY|O_CREAT, 0664);
+ if (fd >= 0)
+ close(fd);
+ }
+ } else
+ unlink(LOCK_PATH);
+
+ rf_lock_active = on;
+}
+
+
+static void we_have_seen_network(unsigned int mcc, unsigned int mnc)
+{
+ /* ignore our own network */
+ if (mcc == OUR_MCC && mnc == OUR_MNC)
+ return;
+
+ /* update timestamp at which we have last seen the network */
+ last_network_seen = time(NULL);
+ bts_rf_lock(1);
+}
+
+static int network_long_ago()
+{
+ time_t now = time(NULL);
+
+ if (now - last_network_seen > MIN_NO_NET_SECS)
+ return 1;
+
+ return 0;
+}
+
+static void rf_lock_timer_check()
+{
+ if (network_long_ago())
+ bts_rf_lock(0);
+ else
+ bts_rf_lock(1);
+}
+
+/* OPERATOR QUEUE */
+
+static LLIST_HEAD(opq);
+
+struct opq_entry {
+ struct llist_head list;
+ char opname_num[32];
+};
+
+static void *opq_ctx = NULL;
+
+static void opq_enqueue(const char *opname_num)
+{
+ struct opq_entry *e = talloc_zero(opq_ctx, struct opq_entry);
+ unsigned int mcc = 0, mnc = 0;
+
+ syslog(LOG_DEBUG, "OPQ: Adding operator `%s'\n", opname_num);
+ strncpy(e->opname_num, opname_num, sizeof(e->opname_num));
+ llist_add_tail(&e->list, &opq);
+
+ sscanf(opname_num, "%03u%02u", &mcc, &mnc);
+ we_have_seen_network(mcc, mnc);
+}
+
+static void opq_next_operator(struct lgsm_handle *lgsmh)
+{
+ struct opq_entry *e;
+
+ if (llist_empty(&opq)) {
+ syslog(LOG_DEBUG, "OPQ: No more operators in queue, re-scanning\n");
+ lgsm_opers_get(lgsmh);
+ return;
+ }
+
+ e = llist_entry(opq.next, struct opq_entry, list);
+ syslog(LOG_DEBUG, "OPQ: Selectiong Operator %s\n", e->opname_num);
+ llist_del(&e->list);
+ lgsm_netreg_register(lgsmh, e->opname_num);
+ talloc_free(e);
+}
+
+
+
+
+/* this is the handler for receiving passthrough responses */
+static int pt_msghandler(struct lgsm_handle *lh, struct gsmd_msg_hdr *gmh)
+{
+ char *payload = (char *)gmh + sizeof(*gmh);
+ printf("RSTR=`%s'\n", payload);
+ return 0;
+}
+
+/* this is the handler for responses to network/operator commands */
+static int net_msghandler(struct lgsm_handle *lh, struct gsmd_msg_hdr *gmh)
+{
+ const struct gsmd_signal_quality *sq = (struct gsmd_signal_quality *)
+ ((void *) gmh + sizeof(*gmh));
+ const char *oper = (char *) gmh + sizeof(*gmh);
+ const struct gsmd_msg_oper *opers = (struct gsmd_msg_oper *)
+ ((void *) gmh + sizeof(*gmh));
+ const struct gsmd_own_number *num = (struct gsmd_own_number *)
+ ((void *) gmh + sizeof(*gmh));
+ const struct gsmd_voicemail *vmail = (struct gsmd_voicemail *)
+ ((void *) gmh + sizeof(*gmh));
+ enum gsmd_netreg_state state = *(enum gsmd_netreg_state *) gmh->data;
+ int result = *(int *) gmh->data;
+ static const char *oper_stat[] = {
+ [GSMD_OPER_UNKNOWN] = "of unknown status",
+ [GSMD_OPER_AVAILABLE] = "available",
+ [GSMD_OPER_CURRENT] = "our current operator",
+ [GSMD_OPER_FORBIDDEN] = "forbidden",
+ };
+ static const char *srvname[] = {
+ [GSMD_SERVICE_ASYNC_MODEM] = "asynchronous modem",
+ [GSMD_SERVICE_SYNC_MODEM] = "synchronous modem",
+ [GSMD_SERVICE_PAD_ACCESS] = "PAD Access (asynchronous)",
+ [GSMD_SERVICE_PACKET_ACCESS] = "Packet Access (synchronous)",
+ [GSMD_SERVICE_VOICE] = "voice",
+ [GSMD_SERVICE_FAX] = "fax",
+ };
+
+ switch (gmh->msg_subtype) {
+ case GSMD_NETWORK_SIGQ_GET:
+ if (sq->rssi == 99)
+ printf("Signal undetectable\n");
+ else
+ printf("Signal quality %i dBm\n", -113 + sq->rssi * 2);
+ if (sq->ber == 99)
+ printf("Error rate undetectable\n");
+ else
+ printf("Bit error rate %i\n", sq->ber);
+ pending_responses --;
+ break;
+ case GSMD_NETWORK_OPER_GET:
+ case GSMD_NETWORK_OPER_N_GET:
+ if (oper[0])
+ printf("Our current operator is %s\n", oper);
+ else
+ printf("No current operator\n");
+ pending_responses --;
+ break;
+ case GSMD_NETWORK_OPER_LIST:
+ for (; !opers->is_last; opers ++) {
+ syslog(LOG_INFO, "OPER: %8.*s %16.*s, %.*s for short, is %s\n",
+ sizeof(opers->opname_num),
+ opers->opname_num,
+ sizeof(opers->opname_longalpha),
+ opers->opname_longalpha,
+ sizeof(opers->opname_shortalpha),
+ opers->opname_shortalpha,
+ oper_stat[opers->stat]);
+ opq_enqueue(opers->opname_num);
+ }
+ opq_next_operator(lh);
+ pending_responses --;
+ break;
+ case GSMD_NETWORK_GET_NUMBER:
+ printf("\t%s\t%10s%s%s%s\n", num->addr.number, num->name,
+ (num->service == GSMD_SERVICE_UNKNOWN) ?
+ "" : " related to ",
+ (num->service == GSMD_SERVICE_UNKNOWN) ?
+ "" : srvname[num->service],
+ (num->service == GSMD_SERVICE_UNKNOWN) ?
+ "" : " services");
+ pending_responses --;
+ break;
+ case GSMD_NETWORK_VMAIL_SET:
+ if (result)
+ printf("Set voicemail error %i\n", result);
+ else
+ printf("Set voicemail OK \n");
+ pending_responses --;
+ break;
+ case GSMD_NETWORK_VMAIL_GET:
+ if(vmail->addr.number)
+ printf ("voicemail number is %s \n",vmail->addr.number);
+ pending_responses --;
+ break;
+ case GSMD_NETWORK_QUERY_REG:
+ switch (state) {
+ case GSMD_NETREG_UNREG:
+ printf("not searching for network \n");
+ break;
+ case GSMD_NETREG_REG_HOME:
+ printf("registered (home network) \n");
+ break;
+ case GSMD_NETREG_UNREG_BUSY:
+ printf("searching for network \n");
+ break;
+ case GSMD_NETREG_DENIED:
+ printf("registration denied \n");
+ break;
+ case GSMD_NETREG_REG_ROAMING:
+ printf("registered (roaming) \n");
+ break;
+ default:
+ break;
+ }
+ pending_responses --;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int phone_msghandler(struct lgsm_handle *lh, struct gsmd_msg_hdr *gmh)
+{
+ char *payload = (char *)gmh + sizeof(*gmh);
+ int *intresult = (void *)gmh + sizeof(*gmh);
+ const struct gsmd_battery_charge *bc = (struct gsmd_battery_charge *)
+ ((void *) gmh + sizeof(*gmh));
+
+ switch (gmh->msg_subtype) {
+ case GSMD_PHONE_GET_IMSI:
+ printf("imsi <%s>\n", payload);
+ break;
+ case GSMD_PHONE_GET_MANUF:
+ printf("manufacturer: %s\n", payload);
+ break;
+ case GSMD_PHONE_GET_MODEL:
+ printf("model: %s\n", payload);
+ break;
+ case GSMD_PHONE_GET_REVISION:
+ printf("revision: %s\n", payload);
+ break;
+ case GSMD_PHONE_GET_SERIAL:
+ printf("serial: %s\n", payload);
+ break;
+ case GSMD_PHONE_POWERUP:
+ if (*intresult)
+ printf("Modem power-up failed: %i\n", *intresult);
+ else
+ printf("Modem powered-up okay\n");
+ break;
+ case GSMD_PHONE_POWERDOWN:
+ if (*intresult)
+ printf("Modem power-down failed: %i\n", *intresult);
+ else
+ printf("Modem down\n");
+ break;
+ case GSMD_PHONE_POWER_STATUS:
+ printf("Antenna Status: %s\n", payload);
+ break;
+ case GSMD_PHONE_GET_BATTERY:
+ printf("<BCS>: %d <BCL>: %d \n", bc->bcs, bc->bcl);
+ break;
+ case GSMD_PHONE_VIB_ENABLE:
+ if(*intresult)
+ printf("Vibrator enable failed: %i\n", *intresult);
+ else
+ printf("Vibrator enabled\n");
+ break;
+ case GSMD_PHONE_VIB_DISABLE:
+ if(*intresult)
+ printf("Vibrator disable failed: %i\n", *intresult);
+ else
+ printf("VIbrator disabled\n");
+ break;
+ default:
+ return -EINVAL;
+ }
+ pending_responses --;
+ return 0;
+}
+
+static const struct msghandler_s {
+ int type;
+ lgsm_msg_handler *fn;
+} msghandlers[] = {
+ { GSMD_MSG_PASSTHROUGH, pt_msghandler },
+ { GSMD_MSG_NETWORK, net_msghandler },
+ { GSMD_MSG_PHONE, phone_msghandler },
+
+ { 0, 0 }
+};
+
+int celllog_main(struct lgsm_handle *lgsmh)
+{
+ int rc;
+ char buf[STDIN_BUF_SIZE+1];
+ fd_set readset;
+ char *ptr, *fcomma, *lcomma;
+ int gsm_fd = lgsm_fd(lgsmh);
+ const struct msghandler_s *hndl;
+
+ for (hndl = msghandlers; hndl->fn; hndl ++)
+ lgsm_register_handler(lgsmh, hndl->type, hndl->fn);
+
+ fcntl(gsm_fd, F_SETFD, O_NONBLOCK);
+ FD_ZERO(&readset);
+
+ struct timeval tv = { .tv_sec = 30 };
+
+ while (1) {
+ fd_set readset;
+ FD_SET(gsm_fd, &readset);
+
+ rc = select(gsm_fd+1, &readset, NULL, NULL, &tv);
+ if (rc < 0)
+ break;
+
+ /* Timeout: Iterate to next operator */
+ if (rc == 0) {
+ opq_next_operator(lgsmh);
+ tv.tv_sec = 30;
+ rf_lock_timer_check();
+ }
+
+ if (FD_ISSET(gsm_fd, &readset)) {
+ /* we've received something on the gsmd socket, pass it
+ * on to the library */
+ rc = read(gsm_fd, buf, sizeof(buf));
+ if (rc <= 0) {
+ syslog(LOG_ERR, "ERROR reading from gsm_fd\n");
+ break;
+ }
+ rc = lgsm_handle_packet(lgsmh, buf, rc);
+ if (rc < 0)
+ syslog(LOG_ERR, "ERROR processing packet: %d(%s)\n", rc, strerror(-rc));
+ }
+ fflush(stdout);
+ }
+ return 0;
+}
+
+static int cinfo_handler(struct lgsm_handle *lh, int evt, struct gsmd_evt_auxdata *aux)
+{
+ syslog(LOG_INFO, "EVENT: Cell Info: %03u-%03u-%04x-%04x @ %04u (%02u)\n",
+ aux->u.cell_info.mcc, aux->u.cell_info.mnc, aux->u.cell_info.lac,
+ aux->u.cell_info.ci, aux->u.cell_info.arfcn, aux->u.cell_info.rxlev);
+ we_have_seen_network(aux->u.cell_info.mcc, aux->u.cell_info.mnc);
+ return 0;
+}
+
+
+int main(int argc, char **argv)
+{
+ static struct lgsm_handle *lgsmh;
+ printf("cell_log - (C) 2012 by Harald Welte <laforge@gnumonks.org>.\n"
+ "This program is Free Software and has ABSOLUTELY NO WARRANTY\n\n");
+
+ openlog("cell_log", 0, LOG_LOCAL0);
+
+ lgsmh = lgsm_init(LGSMD_DEVICE_GSMD);
+ if (!lgsmh) {
+ fprintf(stderr, "Can't connect to gsmd\n");
+ exit(1);
+ }
+
+ lgsm_evt_handler_register(lgsmh, GSMD_EVT_CELLINFO, &cinfo_handler);
+ we_have_seen_network(23, 42);
+
+ celllog_main(lgsmh);
+
+ exit(0);
+}
personal git repositories of Harald Welte. Your mileage may vary