diff options
Diffstat (limited to 'src/gsmd')
-rw-r--r-- | src/gsmd/atcmd.c | 75 | ||||
-rw-r--r-- | src/gsmd/atcmd.h | 4 | ||||
-rw-r--r-- | src/gsmd/gsmd.c | 13 | ||||
-rw-r--r-- | src/gsmd/gsmd.h | 11 | ||||
-rw-r--r-- | src/gsmd/log.c | 6 | ||||
-rw-r--r-- | src/gsmd/unsolicited.c | 4 | ||||
-rw-r--r-- | src/gsmd/usock.c | 38 | ||||
-rw-r--r-- | src/gsmd/usock.h | 5 |
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 |