From bf9b037645a5943e3ba0220be55f7f875445bd5a Mon Sep 17 00:00:00 2001 From: laforge Date: Sun, 22 Oct 2006 14:05:53 +0000 Subject: some further gsmd/libgsmd work git-svn-id: http://svn.openmoko.org/trunk/src/target/gsm@96 99fdad57-331a-0410-800a-d7fa5415bdb3 --- README.txt | 22 +++++++++ doc/functions.txt | 51 +++++++++++++++++++ include/gsmd/event.h | 1 + include/gsmd/usock.h | 53 ++++++++++++-------- src/gsmd/gsmd.c | 2 +- src/gsmd/select.c | 4 +- src/gsmd/unsolicited.c | 100 +++++++++++++++++++++++++++++--------- src/gsmd/usock.c | 95 ++++++++++++++++++++++++++++-------- src/libgsmd/lgsm_internals.h | 9 ++++ src/libgsmd/libgsmd.c | 45 ++++++++++++++++- src/libgsmd/libgsmd_passthrough.c | 65 +++++++++++++++++++++++++ src/util/Makefile.am | 2 +- src/util/libgsmd-tool.c | 45 ++++++++++++++++- src/util/shell.c | 25 ++++++++++ 14 files changed, 449 insertions(+), 70 deletions(-) create mode 100644 doc/functions.txt create mode 100644 src/libgsmd/libgsmd_passthrough.c create mode 100644 src/util/shell.c 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 + +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 +#include +#include +#include +#include + +#include + +#include +#include + +#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 +#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 +#include + +#include + +#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); + } +} -- cgit v1.2.3