summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.txt22
-rw-r--r--doc/functions.txt51
-rw-r--r--include/gsmd/event.h1
-rw-r--r--include/gsmd/usock.h53
-rw-r--r--src/gsmd/gsmd.c2
-rw-r--r--src/gsmd/select.c4
-rw-r--r--src/gsmd/unsolicited.c100
-rw-r--r--src/gsmd/usock.c95
-rw-r--r--src/libgsmd/lgsm_internals.h9
-rw-r--r--src/libgsmd/libgsmd.c45
-rw-r--r--src/libgsmd/libgsmd_passthrough.c65
-rw-r--r--src/util/Makefile.am2
-rw-r--r--src/util/libgsmd-tool.c45
-rw-r--r--src/util/shell.c25
14 files changed, 449 insertions, 70 deletions
diff --git a/README.txt b/README.txt
index 5ea8894..22988fe 100644
--- a/README.txt
+++ b/README.txt
@@ -2,13 +2,35 @@
1. GSMD api towards libgsmd
- provides api for other processes to interact with GSM subsystem
+ - is not documented and subject to change
2. GSMD api towards vendor-specific plugins
- implement vendor-specific AT commands
+ - is not documented and will initially only support TI
+ - later, a Motorola plugin is planned.
3. libgsmd api towards applications
- wraps GSMD-libgsmd api into C functions that can be used by applications
+ - will be documented and is supposed to be stable.
+3.1. Events
+
+The application registers callback handlers for events. libgsmd can call these callback
+handlers at any given time. Events include "incoming call", "remote end hangup", ...
+
+3.2. Commands
+
+Commands have the form of command-reply. Usually they will be performed
+synchronously, i.e. the the caller will be blocked until a response to the command has been
+received.
+
+If this behaviour is not desired, a completion handler callback function can be
+registered. In this case, the function call will return immediately after the
+command has been sent to gsmd. Further incoming packets on the gsmd socket
+will be handled to libgsmd by calling lgsm_handle_packet(). If one such packet is the
+response to a currently-executing command, the completion handler will be
+called from within lgsm_handle_packet(). Matching of responses to requests is done by
+assigning a unique id to each request. gsmd responses will have a matching id.
code flow in gsmd:
diff --git a/doc/functions.txt b/doc/functions.txt
new file mode 100644
index 0000000..638d216
--- /dev/null
+++ b/doc/functions.txt
@@ -0,0 +1,51 @@
+0. general
+
+commands
+- power up/down phone
+- operator selection
+- get list of operators
+- get operator name / id list
+- get (and edit) preferred operator list
+- get manufacturer/device/serial info
+- get IMSI
+- obtain network registration status
+
+
+events
+- some pin required
+- network registration status
+- time zone update
+
+
+1. voice calls
+
+commands (request/response)
+- dial outgoing call
+- send dtmf digit (during call)
+- hang up (incoming/outgoing)
+- accept currently pending incoming call
+- enable/disable clip
+- enable/disable colp
+- enable/disable clir
+- call forwarding
+- call deflection
+
+events
+- incoming call
+- clip
+- colp
+- call waiting
+-
+
+2. SMS
+
+commands
+- send outgoing message
+
+3. data calls
+
+TBD
+
+4. GPRS
+
+TBD
diff --git a/include/gsmd/event.h b/include/gsmd/event.h
index 4500af9..c6f2986 100644
--- a/include/gsmd/event.h
+++ b/include/gsmd/event.h
@@ -13,6 +13,7 @@ enum gsmd_events {
GSMD_EVT_OUT_STATUS = 8, /* Outgoing call status */
GSMD_EVT_OUT_COLP = 9, /* Outgoing COLP */
GSMD_EVT_CALL_WAIT = 10, /* Call Waiting */
+ GSMD_EVT_TIMEZONE = 11, /* Timezone change */
__NUM_GSMD_EVT
};
diff --git a/include/gsmd/usock.h b/include/gsmd/usock.h
index f00ffc4..eced10e 100644
--- a/include/gsmd/usock.h
+++ b/include/gsmd/usock.h
@@ -11,28 +11,17 @@
#define GSMD_MSGSIZE_MAX 4096
-enum gsmd_prot_cmd {
- GSMD_PCMD_NONE,
- GSMD_PCMD_EVT_SUBSCRIPTIONS, /* alter event subscriptions */
- GSMD_PCMD_PASSTHROUGH, /* transparent atcmd passthrough */
-};
-
-enum gsmd_pcmd_result {
- GSMD_PCMD_OK = 0,
- GSMD_PCMD_ERR_UNSPEC = 0xff,
-};
-
-struct gsmd_prot_hdr {
- u_int16_t cmd;
- u_int8_t result;
- u_int8_t version;
-} __attribute__((packed));
-
-
enum gsmd_msg_type {
GSMD_MSG_NONE = 0,
GSMD_MSG_EVENT = 1,
GSMD_MSG_PASSTHROUGH = 2,
+ GSMD_MSG_VOICECALL = 3,
+ GSMD_MSG_DATACALL = 4,
+ GSMD_MSG_PHONEBOOK = 5,
+ GSMD_MSG_NETWORK = 6,
+ GSMD_MSG_PHONE = 7,
+ GSMD_MSG_PIN = 8,
+ __NUM_GSMD_MSGS
};
enum gsmd_passthrough_type {
@@ -41,6 +30,27 @@ enum gsmd_passthrough_type {
GSMD_PASSTHROUGH_RESP = 2,
};
+enum gsmd_event_type {
+ GSMD_EVENT_NONE = 0,
+ GSMD_EVENT_SUBSCRIPTIONS= 1,
+ GSMD_EVENT_HAPPENED = 2,
+};
+
+enum gsmd_msg_voicecall_type {
+ GSMD_VOICECALL_DIAL = 1,
+ GSMD_VOICECALL_HANGUP = 2,
+};
+
+/* Handset / MT related commands */
+enum gsmd_msg_phone_type {
+ GSMD_PHONE_VOLUME = 1,
+ GSMD_PHONE_VIBRATOR = 2,
+};
+
+enum gsmd_msg_pin_type {
+ GSMD_PIN_INPUT = 1,
+};
+
/* Length from 3GPP TS 04.08, Clause 10.5.4.7 */
#define GSMD_ADDR_MAXLEN 13
@@ -72,6 +82,9 @@ struct gsmd_evt_auxdata {
u_int16_t lac;
u_int16_t ci;
} netreg;
+ struct {
+ u_int8_t tz;
+ } timezone;
} u;
} __attribute__((packed));
@@ -79,7 +92,9 @@ struct gsmd_msg_hdr {
u_int8_t version;
u_int8_t msg_type;
u_int8_t msg_subtype;
- u_int8_t len;
+ u_int8_t _pad;
+ u_int16_t id;
+ u_int16_t len;
} __attribute__((packed));
diff --git a/src/gsmd/gsmd.c b/src/gsmd/gsmd.c
index b617eb1..9267977 100644
--- a/src/gsmd/gsmd.c
+++ b/src/gsmd/gsmd.c
@@ -51,7 +51,7 @@ static int gsmd_initsettings(struct gsmd *gsmd)
if (rc < 0)
return rc;
- cmd = atcmd_fill("+CRC=1;+CREG=2;+CMEE=2;+CLIP=1;+COLP=1", 255, &gsmd_test_atcb, NULL);
+ cmd = atcmd_fill("+CRC=1;+CREG=2;+CMEE=2;+CLIP=1;+COLP=1;+CTZR=1", 255, &gsmd_test_atcb, NULL);
return atcmd_submit(gsmd, cmd);
}
diff --git a/src/gsmd/select.c b/src/gsmd/select.c
index 62dc4c2..fc9647f 100644
--- a/src/gsmd/select.c
+++ b/src/gsmd/select.c
@@ -53,7 +53,7 @@ void gsmd_unregister_fd(struct gsmd_fd *fd)
int gsmd_select_main()
{
- struct gsmd_fd *ufd;
+ struct gsmd_fd *ufd, *ufd2;
fd_set readset, writeset, exceptset;
int i;
@@ -76,7 +76,7 @@ int gsmd_select_main()
i = select(maxfd+1, &readset, &writeset, &exceptset, NULL);
if (i > 0) {
/* call registered callback functions */
- llist_for_each_entry(ufd, &gsmd_fds, list) {
+ llist_for_each_entry_safe(ufd, ufd2, &gsmd_fds, list) {
int flags = 0;
if (FD_ISSET(ufd->fd, &readset))
diff --git a/src/gsmd/unsolicited.c b/src/gsmd/unsolicited.c
index 2c7fddf..cb1bce5 100644
--- a/src/gsmd/unsolicited.c
+++ b/src/gsmd/unsolicited.c
@@ -59,7 +59,7 @@ static int usock_evt_send(struct gsmd *gsmd, struct gsmd_ucmd *ucmd, u_int32_t e
return num_sent;
}
-static int ring_parse(const char *buf, int len, const char *param,
+static int ring_parse(char *buf, int len, const char *param,
struct gsmd *gsmd)
{
/* FIXME: generate ring event */
@@ -76,7 +76,7 @@ static int ring_parse(const char *buf, int len, const char *param,
return usock_evt_send(gsmd, ucmd, GSMD_EVT_IN_CALL);
}
-static int cring_parse(const char *buf, int len, const char *param, struct gsmd *gsmd)
+static int cring_parse(char *buf, int len, const char *param, struct gsmd *gsmd)
{
struct gsmd_ucmd *ucmd = build_event(GSMD_MSG_EVENT, GSMD_EVT_IN_CALL,
sizeof(struct gsmd_evt_auxdata));
@@ -108,7 +108,7 @@ static int cring_parse(const char *buf, int len, const char *param, struct gsmd
}
/* Chapter 7.2, network registration */
-static int creg_parse(const char *buf, int len, const char *param,
+static int creg_parse(char *buf, int len, const char *param,
struct gsmd *gsmd)
{
const char *comma = strchr(param, ',');
@@ -121,25 +121,54 @@ static int creg_parse(const char *buf, int len, const char *param,
aux->u.netreg.state = atoi(param);
if (comma) {
- /* FIXME: we also have location area code and cell id to parse (hex) */
+ /* we also have location area code and cell id to parse (hex) */
+ aux->u.netreg.lac = atoi(comma+1);
+ comma = strchr(comma+1, ',');
+ if (!comma)
+ return -EINVAL;
+ aux->u.netreg.ci = atoi(comma+1);
}
return usock_evt_send(gsmd, ucmd, GSMD_EVT_NETREG);
}
/* Chapter 7.11, call waiting */
-static int ccwa_parse(const char *buf, int len, const char *param,
+static int ccwa_parse(char *buf, int len, const char *param,
struct gsmd *gsmd)
{
- const char *number;
- u_int8_t type, class;
+ const char *token;
+ unsigned int type;
+ struct gsmd_ucmd *ucmd = build_event(GSMD_MSG_EVENT, GSMD_EVT_CALL_WAIT,
+ sizeof(struct gsmd_addr));
+ struct gsmd_addr *gaddr;
- /* FIXME: parse */
- return 0;
+ if (!ucmd)
+ return -ENOMEM;
+
+ gaddr = (struct gsmd_addr *) ucmd->buf;
+ memset(gaddr, 0, sizeof(*gaddr));
+
+ /* parse address (phone number) */
+ token = strtok(buf, ",");
+ if (!token)
+ return -EINVAL;
+ strncpy(gaddr->number, token, GSMD_ADDR_MAXLEN);
+
+ /* parse type */
+ token = strtok(NULL, ",");
+ if (!token)
+ return -EINVAL;
+ type = atoi(token) & 0xff;
+ gaddr->type = type;
+
+ /* FIXME: parse class */
+ token = strtok(NULL, ",");
+
+ return usock_evt_send(gsmd, ucmd, GSMD_EVT_CALL_WAIT);
}
/* Chapter 7.14, unstructured supplementary service data */
-static int cusd_parse(const char *buf, int len, const char *param,
+static int cusd_parse(char *buf, int len, const char *param,
struct gsmd *gsmd)
{
/* FIXME: parse */
@@ -147,7 +176,7 @@ static int cusd_parse(const char *buf, int len, const char *param,
}
/* Chapter 7.15, advise of charge */
-static int cccm_parse(const char *buf, int len, const char *param,
+static int cccm_parse(char *buf, int len, const char *param,
struct gsmd *gsmd)
{
/* FIXME: parse */
@@ -155,7 +184,7 @@ static int cccm_parse(const char *buf, int len, const char *param,
}
/* Chapter 10.1.13, GPRS event reporting */
-static int cgev_parse(const char *buf, int len, const char *param,
+static int cgev_parse(char *buf, int len, const char *param,
struct gsmd *gsmd)
{
/* FIXME: parse */
@@ -163,7 +192,7 @@ static int cgev_parse(const char *buf, int len, const char *param,
}
/* Chapter 10.1.14, GPRS network registration status */
-static int cgreg_parse(const char *buf, int len, const char *param,
+static int cgreg_parse(char *buf, int len, const char *param,
struct gsmd *gsmd)
{
/* FIXME: parse */
@@ -171,7 +200,7 @@ static int cgreg_parse(const char *buf, int len, const char *param,
}
/* Chapter 7.6, calling line identification presentation */
-static int clip_parse(const char *buf, int len, const char *param,
+static int clip_parse(char *buf, int len, const char *param,
struct gsmd *gsmd)
{
struct gsmd_ucmd *ucmd = build_event(GSMD_MSG_EVENT, GSMD_EVT_IN_CLIP,
@@ -197,7 +226,7 @@ static int clip_parse(const char *buf, int len, const char *param,
}
/* Chapter 7.9, calling line identification presentation */
-static int colp_parse(const char *buf, int len, const char *param,
+static int colp_parse(char *buf, int len, const char *param,
struct gsmd *gsmd)
{
struct gsmd_ucmd *ucmd = build_event(GSMD_MSG_EVENT, GSMD_EVT_OUT_COLP,
@@ -222,22 +251,47 @@ static int colp_parse(const char *buf, int len, const char *param,
return usock_evt_send(gsmd, ucmd, GSMD_EVT_OUT_COLP);
}
+static int ctzv_parse(char *buf, int len, const char *param,
+ struct gsmd *gsmd)
+{
+ struct gsmd_ucmd *ucmd = build_event(GSMD_MSG_EVENT, GSMD_EVT_TIMEZONE,
+ sizeof(struct gsmd_evt_auxdata));
+ struct gsmd_evt_auxdata *aux;
+ int tz;
+
+ if (!ucmd)
+ return -ENOMEM;
+
+ aux = (struct gsmd_evt_auxdata *) ucmd->buf;
+
+ /* timezones are expressed in quarters of hours +/- GMT (-48...+48) */
+ tz = atoi(param);
+
+ if (tz < -48 || tz > 48)
+ return -EINVAL;
+
+ aux->u.timezone.tz = tz;
+
+ return usock_evt_send(gsmd, ucmd, GSMD_EVT_TIMEZONE);
+}
+
struct gsmd_unsolicit {
const char *prefix;
- int (*parse)(const char *unsol, int len, const char *param, struct gsmd *gsmd);
+ int (*parse)(char *unsol, int len, const char *param, struct gsmd *gsmd);
};
static const struct gsmd_unsolicit gsm0707_unsolicit[] = {
{ "RING", &ring_parse },
{ "+CRING", &cring_parse },
- { "+CREG", &creg_parse },
- { "+CCWA", &ccwa_parse },
- { "+CUSD", &cusd_parse },
- { "+CCCM", &cccm_parse },
- { "+CGEV", &cgev_parse },
- { "+CGREG", &cgreg_parse },
+ { "+CREG", &creg_parse }, /* Network registration */
+ { "+CCWA", &ccwa_parse }, /* Call waiting */
+ { "+CUSD", &cusd_parse }, /* Unstructured supplementary data */
+ { "+CCCM", &cccm_parse }, /* Advice of Charge */
+ { "+CGEV", &cgev_parse }, /* GPRS Event */
+ { "+CGREG", &cgreg_parse }, /* GPRS Registration */
{ "+CLIP", &clip_parse },
{ "+COLP", &colp_parse },
+ { "+CTZV", &ctzv_parse }, /* Timezone */
/*
{ "+CKEV", &ckev_parse },
{ "+CDEV", &cdev_parse },
@@ -250,7 +304,7 @@ static const struct gsmd_unsolicit gsm0707_unsolicit[] = {
};
/* called by midlevel parser if a response seems unsolicited */
-int unsolicited_parse(struct gsmd *g, const char *buf, int len, const char *param)
+int unsolicited_parse(struct gsmd *g, char *buf, int len, const char *param)
{
int i;
diff --git a/src/gsmd/usock.c b/src/gsmd/usock.c
index 7c90c5d..925be75 100644
--- a/src/gsmd/usock.c
+++ b/src/gsmd/usock.c
@@ -39,32 +39,62 @@ static int usock_cmd_cb(struct gsmd_atcmd *cmd, void *ctx)
return 0;
}
-static int usock_rcv_pcmd(struct gsmd_user *gu, char *buf, int len)
+typedef int usock_msg_handler(struct gsmd_user *gu, struct gsmd_msg_hdr *gph, int len);
+
+static int usock_rcv_passthrough(struct gsmd_user *gu, struct gsmd_msg_hdr *gph, int len)
{
- struct gsmd_msg_hdr *gph = (struct gsmd_msg_hdr *)buf;
+ struct gsmd_atcmd *cmd;
+ cmd = atcmd_fill((char *)gph+sizeof(*gph), 255, &usock_cmd_cb, gu);
+ if (!cmd)
+ return -ENOMEM;
- if (gph->version != GSMD_PROTO_VERSION)
+ return atcmd_submit(gu->gsmd, cmd);
+}
+
+static int usock_rcv_event(struct gsmd_user *gu, struct gsmd_msg_hdr *gph, int len)
+{
+ u_int32_t *evtmask = (u_int32_t *) ((char *)gph + sizeof(*gph));
+
+ if (len < sizeof(*gph) + sizeof(u_int32_t))
return -EINVAL;
- switch (gph->msg_type) {
- case GSMD_MSG_PASSTHROUGH:
- {
- struct gsmd_atcmd *cmd;
- cmd = atcmd_fill((char *)gph+sizeof(*gph),
- 255, &usock_cmd_cb, gu);
- if (!cmd)
- return -ENOMEM;
- return atcmd_submit(gu->gsmd, cmd);
- }
+ if (gph->msg_subtype != GSMD_EVENT_SUBSCRIPTIONS)
+ return -EINVAL;
+
+ gu->subscriptions = *evtmask;
+}
+
+static int usock_rcv_voicecall(struct gsmd_user *gu, struct gsmd_msg_hdr *gph, int len)
+{
+ struct gsmd_atcmd *cmd;
+
+ switch (gph->msg_subtype) {
+ case GSMD_VOICECALL_DIAL:
+ /* FIXME */
break;
- case GSMD_PCMD_EVT_SUBSCRIPTIONS:
- {
- u_int32_t *evtmask = (u_int32_t *) (buf + sizeof(*gph));
- if (len < sizeof(*gph) + sizeof(u_int32_t))
- return -EINVAL;
+ case GSMD_VOICECALL_HANGUP:
+ cmd = atcmd_fill("ATH0", 5, &usock_cmd_cb, gu);
+ break;
+ default:
+ return -EINVAL;
+ }
- gu->subscriptions = *evtmask;
- }
+ return 0;
+}
+
+#define GSMD_PIN_MAXLEN 16
+
+static int usock_rcv_pin(struct gsmd_user *gu, struct gsmd_msg_hdr *gph, int len)
+{
+ u_int8_t *pin = (u_int8_t *)gph + sizeof(*gph);
+ int pin_len = len - sizeof(*gph);
+ char pinbuf[GSMD_PIN_MAXLEN + 11]; /* `AT+CPIN=""\0' */
+
+ snprintf(pinbuf, sizeof(pinbuf), "AT+CPIN=\"%s\"", pin);
+
+ switch (gph->msg_subtype) {
+ case GSMD_PIN_INPUT:
+ /* FIXME */
break;
default:
return -EINVAL;
@@ -73,6 +103,31 @@ static int usock_rcv_pcmd(struct gsmd_user *gu, char *buf, int len)
return 0;
}
+static usock_msg_handler *pcmd_type_handlers[] = {
+ [GSMD_MSG_PASSTHROUGH] = &usock_rcv_passthrough,
+ [GSMD_MSG_EVENT] = &usock_rcv_event,
+ [GSMD_MSG_VOICECALL] = &usock_rcv_voicecall,
+ [GSMD_MSG_PIN] = &usock_rcv_pin,
+};
+
+static int usock_rcv_pcmd(struct gsmd_user *gu, char *buf, int len)
+{
+ struct gsmd_msg_hdr *gph = (struct gsmd_msg_hdr *)buf;
+ usock_msg_handler *umh;
+
+ if (gph->version != GSMD_PROTO_VERSION)
+ return -EINVAL;
+
+ if (gph->msg_type >= ARRAY_SIZE(pcmd_type_handlers))
+ return -EINVAL;
+
+ umh = pcmd_type_handlers[gph->msg_type];
+ if (!umh)
+ return -EINVAL;
+
+ return umh(gu, gph, len);
+}
+
/* callback for read/write on client (libgsmd) socket */
static int gsmd_usock_user_cb(int fd, unsigned int what, void *data)
{
diff --git a/src/libgsmd/lgsm_internals.h b/src/libgsmd/lgsm_internals.h
index 66fd5fe..0601959 100644
--- a/src/libgsmd/lgsm_internals.h
+++ b/src/libgsmd/lgsm_internals.h
@@ -1,4 +1,13 @@
+#ifndef _LGSM_INTERNALS_H
+#define _LGSM_INTERNALS_H
+
+#include <gsmd/usock.h>
+
+typedef int lgsm_msg_handler(struct lgsm_handle *lh, struct gsmd_msg_hdr *gmh);
struct lgsm_handle {
int fd;
+ lgsm_msg_handler *handler[__NUM_GSMD_MSGS];
};
+
+#endif /* _LGSM_INTERNALS_H */
diff --git a/src/libgsmd/libgsmd.c b/src/libgsmd/libgsmd.c
index 77b8499..104a8b3 100644
--- a/src/libgsmd/libgsmd.c
+++ b/src/libgsmd/libgsmd.c
@@ -36,7 +36,6 @@ static int lgsm_get_packet(struct lgsm_handle *lh)
return 0;
}
-
static int lgsm_open_backend(struct lgsm_handle *lh, const char *device)
{
int rc;
@@ -52,7 +51,6 @@ static int lgsm_open_backend(struct lgsm_handle *lh, const char *device)
memset(&sun, 0, sizeof(sun));
sun.sun_family = AF_UNIX;
memcpy(sun.sun_path, GSMD_UNIX_SOCKET, sizeof(GSMD_UNIX_SOCKET));
- printf("sizeof(GSMD_UNIX_SOCKET) = %u\n", sizeof(GSMD_UNIX_SOCKET));
rc = connect(lh->fd, (struct sockaddr *)&sun, sizeof(sun));
if (rc < 0) {
@@ -66,6 +64,49 @@ static int lgsm_open_backend(struct lgsm_handle *lh, const char *device)
return 0;
}
+/* handle a packet that was received on the gsmd socket */
+int lgsm_handle_packet(struct lgsm_handle *lh, char *buf, int len)
+{
+ struct gsmd_msg_hdr *gmh = (struct gsmd_msg_hdr *)buf;
+ if (len < sizeof(*gmh))
+ return -EINVAL;
+
+ if (len - sizeof(*gmh) < gmh->len)
+ return -EINVAL;
+
+ if (gmh->msg_type >= __NUM_GSMD_MSGS)
+ return -EINVAL;
+
+ return lh->handler[gmh->msg_type](lh, gmh);
+}
+
+/* blocking read and processing of packets until packet matching 'id' is found */
+int lgsm_blocking_wait_packet(struct lgsm_handle *lh, u_int16_t id,
+ struct gsmd_msg_hdr *gmh, int rlen)
+{
+ int rc;
+ fd_set readset;
+
+ FD_ZERO(&readset);
+
+ while (1) {
+ FD_SET(lh->fd, &readset);
+ rc = select(lh->fd+1, &readset, NULL, NULL, NULL);
+ if (rc <= 0)
+ return rc;
+
+ rc = read(lh->fd, (char *)gmh, rlen);
+ if (rc <= 0)
+ return rc;
+
+ if (gmh->id == id) {
+ /* we've found the matching packet, return to calling function */
+ return rc;
+ } else
+ rc = lgsm_handle_packet(lh, (char *)gmh, rc);
+ }
+}
+
int lgsm_fd(struct lgsm_handle *lh)
{
return lh->fd;
diff --git a/src/libgsmd/libgsmd_passthrough.c b/src/libgsmd/libgsmd_passthrough.c
new file mode 100644
index 0000000..45ce066
--- /dev/null
+++ b/src/libgsmd/libgsmd_passthrough.c
@@ -0,0 +1,65 @@
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include <sys/types.h>
+
+#include <gsmd/usock.h>
+#include <libgsmd/libgsmd.h>
+
+#include "lgsm_internals.h"
+
+static u_int16_t next_msg_id;
+
+static int lgsm_send(struct lgsm_handle *lh, struct gsmd_msg_hdr *gmh)
+{
+ gmh->id = next_msg_id++;
+ return send(lh->fd, (char *) gmh, sizeof(*gmh) + gmh->len);
+}
+
+#define PT_BUF_SIZE 1024
+static char passthrough_buf[sizeof(struct gsmd_msg_hdr)+PT_BUF_SIZE];
+static char passthrough_rbuf[sizeof(struct gsmd_msg_hdr)+PT_BUF_SIZE];
+
+int lgsm_passthrough(struct lgsm_handle *lh, const char *tx, char *rx, unsigned int *rx_len)
+{
+ struct gsmd_msg_hdr *gmh = (struct gsmd_msg_hdr *)passthrough_buf;
+ struct gsmd_msg_hdr *rgmh = (struct gsmd_msg_hdr *)passthrough_rbuf;
+ char *tx_buf = (char *)gmh + sizeof(*gmh);
+ char *rx_buf = (char *)rgmh + sizeof(*rgmh);
+ int len = strlen(tx);
+ int rc;
+
+ if (len > PT_BUF_SIZE)
+ return -EINVAL;
+
+ gmh->version = GSMD_PROTO_VERSION;
+ gmh->msg_type = GSMD_MSG_PASSTHROUGH;
+ gmh->msg_subtype = GSMD_PASSTHROUGH_REQUEST;
+ gmh->len = len;
+ strcpy(tx_buf, tx);
+
+ rc = lgsm_send(lh, gmh);
+ if (rc < len+sizeof(*gmh))
+ return rc;
+
+ /* since we synchronously want to wait for a response, we need to _internally_ loop over
+ * incoming packets and call the callbacks for intermediate messages (if applicable) */
+ rc = lgsm_blocking_wait_packet(lh, gmh->id, passthrough_rbuf, sizeof(passthrough_rbuf));
+ if (rc <= 0)
+ return rc;
+
+ if (rc < sizeof(*rgmh))
+ return -EINVAL;
+
+ if (rc < sizeof(*rgmh) + rgmh->len)
+ return -EINVAL;
+
+ /* FIXME: make sure rx_buf is zero-terminated */
+ strcpy(rx, rx_buf);
+ *rx_len = rgmh->len;
+
+ return rx_len;
+}
diff --git a/src/util/Makefile.am b/src/util/Makefile.am
index bb257f5..bec625a 100644
--- a/src/util/Makefile.am
+++ b/src/util/Makefile.am
@@ -3,7 +3,7 @@ AM_CFLAGS = -std=gnu99
bin_PROGRAMS = libgsmd-tool
-libgsmd_tool_SOURCES = libgsmd-tool.c
+libgsmd_tool_SOURCES = libgsmd-tool.c shell.c
libgsmd_tool_LDADD = ../libgsmd/libgsmd.la
libgsmd_tool_LDFLAGS = -dynamic
diff --git a/src/util/libgsmd-tool.c b/src/util/libgsmd-tool.c
index a3da490..e8590c1 100644
--- a/src/util/libgsmd-tool.c
+++ b/src/util/libgsmd-tool.c
@@ -8,13 +8,42 @@
#include <libgsmd/libgsmd.h>
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+#endif
+
static struct lgsm_handle *lgsmh;
static int verbose = 0;
+enum mode_enum {
+ MODE_NONE,
+ MODE_SHELL,
+ MODE_EVENTLOG,
+};
+
+static char *modes[] = {
+ [MODE_NONE] = "",
+ [MODE_SHELL] = "shell",
+ [MODE_EVENTLOG] = "eventlog",
+};
+
+static int parse_mode(char *modestr)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(modes); i++) {
+ if (!strcmp(modes[i], modestr))
+ return i;
+ }
+
+ return -1;
+}
+
static struct option opts[] = {
{ "help", 0, 0, 'h' },
{ "version", 0, 0, 'V' },
{ "verbose", 0, 0, 'v' },
+ { "mode", 1, 0, 'm' },
{ 0, 0, 0, 0 }
};
@@ -28,14 +57,14 @@ static void help(void)
int main(int argc, char **argv)
{
- int rc, i;
+ int rc, i, mode;
printf("libgsm-tool - (C) 2006 by Harald Welte\n"
"This program is Free Software and has ABSOLUTELY NO WARRANTY\n\n");
while (1) {
int c, option_index = 0;
- c = getopt_long(argc, argv, "hVv", opts, &option_index);
+ c = getopt_long(argc, argv, "vVhm:", opts, &option_index);
if (c == -1)
break;
@@ -50,6 +79,13 @@ int main(int argc, char **argv)
help();
exit(0);
break;
+ case 'm':
+ mode = parse_mode(optarg);
+ if (mode < 0) {
+ fprintf(stderr, "unknown/unsupported mode `%s'\n", optarg);
+ exit(2);
+ }
+ break;
}
}
@@ -59,6 +95,11 @@ int main(int argc, char **argv)
exit(1);
}
+ switch (mode) {
+ case MODE_SHELL:
+ shell_main(lgsmh);
+ break;
+ }
exit(0);
}
diff --git a/src/util/shell.c b/src/util/shell.c
new file mode 100644
index 0000000..eb1991d
--- /dev/null
+++ b/src/util/shell.c
@@ -0,0 +1,25 @@
+#include <stdio.h>
+#include <string.h>
+
+#include <libgsmd/libgsmd.h>
+
+#define STDIN_BUF_SIZE 1024
+
+int shell_main(struct lgsmd_handle *lgsmh)
+{
+ int rc;
+ char buf[STDIN_BUF_SIZE+1];
+
+ while (1) {
+ rc = fscanf(stdin, "%s", buf);
+ if (rc == EOF) {
+ printf("EOF\n");
+ return -1;
+ }
+ if (rc <= 0) {
+ printf("NULL\n");
+ continue;
+ }
+ printf("STR=`%s'\n", buf);
+ }
+}
personal git repositories of Harald Welte. Your mileage may vary