svn commit: r210276 - head/usr.sbin/uhsoctl

Andrew Thompson thompsa at FreeBSD.org
Tue Jul 20 03:11:26 UTC 2010


Author: thompsa
Date: Tue Jul 20 03:11:26 2010
New Revision: 210276
URL: http://svn.freebsd.org/changeset/base/210276

Log:
  - 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

Modified:
  head/usr.sbin/uhsoctl/uhsoctl.c

Modified: head/usr.sbin/uhsoctl/uhsoctl.c
==============================================================================
--- head/usr.sbin/uhsoctl/uhsoctl.c	Tue Jul 20 03:10:22 2010	(r210275)
+++ head/usr.sbin/uhsoctl/uhsoctl.c	Tue Jul 20 03:11:26 2010	(r210276)
@@ -66,6 +66,7 @@
 
 #define TTY_NAME	"/dev/%s"
 #define SYSCTL_TEST	"dev.uhso.%d.%%driver"
+#define SYSCTL_LOCATION "dev.uhso.%d.%%location"
 #define SYSCTL_PORTS	"dev.uhso.%d.ports"
 #define SYSCTL_NETIF	"dev.uhso.%d.netif"
 #define SYSCTL_NAME_TTY	"dev.uhso.%d.port.%s.tty"
@@ -207,9 +208,6 @@ tmr_run(struct timers *tmrs)
 	while (te->timeout <= 0) {
 		te2 = TAILQ_NEXT(te, next);
 		TAILQ_REMOVE(&tmrs->head, te, next);
-		if (te2 != NULL)
-			te2->timeout -= tmrs->res;
-
 		te->func(te->id, te->arg);
 		free(te);
 		te = te2;
@@ -579,12 +577,13 @@ readline(int fd, char *buf, size_t bufsz
 static int
 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;
 	int n, error, retval = 0;
 	va_list ap;
 	fd_set set;
-	char buf[512];
-	char cmd[64];
+	char *p;
 
 	va_start(ap, cf);
 	vsnprintf(cmd, sizeof(cmd), cf, ap);
@@ -614,12 +613,12 @@ at_cmd(struct ctx *ctx, const char *resp
 		do {
 			FD_SET(ctx->fd, &set);
 			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);
-				retval = -2;
-				break;
+				return (-2);
 			}
 		} while (error <= 0 && errno == EINTR);
+		watchdog_disable(ctx);
 
 		if (error <= 0) {
 			retval = -2;
@@ -635,24 +634,30 @@ at_cmd(struct ctx *ctx, const char *resp
 		if (strcmp(buf, "\r\n") == 0 || strcmp(buf, "\n") == 0)
 			continue;
 
+		if ((p = strchr(buf, '\r')) != NULL)
+			*p = '\0';
+		else if ((p = strchr(buf, '\n')) != NULL)
+			*p = '\0';
 #ifdef DEBUG
-		fprintf(stderr, "SYNC_RESP: %s", buf);
+		fprintf(stderr, "SYNC_RESP: %s\n", buf);
 #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) {
+			retval = retval ? retval : 0;
 			break;
-		}
-		else if (strncmp(buf, "ERROR", 5) == 0) {
+		} else if (strstr(buf, "ERROR") != NULL) {
 			retval = -1;
 			break;
 		}
-
-		if (resp != NULL) {
-			retval = strncmp(resp, buf, l);
-			if (retval == 0 && cb != NULL) {
-				cb(ra, cmd, buf);
-			}
-		}
+		if (resp != NULL)
+			retval = strncmp(buf, resp, l);
 	}
 #ifdef DEBUG
 	fprintf(stderr, "SYNC_RETVAL=%d\n", retval);
@@ -684,6 +689,10 @@ saveresp(resp_arg *ra, const char *cmd, 
 	char **buf;
 	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));
 	if (buf == NULL)
 		return;
@@ -695,6 +704,19 @@ saveresp(resp_arg *ra, const char *cmd, 
 }
 
 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
 at_async_creg(void *arg, const char *resp)
 {
 	struct ctx *ctx = arg;
@@ -992,129 +1014,119 @@ static const char *port_type_list[] = {
 
 /*
  * 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.
  */
 static char **
 get_tty(struct ctx *ctx)
 {
-	char buf[64];
-	char data[128];
-	size_t len;
-	int error;
-	unsigned int i;
+	char buf[64], data[128];
+	int error, i, usbport, usbport0, list_size = 0;
 	char **list = NULL;
-	int list_size = 0;
-	const char **p;
+	size_t len;
+	const char **p, *q;
 	
+	/*
+	 * Look for the network interface first
+	 */
 	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);
 		len = 127;
 		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)
-			return NULL;
-		if (strcasecmp(data, "uhso") != 0)
+		if (error < 0 || strcasecmp(data, "uhso") != 0)
 			return NULL;
 
-		/* Check for interface */
+		/* Check if this node contains the network interface we want */
 		snprintf(buf, 64, SYSCTL_NETIF, i);
 		len = 127;
 		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)
-			continue;
+		if (error == 0 && strcasecmp(data, ctx->ifnam) == 0)
+			break;
+	}
 
-		if (strcasecmp(data, ctx->ifnam) != 0)
-			continue;
+	/* Figure out the USB port location */
+	snprintf(buf, 64, SYSCTL_LOCATION, i);
+	len = 127;
+	error = sysctlbyname(buf, data, &len, NULL, 0);
+	data[len] = '\0';
 #ifdef DEBUG
-		fprintf(stderr, "Found %s at %s\n", ctx->ifnam, buf);
+	fprintf(stderr, "sysctl %s returned(%d): %s\n",
+	    buf, error, error == 0 ? data : "FAILED");
 #endif
-		break;
-	}
+	if (error != 0)
+		return (NULL);
 
-	/* Add multiplexed ports */	
-	for (p = port_type_list; *p != NULL; p++) {
-		snprintf(buf, 64, SYSCTL_NAME_TTY, i, *p);
-		len = 127;
-		error = sysctlbyname(buf, data, &len, NULL, 0);
+	q = strstr(data, "port=");
+	if (q != NULL) {
+		error = sscanf(q, " port=%d", &usbport);
+		if (error != 1) {
 #ifdef DEBUG
-		fprintf(stderr, "sysctl %s returned(%d): %s\n",
-		    buf, error, error == 0 ? data : "FAILED");
+			fprintf(stderr, "failed to read usb port location from '%s'\n", data);
 #endif
-		if (error == 0) {
-			list = realloc(list, (list_size + 1) * sizeof(char *));
-			list[list_size] = malloc(strlen(data) + strlen(TTY_NAME));
-			sprintf(list[list_size], TTY_NAME, data);
-			list_size++;
+			return (NULL);
 		}
+	} else {
+#ifdef DEBUG
+			fprintf(stderr, "failed to parse location '%s'\n", data);
+#endif
+			return (NULL);
 	}
-	
-	/*
-	 * 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;
-	}
+#ifdef DEBUG
+	fprintf(stderr, "USB port location=%d\n", usbport);
+#endif
 
 	/*
-	 * The network port is on a high numbered interface so we walk backwards until
-	 * we hit anything other than application/control.
+	 * Now go through it all again but only look at those matching the
+	 * usb port location we found.
 	 */
-
-	for (--i; i >= 0; i--) {
-		/* Basic test to check if we're even in the right ballpark */
-		snprintf(buf, 64, SYSCTL_TEST, i);
+	for (i = 0; ; i++) {
+		snprintf(buf, 64, SYSCTL_LOCATION, i);
 		len = 127;
+		memset(&data, 0, sizeof(data));
 		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;
-		if (strcasecmp(data, "uhso") != 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;
 
-		/* Test for useable ports */
+		/* Try to add ports */	
 		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;
+			memset(&data, 0, sizeof(data));
 			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) {
 				list = realloc(list, (list_size + 1) * sizeof(char *));
 				list[list_size] = malloc(strlen(data) + strlen(TTY_NAME));
-				sprintf(list[list_size], TTY_NAME, data);
-				list_size++;
+		    		sprintf(list[list_size], TTY_NAME, data);
+		    		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[list_size] = NULL;
-	return list;	
+	return (list);
 }
 
 static int
@@ -1146,13 +1158,28 @@ do_connect(struct ctx *ctx, const char *
 
 	error = at_cmd(ctx, NULL, NULL, NULL, "AT\r\n");
 	if (error == -2) {
-		warnx("failed to read from device");
+		warnx("failed to read from device %s", tty);
 		return (-1);
 	}
 
 	/* Check for PIN */
 	error = at_cmd(ctx, "+CPIN: READY", NULL, NULL, "AT+CPIN?\r\n");
 	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) {
 			errx(1, "device requires PIN");
 		}
@@ -1445,6 +1472,8 @@ main(int argc, char *argv[])
 	}
 	else {
 		tty_list = get_tty(&ctx);
+		if (tty_list == NULL)
+			errx(1, "%s does not appear to be a uhso device", ifnam);
 #ifdef DEBUG
 		if (tty_list == NULL) {
 			fprintf(stderr, "get_tty returned empty list\n");
@@ -1507,7 +1536,7 @@ main(int argc, char *argv[])
 			    network_access_type[ctx.con_net_type]);
 			if (ctx.dbm < 0)
 				printf(", signal: %d dBm", ctx.dbm);
-			printf("\r");
+			printf("\t\t\t\r");
 			fflush(stdout);
 		}
 	}


More information about the svn-src-all mailing list