summaryrefslogtreecommitdiff
path: root/src/gsmd
diff options
context:
space:
mode:
Diffstat (limited to 'src/gsmd')
-rw-r--r--src/gsmd/atcmd.c75
-rw-r--r--src/gsmd/atcmd.h4
-rw-r--r--src/gsmd/gsmd.c13
-rw-r--r--src/gsmd/gsmd.h11
-rw-r--r--src/gsmd/log.c6
-rw-r--r--src/gsmd/unsolicited.c4
-rw-r--r--src/gsmd/usock.c38
-rw-r--r--src/gsmd/usock.h5
8 files changed, 109 insertions, 47 deletions
diff --git a/src/gsmd/atcmd.c b/src/gsmd/atcmd.c
index 145ade7..2647192 100644
--- a/src/gsmd/atcmd.c
+++ b/src/gsmd/atcmd.c
@@ -101,6 +101,7 @@ static int llparse_byte(struct llparser *llp, char byte)
/* re-set cursor to start of buffer */
llp->cur = llp->buf;
llp->state = LLPARSE_STATE_IDLE;
+ memset(llp->buf, 0, LLPARSE_BUF_SIZE);
}
break;
case LLPARSE_STATE_ERROR:
@@ -151,14 +152,27 @@ static int ml_parse(const char *buf, int len, void *ctx)
{
struct gsmd *g = ctx;
struct gsmd_atcmd *cmd;
- int rc, final = 0;
+ int rc = 0, final = 0;
DEBUGP("buf=`%s'(%d)\n", buf, len);
/* responses come in order, so first response has to be for first
* command we sent, i.e. first entry in list */
cmd = llist_entry(g->busy_atcmds.next, struct gsmd_atcmd, list);
- cmd->resp = buf;
+
+ /* we have to differentiate between the following cases:
+ *
+ * A) an information response ("+whatever: ...")
+ * we just pass it up the callback
+ * B) an unsolicited message ("+whateverelse: ... ")
+ * we call the unsolicited.c handlers
+ * C) a final response ("OK", "+CME ERROR", ...)
+ * in this case, we need to check whether we already sent some
+ * previous data to the callback (information response). If yes,
+ * we do nothing. If no, we need to call the callback.
+ * D) an intermediate response ("CONNECTED", "BUSY", "NO DIALTONE")
+ * TBD
+ */
if (buf[0] == '+') {
/* an extended response */
@@ -169,6 +183,7 @@ static int ml_parse(const char *buf, int len, void *ctx)
return -EINVAL;
}
if (!strncmp(buf+1, "CME ERROR", 9)) {
+ /* Part of Case 'C' */
unsigned long err_nr;
err_nr = strtoul(colon+1, NULL, 10);
DEBUGP("error number %lu\n", err_nr);
@@ -178,6 +193,7 @@ static int ml_parse(const char *buf, int len, void *ctx)
}
if (strncmp(buf, &cmd->buf[2], colon-buf)) {
+ /* Assuming Case 'B' */
DEBUGP("extd reply `%s' to cmd `%s', must be "
"unsolicited\n", buf, &cmd->buf[2]);
colon++;
@@ -186,8 +202,11 @@ static int ml_parse(const char *buf, int len, void *ctx)
rc = unsolicited_parse(g, buf, len, colon);
/* if unsolicited parser didn't handle this 'reply', then we
* need to continue and try harder and see what it is */
- if (rc != -ENOENT)
+ if (rc != -ENOENT) {
+ /* Case 'B' finished */
return rc;
+ }
+ /* contine, not 'B' */
}
if (cmd->buf[2] != '+') {
@@ -196,21 +215,23 @@ static int ml_parse(const char *buf, int len, void *ctx)
}
/* if we survive till here, it's a valid extd response
- * to an extended command */
-
+ * to an extended command and thus Case 'A' */
+
/* FIXME: solve multi-line responses ! */
if (cmd->buflen < len)
len = cmd->buflen;
memcpy(cmd->buf, buf, len);
} else {
-
- /* this is the only non-extended unsolicited return code */
- if (!strcmp(buf, "RING"))
+ if (!strcmp(buf, "RING")) {
+ /* this is the only non-extended unsolicited return
+ * code, part of Case 'B' */
return unsolicited_parse(g, buf, len, NULL);
+ }
if (!strcmp(buf, "ERROR") ||
- ((g->flags & GSMD_FLAG_V0) && cmd->buf[0] == '4')){
+ ((g->flags & GSMD_FLAG_V0) && cmd->buf[0] == '4')) {
+ /* Part of Case 'C' */
DEBUGP("unspecified error\n");
cmd->ret = 4;
final = 1;
@@ -219,6 +240,7 @@ static int ml_parse(const char *buf, int len, void *ctx)
if (!strncmp(buf, "OK", 2)
|| ((g->flags & GSMD_FLAG_V0) && cmd->buf[0] == '0')) {
+ /* Part of Case 'C' */
cmd->ret = 0;
final = 1;
goto final_cb;
@@ -227,32 +249,49 @@ static int ml_parse(const char *buf, int len, void *ctx)
/* FIXME: handling of those special commands in response to
* ATD / ATA */
if (!strncmp(buf, "NO CARRIER", 10)) {
+ /* Part of Case 'D' */
+ goto final_cb;
}
if (!strncmp(buf, "BUSY", 4)) {
+ /* Part of Case 'D' */
+ goto final_cb;
}
}
+ /* we reach here, if we are at an information response that needs to be
+ * passed on */
+
final_cb:
+ /* if we reach here, the final result code of a command has been reached */
+
+
if (cmd->ret != 0)
generate_event_from_cme(g, cmd->ret);
+
+ if (!cmd->cb) {
+ gsmd_log(GSMD_NOTICE, "command without cb!!!\n");
+ } else {
+ if (!final || !cmd->resp) {
+ /* if we reach here, we didn't send any information responses yet */
+ DEBUGP("Calling cmd->cb()\n");
+ cmd->resp = buf;
+ rc = cmd->cb(cmd, cmd->ctx, buf);
+ }
+ }
+
if (final) {
/* remove from list of currently executing cmds */
llist_del(&cmd->list);
+ free(cmd);
/* if we're finished with current commands, but still have pending
* commands: we want to WRITE again */
if (llist_empty(&g->busy_atcmds) && !llist_empty(&g->pending_atcmds))
g->gfd_uart.when |= GSMD_FD_WRITE;
-
- if (!cmd->cb) {
- gsmd_log(GSMD_NOTICE, "command without cb!!!\n");
- return -EINVAL;
- }
- return cmd->cb(cmd, cmd->ctx);
}
- return 0;
+ return rc;
}
/* callback to be called if [virtual] UART has some data for us */
@@ -321,7 +360,7 @@ static int atcmd_select_cb(int fd, unsigned int what, void *data)
struct gsmd_atcmd *atcmd_fill(const char *cmd, int rlen,
- atcmd_cb_t cb, void *ctx)
+ atcmd_cb_t cb, void *ctx, u_int16_t id)
{
int buflen = strlen(cmd);
struct gsmd_atcmd *atcmd;
@@ -334,11 +373,13 @@ struct gsmd_atcmd *atcmd_fill(const char *cmd, int rlen,
return NULL;
atcmd->ctx = ctx;
+ atcmd->id = id;
atcmd->flags = 0;
atcmd->ret = -255;
atcmd->buflen = buflen;
atcmd->buf[buflen-1] = '\0';
atcmd->cb = cb;
+ atcmd->resp = NULL;
strncpy(atcmd->buf, cmd, buflen-1);
return atcmd;
diff --git a/src/gsmd/atcmd.h b/src/gsmd/atcmd.h
index ded3f00..1e4cdfb 100644
--- a/src/gsmd/atcmd.h
+++ b/src/gsmd/atcmd.h
@@ -3,9 +3,9 @@
#include "gsmd.h"
-typedef int atcmd_cb_t(struct gsmd_atcmd *cmd, void *ctx);
+typedef int atcmd_cb_t(struct gsmd_atcmd *cmd, void *ctx, char *resp);
-struct gsmd_atcmd *atcmd_fill(const char *cmd, int rlen, atcmd_cb_t *cb, void *ctx);
+struct gsmd_atcmd *atcmd_fill(const char *cmd, int rlen, atcmd_cb_t *cb, void *ctx, u_int16_t id);
int atcmd_submit(struct gsmd *g, struct gsmd_atcmd *cmd);
int atcmd_init(struct gsmd *g, int sockfd);
void atcmd_drain(int fd);
diff --git a/src/gsmd/gsmd.c b/src/gsmd/gsmd.c
index f17b7a2..c8a3b3f 100644
--- a/src/gsmd/gsmd.c
+++ b/src/gsmd/gsmd.c
@@ -20,24 +20,23 @@
#include "usock.h"
#include "vendorplugin.h"
-static int gsmd_test_atcb(struct gsmd_atcmd *cmd, void *ctx)
+static int gsmd_test_atcb(struct gsmd_atcmd *cmd, void *ctx, char *resp)
{
- printf("`%s' returned `%s'\n", cmd->buf, cmd->resp);
- free(cmd);
+ printf("`%s' returned `%s'\n", cmd->buf, resp);
return 0;
}
static int gsmd_test(struct gsmd *gsmd)
{
struct gsmd_atcmd *cmd;
- cmd = atcmd_fill("AT+CRC?", 255, &gsmd_test_atcb, NULL);
+ cmd = atcmd_fill("AT+CRC?", 255, &gsmd_test_atcb, NULL, 0);
return atcmd_submit(gsmd, cmd);
}
static int atcmd_test(struct gsmd *gsmd)
{
struct gsmd_atcmd *cmd;
- cmd = atcmd_fill("ATE0", 255, &gsmd_test_atcb, NULL);
+ cmd = atcmd_fill("ATE0", 255, &gsmd_test_atcb, NULL, 0);
return atcmd_submit(gsmd, cmd);
}
@@ -46,12 +45,12 @@ static int gsmd_initsettings(struct gsmd *gsmd)
int rc;
struct gsmd_atcmd *cmd;
- cmd = atcmd_fill("ATV1", 255, &gsmd_test_atcb, NULL);
+ cmd = atcmd_fill("ATV1", 255, &gsmd_test_atcb, NULL, 0);
rc = atcmd_submit(gsmd, cmd);
if (rc < 0)
return rc;
- cmd = atcmd_fill("+CRC=1;+CREG=2;+CMEE=2;+CLIP=1;+COLP=1;+CTZR=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, 0);
return atcmd_submit(gsmd, cmd);
}
diff --git a/src/gsmd/gsmd.h b/src/gsmd/gsmd.h
index 460e9d4..9c3a484 100644
--- a/src/gsmd/gsmd.h
+++ b/src/gsmd/gsmd.h
@@ -14,11 +14,12 @@
struct gsmd_atcmd {
struct llist_head list;
void *ctx;
- int (*cb)(struct gsmd_atcmd *, void *);
- u_int8_t flags;
+ int (*cb)(struct gsmd_atcmd *cmd, void *ctx, char *resp);
+ char *resp;
int32_t ret;
u_int32_t buflen;
- char *resp;
+ u_int16_t id;
+ u_int8_t flags;
char buf[];
};
@@ -73,10 +74,10 @@ struct gsmd_user {
extern int gsmdlog_init(const char *path);
/* write a message to the daemons' logfile */
-void __gsmd_log(int level, const char *file, int line, const char *message, ...);
+void __gsmd_log(int level, const char *file, int line, const char *function, const char *message, ...);
/* macro for logging including filename and line number */
#define gsmd_log(level, format, args...) \
- __gsmd_log(level, __FILE__, __LINE__, format, ## args)
+ __gsmd_log(level, __FILE__, __LINE__, __FUNCTION__, format, ## args)
#define DEBUGP(x, args ...) gsmd_log(GSMD_DEBUG, x, ## args)
diff --git a/src/gsmd/log.c b/src/gsmd/log.c
index 671916e..af58c6d 100644
--- a/src/gsmd/log.c
+++ b/src/gsmd/log.c
@@ -31,7 +31,8 @@ static inline int gsmd2syslog_level(int level)
return gsmd2syslog[level];
}
-void __gsmd_log(int level, const char *file, int line, const char *format, ...)
+void __gsmd_log(int level, const char *file, int line, const char *function,
+ const char *format, ...)
{
char *timestr;
va_list ap;
@@ -54,7 +55,8 @@ void __gsmd_log(int level, const char *file, int line, const char *format, ...)
tm = time(NULL);
timestr = ctime(&tm);
timestr[strlen(timestr)-1] = '\0';
- fprintf(outfd, "%s <%1.1d> %s:%d ", timestr, level, file, line);
+ fprintf(outfd, "%s <%1.1d> %s:%d:%s() ", timestr, level, file,
+ line, function);
va_start(ap, format);
vfprintf(outfd, format, ap);
diff --git a/src/gsmd/unsolicited.c b/src/gsmd/unsolicited.c
index 1fdcfe4..5242042 100644
--- a/src/gsmd/unsolicited.c
+++ b/src/gsmd/unsolicited.c
@@ -43,10 +43,12 @@ static int usock_evt_send(struct gsmd *gsmd, struct gsmd_ucmd *ucmd, u_int32_t e
struct gsmd_user *gu;
int num_sent = 0;
+ DEBUGP("entering evt=%u\n", evt);
+
llist_for_each_entry(gu, &gsmd->users, list) {
if (gu->subscriptions & (1 << evt)) {
struct gsmd_ucmd *cpy = ucmd_copy(ucmd);
- llist_add_tail(&ucmd->list, &gu->finished_ucmds);
+ usock_cmd_enqueue(ucmd, gu);
num_sent++;
ucmd = cpy;
if (!ucmd) {
diff --git a/src/gsmd/usock.c b/src/gsmd/usock.c
index 774fff3..b774f74 100644
--- a/src/gsmd/usock.c
+++ b/src/gsmd/usock.c
@@ -15,26 +15,36 @@
#include "atcmd.h"
#include "usock.h"
+void usock_cmd_enqueue(struct gsmd_ucmd *ucmd, struct gsmd_user *gu)
+{
+ DEBUGP("enqueueing usock cmd %p for user %p\n", ucmd, gu);
+
+ /* add to per-user list of finished cmds */
+ llist_add_tail(&ucmd->list, &gu->finished_ucmds);
+
+ /* mark socket of user as we-want-to-write */
+ gu->gfd.when |= GSMD_FD_WRITE;
+}
+
/* callback for completed passthrough gsmd_atcmd's */
-static int usock_cmd_cb(struct gsmd_atcmd *cmd, void *ctx)
+static int usock_cmd_cb(struct gsmd_atcmd *cmd, void *ctx, char *resp)
{
struct gsmd_user *gu = ctx;
struct gsmd_ucmd *ucmd = malloc(sizeof(*ucmd)+cmd->buflen);
+ DEBUGP("entering(cmd=%p, gu=%p)\n", cmd, gu);
+
if (!ucmd)
return -ENOMEM;
ucmd->hdr.version = GSMD_PROTO_VERSION;
ucmd->hdr.msg_type = GSMD_MSG_PASSTHROUGH;
ucmd->hdr.msg_subtype = GSMD_PASSTHROUGH_RESP;
- ucmd->hdr.len = cmd->buflen;
- memcpy(ucmd->buf, cmd->buf, ucmd->hdr.len);
-
- /* add to per-user list of finished cmds */
- llist_add_tail(&ucmd->list, &gu->finished_ucmds);
+ ucmd->hdr.len = strlen(resp)+1;
+ ucmd->hdr.id = cmd->id;
+ memcpy(ucmd->buf, resp, ucmd->hdr.len);
- /* mark socket of user as we-want-to-write */
- gu->gfd.when |= GSMD_FD_WRITE;
+ usock_cmd_enqueue(ucmd, gu);
return 0;
}
@@ -44,16 +54,18 @@ typedef int usock_msg_handler(struct gsmd_user *gu, struct gsmd_msg_hdr *gph, in
static int usock_rcv_passthrough(struct gsmd_user *gu, struct gsmd_msg_hdr *gph, int len)
{
struct gsmd_atcmd *cmd;
- cmd = atcmd_fill((char *)gph+sizeof(*gph), 255, &usock_cmd_cb, gu);
+ cmd = atcmd_fill((char *)gph+sizeof(*gph), gph->len, &usock_cmd_cb, gu, gph->id);
if (!cmd)
return -ENOMEM;
+ DEBUGP("submitting cmd=%p, gu=%p\n", cmd, gu);
+
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));
+ u_int32_t *evtmask = (u_int32_t *) ((char *)gph + sizeof(*gph), gph->id);
if (len < sizeof(*gph) + sizeof(u_int32_t))
return -EINVAL;
@@ -73,7 +85,7 @@ static int usock_rcv_voicecall(struct gsmd_user *gu, struct gsmd_msg_hdr *gph, i
/* FIXME */
break;
case GSMD_VOICECALL_HANGUP:
- cmd = atcmd_fill("ATH0", 5, &usock_cmd_cb, gu);
+ cmd = atcmd_fill("ATH0", 5, &usock_cmd_cb, gu, gph->id);
break;
default:
return -EINVAL;
@@ -178,6 +190,8 @@ static int gsmd_usock_user_cb(int fd, unsigned int what, void *data)
llist_del(&ucmd->list);
free(ucmd);
}
+ if (llist_empty(&gu->finished_ucmds))
+ gu->gfd.when &= ~GSMD_FD_WRITE;
}
return 0;
@@ -206,6 +220,8 @@ static int gsmd_usock_cb(int fd, unsigned int what, void *data)
newuser->gfd.data = newuser;
newuser->gfd.cb = &gsmd_usock_user_cb;
newuser->gsmd = g;
+ newuser->subscriptions = 0xffffffff;
+ INIT_LLIST_HEAD(&newuser->finished_ucmds);
llist_add(&newuser->list, &g->users);
gsmd_register_fd(&newuser->gfd);
diff --git a/src/gsmd/usock.h b/src/gsmd/usock.h
index aa7c43f..efa0f34 100644
--- a/src/gsmd/usock.h
+++ b/src/gsmd/usock.h
@@ -3,13 +3,14 @@
#include <gsmd/usock.h>
-int usock_init(struct gsmd *g);
-
struct gsmd_ucmd {
struct llist_head list;
struct gsmd_msg_hdr hdr;
char buf[];
} __attribute__ ((packed));
+extern int usock_init(struct gsmd *g);
+extern void usock_cmd_enqueue(struct gsmd_ucmd *ucmd, struct gsmd_user *gu);
+
#endif
personal git repositories of Harald Welte. Your mileage may vary