/*
 * write a dryice register and loop, waiting for it
 * to complete. use only during driver initialization.
 * returns 0 on success or 1 on write failure.
 */
static int di_write_loop(uint32_t val, int reg)
{
	int rc = 0;
	int cnt;

	di_debug("FUNC: %s\n", __func__);
	di_write(val, reg);

	for (cnt = 0; cnt < DI_WRITE_LOOP_CNT; cnt++) {
		uint32_t dsr = di_read(DSR);
		if (dsr & DSR_WEF) {
			try_to_clear_wef();
			rc = 1;
		}
		if (dsr & DSR_WCF)
			break;
	}
	di_debug("wait_write_loop looped %d times\n", cnt);
	if (cnt == DI_WRITE_LOOP_CNT)
		rc = 1;

	if (rc)
		di_warn("DryIce wait_write_done: WRITE ERROR!\n");
	return rc;
}
/*
 * blocking callers sleep here until the todo list is done
 */
static int todo_wait_done(void)
{
	di_debug("FUNC: %s\n", __func__);
	os_sleep(done_queue, todo.status == TODO_ST_DONE, 0);

	return todo.rc;
}
/*
 * initialize the todo list. must be called
 * before adding items to the list.
 */
static void todo_init(int async_flag)
{
	di_debug("FUNC: %s\n", __func__);
	todo.cur = 0;
	todo.num = 0;
	todo.async = async_flag;
	todo.rc = 0;
	todo.status = TODO_ST_LOADING;
}
/*
 * performs the actions sequentially from the todo list
 * until it encounters an item that isn't ready.
 */
static void todo_run(void)
{
	di_debug("FUNC: %s\n", __func__);
	while (todo.status == TODO_ST_READY) {
		if (todo.cur == todo.num) {
			todo_done(0);
			break;
		}
		todo_cur();
		if (todo.status != TODO_ST_READY)
			break;
		todo.cur++;
	}
}
static void todo_add(int action, uint32_t src, uint32_t dst, int num)
{
	struct td *p = &todo.list[todo.num];

	di_debug("FUNC: %s\n", __func__);
	if (todo.num == TODO_LIST_LEN) {
		di_warn("WARNING: DryIce todo-list overflow!\n");
		return;
	}
	p->action = action;
	p->src = src;
	p->dst = dst;
	p->num = num;
	todo.num++;
}
Esempio n. 6
0
/* The main function for writing things to INTERFACES_FILE (aka
 * /etc/network/interfaces).
 *
 * In principle, this function is very simple: just examine the interface
 * we've been passed, and call out to the relevant private helper function. 
 * In practice...
 *
 * Takes the interface struct to write out.  If you pass NULL, the file gets
 * deleted and a helpful comment header gets written.
 *
 * Returns a true/false boolean representing "did everything go OK"; if 0 is
 * returned, the interfaces file will not have been modified, and errno will
 * contain the details.
 */
int netcfg_write_interface(const struct netcfg_interface *interface)
{
	FILE *fd;
	int rv;
	struct stat stat_buf;
	
	if (!interface) {
		di_debug("No interface given; clearing " INTERFACES_FILE);
		rv = unlink(INTERFACES_FILE);
		if (rv < 0 && errno != ENOENT) {
			di_info("Error clearing %s: %s", INTERFACES_FILE, strerror(errno));
			return 0;
		}
	}
	
	fd = file_open(INTERFACES_FILE ".tmp", "w");
	if (!fd) {
		di_warning("Failed to open %s.tmp: %s", INTERFACES_FILE, strerror(errno));
		return 0;
	}

	/* All of this code is to handle the apparently simple task of
	 * copying the existing interfaces file to the tmpfile (if it exists)
	 * so we can add our new stuff to it.  Bloody longwinded way of doing
	 * it, I'm sure you'll agree.
	 */
	rv = stat(INTERFACES_FILE, &stat_buf);
	if (rv < 0 && errno != ENOENT) {
		di_warning("Failed to stat %s: %s", INTERFACES_FILE, strerror(errno));
		unlink(INTERFACES_FILE ".tmp");
		return 0;
	}
	if (rv == 0) {
		char *tmpbuf = malloc(stat_buf.st_size + 1);
		int origfd;
		origfd = open(INTERFACES_FILE, O_RDONLY);
		if (origfd < 0) {
			di_warning("Failed to open %s: %s", INTERFACES_FILE, strerror(errno));
			fclose(fd);
			unlink(INTERFACES_FILE ".tmp");
			free(tmpbuf);
			return 0;
		}
		rv = read(origfd, tmpbuf, stat_buf.st_size);
		if (rv < 0) {
			di_warning("Failed to read %s: %s", INTERFACES_FILE, strerror(errno));
			fclose(fd);
			unlink(INTERFACES_FILE ".tmp");
			free(tmpbuf);
			close(origfd);
			return 0;
		}
		if (rv != stat_buf.st_size) {
			di_warning("Short read on %s", INTERFACES_FILE);
			fclose(fd);
			unlink(INTERFACES_FILE ".tmp");
			free(tmpbuf);
			close(origfd);
			return 0;
		}
		rv = fwrite(tmpbuf, sizeof(char), stat_buf.st_size, fd);
		if (rv != (int)stat_buf.st_size) {
			di_warning("Short write on %s.tmp", INTERFACES_FILE);
			fclose(fd);
			unlink(INTERFACES_FILE ".tmp");
			free(tmpbuf);
			close(origfd);
			return 0;
		}
		free(tmpbuf);
		close(origfd);
	}
		
	
	/* Thank $DEITY all that's out of the way... now we can write a
	 * freaking interfaces file entry */
	rv = 1;

	if (!interface) {
		di_debug("Writing informative header");
		rv = nc_wi_header(fd);
	} else if (interface->loopback == 1) {
		di_debug("Writing loopback interface");
		rv = nc_wi_loopback(interface, fd);
	} else if (interface->dhcp == 1 || interface->slaac == 1) {
		if (interface->dhcp == 1) {
			di_debug("Writing DHCP stanza for %s", interface->name);
			rv = nc_wi_dhcp(interface, fd);
		}
		if (interface->slaac == 1) {
			di_debug("Writing SLAAC stanza for %s", interface->name);
			rv = nc_wi_slaac(interface, fd);
		}
	} else if (interface->address_family == AF_INET) {
		di_debug("Writing static IPv4 stanza for %s", interface->name);
		rv = nc_wi_static_ipv4(interface, fd);
	} else if (interface->address_family == AF_INET6) {
		di_debug("Writing static IPv6 stanza for %s", interface->name);
		rv = nc_wi_static_ipv6(interface, fd);
	}
	if (rv && interface && interface->parentif) {
		di_debug("Writing VLAN: %s", interface->name);
		rv = nc_wi_vlan(interface, fd);
	}
	if (rv && interface && is_wireless_iface(interface->name)) {
		di_debug("Writing wireless options for %s", interface->name);
		rv = nc_wi_wireless_options(interface, fd);
	}

	if (rv) {
		di_debug("Success!");
		rename(INTERFACES_FILE ".tmp", INTERFACES_FILE);
	}

	fclose(fd);
	unlink(INTERFACES_FILE ".tmp");
	return rv;
}
/*
 * kick off the todo list by making it ready
 */
static void todo_start(void)
{
	di_debug("FUNC: %s\n", __func__);
	todo.status = TODO_ST_READY;
	todo_run();
}
void todo_cur(void)
{
	di_debug("FUNC: %s[%d]\n", __func__, todo.cur);
	switch (TC.action) {
	case TODO_ACT_WRITE_VAL:
		di_debug("  TODO_ACT_WRITE_VAL\n");
		/* enable the write-completion interrupt */
		todo.status = TODO_ST_PEND_WCF;
		di_write(di_read(DIER) | DIER_WCIE, DIER);

		di_write(TC.src, TC.dst);
		break;

	case TODO_ACT_WRITE_PTR32:
		di_debug("  TODO_ACT_WRITE_PTR32\n");
		/* enable the write-completion interrupt */
		todo.status = TODO_ST_PEND_WCF;
		di_write(di_read(DIER) | DIER_WCIE, DIER);

		di_write(*(uint32_t *)TC.src, TC.dst);
		break;

	case TODO_ACT_WRITE_PTR:
		{
			uint8_t *p = (uint8_t *)TC.src;
			uint32_t val = 0;
			int num = TC.num;

			di_debug("  TODO_ACT_WRITE_PTR\n");
			while (num--)
				val = (val << 8) | *p++;

			/* enable the write-completion interrupt */
			todo.status = TODO_ST_PEND_WCF;
			di_write(di_read(DIER) | DIER_WCIE, DIER);

			di_write(val, TC.dst);
		}
		break;

	case TODO_ACT_ASSIGN:
		di_debug("  TODO_ACT_ASSIGN\n");
		switch (TC.num) {
		case 1:
			*(uint8_t *)TC.dst = TC.src;
			break;
		case 2:
			*(uint16_t *)TC.dst = TC.src;
			break;
		case 4:
			*(uint32_t *)TC.dst = TC.src;
			break;
		default:
			di_warn("Unexpected size in TODO_ACT_ASSIGN\n");
			break;
		}
		break;

	case TODO_ACT_WAIT_RKG:
		di_debug("  TODO_ACT_WAIT_RKG\n");
		/* enable the random-key interrupt */
		todo.status = TODO_ST_PEND_RKG;
		di_write(di_read(DIER) | DIER_RKIE, DIER);
		break;

	default:
		di_debug("  TODO_ACT_NOOP\n");
		break;
	}
}