- Fixed automatic detection of the control serial port.

- Fixed segmentation fault when an invalid network interface was given.
- More helpful message in case of wrong PIN number.

Submitted by:	Fredrik Lindberg
This commit is contained in:
thompsa 2010-07-20 03:11:26 +00:00
parent fac99fc079
commit ba0349b2b7

View File

@ -66,6 +66,7 @@
#define TTY_NAME "/dev/%s" #define TTY_NAME "/dev/%s"
#define SYSCTL_TEST "dev.uhso.%d.%%driver" #define SYSCTL_TEST "dev.uhso.%d.%%driver"
#define SYSCTL_LOCATION "dev.uhso.%d.%%location"
#define SYSCTL_PORTS "dev.uhso.%d.ports" #define SYSCTL_PORTS "dev.uhso.%d.ports"
#define SYSCTL_NETIF "dev.uhso.%d.netif" #define SYSCTL_NETIF "dev.uhso.%d.netif"
#define SYSCTL_NAME_TTY "dev.uhso.%d.port.%s.tty" #define SYSCTL_NAME_TTY "dev.uhso.%d.port.%s.tty"
@ -207,9 +208,6 @@ tmr_run(struct timers *tmrs)
while (te->timeout <= 0) { while (te->timeout <= 0) {
te2 = TAILQ_NEXT(te, next); te2 = TAILQ_NEXT(te, next);
TAILQ_REMOVE(&tmrs->head, te, next); TAILQ_REMOVE(&tmrs->head, te, next);
if (te2 != NULL)
te2->timeout -= tmrs->res;
te->func(te->id, te->arg); te->func(te->id, te->arg);
free(te); free(te);
te = te2; te = te2;
@ -579,12 +577,13 @@ readline(int fd, char *buf, size_t bufsz)
static int static int
at_cmd(struct ctx *ctx, const char *resp, resp_cb cb, resp_arg *ra, const char *cf, ...) at_cmd(struct ctx *ctx, const char *resp, resp_cb cb, resp_arg *ra, const char *cf, ...)
{ {
char buf[512];
char cmd[64];
size_t l; size_t l;
int n, error, retval = 0; int n, error, retval = 0;
va_list ap; va_list ap;
fd_set set; fd_set set;
char buf[512]; char *p;
char cmd[64];
va_start(ap, cf); va_start(ap, cf);
vsnprintf(cmd, sizeof(cmd), cf, ap); vsnprintf(cmd, sizeof(cmd), cf, ap);
@ -614,12 +613,12 @@ at_cmd(struct ctx *ctx, const char *resp, resp_cb cb, resp_arg *ra, const char *
do { do {
FD_SET(ctx->fd, &set); FD_SET(ctx->fd, &set);
error = select(ctx->fd + 1, &set, NULL, NULL, NULL); error = select(ctx->fd + 1, &set, NULL, NULL, NULL);
if (error < 0 && errno == EINTR && ctx->flags & FLG_WDEXP) { if (ctx->flags & FLG_WDEXP) {
watchdog_disable(ctx); watchdog_disable(ctx);
retval = -2; return (-2);
break;
} }
} while (error <= 0 && errno == EINTR); } while (error <= 0 && errno == EINTR);
watchdog_disable(ctx);
if (error <= 0) { if (error <= 0) {
retval = -2; retval = -2;
@ -635,24 +634,30 @@ at_cmd(struct ctx *ctx, const char *resp, resp_cb cb, resp_arg *ra, const char *
if (strcmp(buf, "\r\n") == 0 || strcmp(buf, "\n") == 0) if (strcmp(buf, "\r\n") == 0 || strcmp(buf, "\n") == 0)
continue; continue;
if ((p = strchr(buf, '\r')) != NULL)
*p = '\0';
else if ((p = strchr(buf, '\n')) != NULL)
*p = '\0';
#ifdef DEBUG #ifdef DEBUG
fprintf(stderr, "SYNC_RESP: %s", buf); fprintf(stderr, "SYNC_RESP: %s\n", buf);
#endif #endif
/* Skip local echo */
if (strncasecmp(cmd, buf, strlen(buf)) == 0)
continue;
if (cb != NULL)
cb(ra, cmd, buf);
if (strncmp(buf, "OK", 2) == 0) { if (strncmp(buf, "OK", 2) == 0) {
retval = retval ? retval : 0;
break; break;
} } else if (strstr(buf, "ERROR") != NULL) {
else if (strncmp(buf, "ERROR", 5) == 0) {
retval = -1; retval = -1;
break; break;
} }
if (resp != NULL)
if (resp != NULL) { retval = strncmp(buf, resp, l);
retval = strncmp(resp, buf, l);
if (retval == 0 && cb != NULL) {
cb(ra, cmd, buf);
}
}
} }
#ifdef DEBUG #ifdef DEBUG
fprintf(stderr, "SYNC_RETVAL=%d\n", retval); fprintf(stderr, "SYNC_RETVAL=%d\n", retval);
@ -684,6 +689,10 @@ saveresp(resp_arg *ra, const char *cmd, const char *resp)
char **buf; char **buf;
int i = ra->val[1].int32; int i = ra->val[1].int32;
#ifdef DEBUG
fprintf(stderr, "Save '%s'\n", resp);
#endif
buf = realloc(ra->val[0].ptr, sizeof(char *) * (i + 1)); buf = realloc(ra->val[0].ptr, sizeof(char *) * (i + 1));
if (buf == NULL) if (buf == NULL)
return; return;
@ -694,6 +703,19 @@ saveresp(resp_arg *ra, const char *cmd, const char *resp)
ra->val[1].int32 = i + 1; ra->val[1].int32 = i + 1;
} }
static void
freeresp(resp_arg *ra)
{
char **buf;
int i;
buf = ra->val[0].ptr;
for (i = 0; i < ra->val[1].int32; i++) {
free(buf[i]);
}
free(buf);
}
static void static void
at_async_creg(void *arg, const char *resp) at_async_creg(void *arg, const char *resp)
{ {
@ -992,129 +1014,119 @@ static const char *port_type_list[] = {
/* /*
* Attempts to find a list of control tty for the interface * Attempts to find a list of control tty for the interface
* FreeBSD attaches USb devices per interface so we have to go through * FreeBSD attaches USB devices per interface so we have to go through
* hoops to find which ttys that belong to our network interface. * hoops to find which ttys that belong to our network interface.
*/ */
static char ** static char **
get_tty(struct ctx *ctx) get_tty(struct ctx *ctx)
{ {
char buf[64]; char buf[64], data[128];
char data[128]; int error, i, usbport, usbport0, list_size = 0;
size_t len;
int error;
unsigned int i;
char **list = NULL; char **list = NULL;
int list_size = 0; size_t len;
const char **p; const char **p, *q;
/*
* Look for the network interface first
*/
for (i = 0; ; i++) { for (i = 0; ; i++) {
/* Basic test to check if we're even in the right ballpark */ /* Check if we still have uhso nodes to check */
snprintf(buf, 64, SYSCTL_TEST, i); snprintf(buf, 64, SYSCTL_TEST, i);
len = 127; len = 127;
error = sysctlbyname(buf, data, &len, NULL, 0); error = sysctlbyname(buf, data, &len, NULL, 0);
data[len] = '\0';
#ifdef DEBUG #ifdef DEBUG
fprintf(stderr, "sysctl %s returned(%d): %s\n", fprintf(stderr, "sysctl %s returned(%d): %s\n",
buf, error, error == 0 ? data : "FAILED"); buf, error, error == 0 ? data : "FAILED");
#endif #endif
if (error < 0) if (error < 0 || strcasecmp(data, "uhso") != 0)
return NULL;
if (strcasecmp(data, "uhso") != 0)
return NULL; return NULL;
/* Check for interface */ /* Check if this node contains the network interface we want */
snprintf(buf, 64, SYSCTL_NETIF, i); snprintf(buf, 64, SYSCTL_NETIF, i);
len = 127; len = 127;
error = sysctlbyname(buf, data, &len, NULL, 0); error = sysctlbyname(buf, data, &len, NULL, 0);
data[len] = '\0';
#ifdef DEBUG #ifdef DEBUG
fprintf(stderr, "sysctl %s returned(%d): %s\n", fprintf(stderr, "sysctl %s returned(%d): %s\n",
buf, error, error == 0 ? data : "FAILED"); buf, error, error == 0 ? data : "FAILED");
#endif #endif
if (error < 0) if (error == 0 && strcasecmp(data, ctx->ifnam) == 0)
continue; break;
if (strcasecmp(data, ctx->ifnam) != 0)
continue;
#ifdef DEBUG
fprintf(stderr, "Found %s at %s\n", ctx->ifnam, buf);
#endif
break;
} }
/* Add multiplexed ports */ /* Figure out the USB port location */
for (p = port_type_list; *p != NULL; p++) { snprintf(buf, 64, SYSCTL_LOCATION, i);
snprintf(buf, 64, SYSCTL_NAME_TTY, i, *p); len = 127;
len = 127; error = sysctlbyname(buf, data, &len, NULL, 0);
error = sysctlbyname(buf, data, &len, NULL, 0); data[len] = '\0';
#ifdef DEBUG #ifdef DEBUG
fprintf(stderr, "sysctl %s returned(%d): %s\n", fprintf(stderr, "sysctl %s returned(%d): %s\n",
buf, error, error == 0 ? data : "FAILED"); buf, error, error == 0 ? data : "FAILED");
#endif #endif
if (error == 0) { if (error != 0)
list = realloc(list, (list_size + 1) * sizeof(char *)); return (NULL);
list[list_size] = malloc(strlen(data) + strlen(TTY_NAME));
sprintf(list[list_size], TTY_NAME, data); q = strstr(data, "port=");
list_size++; if (q != NULL) {
error = sscanf(q, " port=%d", &usbport);
if (error != 1) {
#ifdef DEBUG
fprintf(stderr, "failed to read usb port location from '%s'\n", data);
#endif
return (NULL);
} }
} } else {
/*
* We can return directly if we found multiplexed serial ports because
* devices with these ports only have additional diagnostic ports (useless)
* and modem ports (for used with pppd).
*/
if (list_size > 0) {
list = realloc(list, (list_size + 1) * sizeof(char *));
list[list_size] = NULL;
return list;
}
/*
* The network port is on a high numbered interface so we walk backwards until
* we hit anything other than application/control.
*/
for (--i; i >= 0; i--) {
/* Basic test to check if we're even in the right ballpark */
snprintf(buf, 64, SYSCTL_TEST, i);
len = 127;
error = sysctlbyname(buf, data, &len, NULL, 0);
#ifdef DEBUG #ifdef DEBUG
fprintf(stderr, "sysctl %s returned(%d): %s\n", fprintf(stderr, "failed to parse location '%s'\n", data);
buf, error, error == 0 ? data : "FAILED"); #endif
return (NULL);
}
#ifdef DEBUG
fprintf(stderr, "USB port location=%d\n", usbport);
#endif #endif
if (error < 0)
break;
if (strcasecmp(data, "uhso") != 0)
break;
/* Test for useable ports */ /*
* Now go through it all again but only look at those matching the
* usb port location we found.
*/
for (i = 0; ; i++) {
snprintf(buf, 64, SYSCTL_LOCATION, i);
len = 127;
memset(&data, 0, sizeof(data));
error = sysctlbyname(buf, data, &len, NULL, 0);
if (error != 0)
break;
data[len] = '\0';
q = strstr(data, "port=");
if (q == NULL)
continue;
sscanf(q, " port=%d", &usbport0);
if (usbport != usbport0)
continue;
/* Try to add ports */
for (p = port_type_list; *p != NULL; p++) { for (p = port_type_list; *p != NULL; p++) {
snprintf(buf, 64, SYSCTL_NAME_TTY, i, p); snprintf(buf, 64, SYSCTL_NAME_TTY, i, *p);
len = 127; len = 127;
memset(&data, 0, sizeof(data));
error = sysctlbyname(buf, data, &len, NULL, 0); error = sysctlbyname(buf, data, &len, NULL, 0);
data[len] = '\0';
#ifdef DEBUG
fprintf(stderr, "sysctl %s returned(%d): %s\n",
buf, error, error == 0 ? data : "FAILED");
#endif
if (error == 0) { if (error == 0) {
list = realloc(list, (list_size + 1) * sizeof(char *)); list = realloc(list, (list_size + 1) * sizeof(char *));
list[list_size] = malloc(strlen(data) + strlen(TTY_NAME)); list[list_size] = malloc(strlen(data) + strlen(TTY_NAME));
sprintf(list[list_size], TTY_NAME, data); sprintf(list[list_size], TTY_NAME, data);
list_size++; list_size++;
} }
} }
/* HACK! first port is a diagnostic port, we abort here */
snprintf(buf, 64, SYSCTL_NAME_TTY, i, "diagnostic");
len = 127;
error = sysctlbyname(buf, data, &len, NULL, 0);
#ifdef DEBUG
fprintf(stderr, "sysctl %s returned(%d): %s\n",
buf, error, error == 0 ? data : "FAILED");
#endif
if (error == 0)
break;
} }
list = realloc(list, (list_size + 1) * sizeof(char *)); list = realloc(list, (list_size + 1) * sizeof(char *));
list[list_size] = NULL; list[list_size] = NULL;
return list; return (list);
} }
static int static int
@ -1146,13 +1158,28 @@ do_connect(struct ctx *ctx, const char *tty)
error = at_cmd(ctx, NULL, NULL, NULL, "AT\r\n"); error = at_cmd(ctx, NULL, NULL, NULL, "AT\r\n");
if (error == -2) { if (error == -2) {
warnx("failed to read from device"); warnx("failed to read from device %s", tty);
return (-1); return (-1);
} }
/* Check for PIN */ /* Check for PIN */
error = at_cmd(ctx, "+CPIN: READY", NULL, NULL, "AT+CPIN?\r\n"); error = at_cmd(ctx, "+CPIN: READY", NULL, NULL, "AT+CPIN?\r\n");
if (error != 0) { if (error != 0) {
ra.val[0].ptr = NULL;
ra.val[1].int32 = 0;
error = at_cmd(ctx, "+CME ERROR", saveresp, &ra, "AT+CPIN?\r\n");
if (ra.val[1].int32 > 0) {
char *p;
buf = ra.val[0].ptr;
if (strstr(buf[0], "+CME ERROR:") != NULL) {
buf[0] += 12;
errx(1, buf[0]);
}
freeresp(&ra);
} else
freeresp(&ra);
if (ctx->pin == NULL) { if (ctx->pin == NULL) {
errx(1, "device requires PIN"); errx(1, "device requires PIN");
} }
@ -1445,6 +1472,8 @@ main(int argc, char *argv[])
} }
else { else {
tty_list = get_tty(&ctx); tty_list = get_tty(&ctx);
if (tty_list == NULL)
errx(1, "%s does not appear to be a uhso device", ifnam);
#ifdef DEBUG #ifdef DEBUG
if (tty_list == NULL) { if (tty_list == NULL) {
fprintf(stderr, "get_tty returned empty list\n"); fprintf(stderr, "get_tty returned empty list\n");
@ -1507,7 +1536,7 @@ main(int argc, char *argv[])
network_access_type[ctx.con_net_type]); network_access_type[ctx.con_net_type]);
if (ctx.dbm < 0) if (ctx.dbm < 0)
printf(", signal: %d dBm", ctx.dbm); printf(", signal: %d dBm", ctx.dbm);
printf("\r"); printf("\t\t\t\r");
fflush(stdout); fflush(stdout);
} }
} }