summaryrefslogtreecommitdiff
path: root/src/gsmd
diff options
context:
space:
mode:
Diffstat (limited to 'src/gsmd')
-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
4 files changed, 155 insertions, 46 deletions
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)
{
personal git repositories of Harald Welte. Your mileage may vary