示例#1
0
void
g_bde_crypt_delete(struct g_bde_work *wp)
{
	struct g_bde_softc *sc;
	u_char *d;
	off_t o;
	u_char skey[G_BDE_SKEYLEN];
	keyInstance ki;
	cipherInstance ci;

	sc = wp->softc;
	d = wp->sp->data;
	AES_init(&ci);
	/*
	 * Do not unroll this loop!
	 * Our zone may be significantly wider than the amount of random
	 * bytes arc4rand likes to give in one reseeding, whereas our
	 * sectorsize is far more likely to be in the same range.
	 */
	for (o = 0; o < wp->length; o += sc->sectorsize) {
		arc4rand(d, sc->sectorsize, 0);
		arc4rand(&skey, sizeof skey, 0);
		AES_makekey(&ki, DIR_ENCRYPT, G_BDE_SKEYBITS, skey);
		AES_encrypt(&ci, &ki, d, d, sc->sectorsize);
		d += sc->sectorsize;
	}
	/*
	 * Having written a long random sequence to disk here, we want to
	 * force a reseed, to avoid weakening the next time we use random
	 * data for something important.
	 */
	arc4rand(&o, sizeof o, 1);
}
示例#2
0
void
g_bde_crypt_write(struct g_bde_work *wp)
{
	u_char *s, *d;
	struct g_bde_softc *sc;
	u_int n;
	off_t o;
	u_char skey[G_BDE_SKEYLEN];
	keyInstance ki;
	cipherInstance ci;

	sc = wp->softc;
	AES_init(&ci);
	o = 0;
	for (n = 0; o < wp->length; n++, o += sc->sectorsize) {

		s = (u_char *)wp->data + o;
		d = (u_char *)wp->sp->data + o;
		arc4rand(&skey, sizeof skey, 0);
		AES_makekey(&ki, DIR_ENCRYPT, G_BDE_SKEYBITS, skey);
		AES_encrypt(&ci, &ki, s, d, sc->sectorsize);

		d = (u_char *)wp->ksp->data + wp->ko + n * G_BDE_SKEYLEN;
		g_bde_kkey(sc, &ki, DIR_ENCRYPT, wp->offset + o);
		AES_encrypt(&ci, &ki, skey, d, sizeof skey);
		bzero(skey, sizeof skey);
	}
	bzero(skey, sizeof skey);
	bzero(&ci, sizeof ci);
	bzero(&ki, sizeof ci);
}
示例#3
0
int
aesni_cipher_setup(struct aesni_session *ses, struct cryptoini *encini)
{
	struct thread *td;
	int error;

	switch (encini->cri_klen) {
	case 128:
		ses->rounds = AES128_ROUNDS;
		break;
	case 192:
		ses->rounds = AES192_ROUNDS;
		break;
	case 256:
		ses->rounds = AES256_ROUNDS;
		break;
	default:
		return (EINVAL);
	}

	td = curthread;
	error = fpu_kern_enter(td, &ses->fpu_ctx, FPU_KERN_NORMAL);
	if (error == 0) {
		aesni_set_enckey(encini->cri_key, ses->enc_schedule,
		    ses->rounds);
		aesni_set_deckey(ses->enc_schedule, ses->dec_schedule,
		    ses->rounds);
		arc4rand(ses->iv, sizeof(ses->iv), 0);
		fpu_kern_leave(td, &ses->fpu_ctx);
	}
	return (error);
}
示例#4
0
文件: rand.c 项目: bladely/HelloX_OS
uint32_t arc4random()
{
    uint32_t ret;

    arc4rand(&ret, sizeof ret, 0);
    return ret;
}
示例#5
0
uint32_t
ipf_random(void)
{
	uint32_t ret;

	arc4rand(&ret, sizeof ret, 0);
	return ret;
}
示例#6
0
int
cloudabi64_fixup(register_t **stack_base, struct image_params *imgp)
{
	char canarybuf[64];
	Elf64_Auxargs *args;
	struct thread *td;
	void *argdata, *canary;
	size_t argdatalen;
	int error;

	/*
	 * CloudABI executables do not store the FreeBSD OS release
	 * number in their header. Set the OS release number to the
	 * latest version of FreeBSD, so that system calls behave as if
	 * called natively.
	 */
	td = curthread;
	td->td_proc->p_osrel = __FreeBSD_version;

	/* Store canary for stack smashing protection. */
	argdata = *stack_base;
	arc4rand(canarybuf, sizeof(canarybuf), 0);
	*stack_base -= howmany(sizeof(canarybuf), sizeof(register_t));
	canary = *stack_base;
	error = copyout(canarybuf, canary, sizeof(canarybuf));
	if (error != 0)
		return (error);

	/*
	 * Compute length of program arguments. As the argument data is
	 * binary safe, we had to add a trailing null byte in
	 * exec_copyin_data_fds(). Undo this by reducing the length.
	 */
	args = (Elf64_Auxargs *)imgp->auxargs;
	argdatalen = imgp->args->begin_envv - imgp->args->begin_argv;
	if (argdatalen > 0)
		--argdatalen;

	/* Write out an auxiliary vector. */
	cloudabi64_auxv_t auxv[] = {
#define	VAL(type, val)	{ .a_type = (type), .a_val = (val) }
#define	PTR(type, ptr)	{ .a_type = (type), .a_ptr = (uintptr_t)(ptr) }
		PTR(CLOUDABI_AT_ARGDATA, argdata),
		VAL(CLOUDABI_AT_ARGDATALEN, argdatalen),
		PTR(CLOUDABI_AT_CANARY, canary),
		VAL(CLOUDABI_AT_CANARYLEN, sizeof(canarybuf)),
		VAL(CLOUDABI_AT_NCPUS, mp_ncpus),
		VAL(CLOUDABI_AT_PAGESZ, args->pagesz),
		PTR(CLOUDABI_AT_PHDR, args->phdr),
		VAL(CLOUDABI_AT_PHNUM, args->phnum),
		VAL(CLOUDABI_AT_TID, td->td_tid),
#undef VAL
#undef PTR
		{ .a_type = CLOUDABI_AT_NULL },
	};
示例#7
0
static int
sysctl_kern_arnd(SYSCTL_HANDLER_ARGS)
{
	char buf[256];
	size_t len;

	len = req->oldlen;
	if (len > sizeof(buf))
		len = sizeof(buf);
	arc4rand(buf, len, 0);
	return (SYSCTL_OUT(req, buf, len));
}
示例#8
0
int
aesni_cipher_setup_common(struct aesni_session *ses, const uint8_t *key,
    int keylen)
{

	switch (ses->algo) {
	case CRYPTO_AES_CBC:
		switch (keylen) {
		case 128:
			ses->rounds = AES128_ROUNDS;
			break;
		case 192:
			ses->rounds = AES192_ROUNDS;
			break;
		case 256:
			ses->rounds = AES256_ROUNDS;
			break;
		default:
			return (EINVAL);
		}
		break;
	case CRYPTO_AES_XTS:
		switch (keylen) {
		case 256:
			ses->rounds = AES128_ROUNDS;
			break;
		case 512:
			ses->rounds = AES256_ROUNDS;
			break;
		default:
			return (EINVAL);
		}
		break;
	default:
		return (EINVAL);
	}

	aesni_set_enckey(key, ses->enc_schedule, ses->rounds);
	aesni_set_deckey(ses->enc_schedule, ses->dec_schedule, ses->rounds);
	if (ses->algo == CRYPTO_AES_CBC)
		arc4rand(ses->iv, sizeof(ses->iv), 0);
	else /* if (ses->algo == CRYPTO_AES_XTS) */ {
		aesni_set_enckey(key + keylen / 16, ses->xts_schedule,
		    ses->rounds);
	}

	return (0);
}
示例#9
0
/*
 * When doing encryption only, copy IV key and encryption key.
 * When doing encryption and authentication, copy IV key, generate encryption
 * key and generate authentication key.
 */
void
g_eli_mkey_propagate(struct g_eli_softc *sc, const unsigned char *mkey)
{

	/* Remember the Master Key. */
	bcopy(mkey, sc->sc_mkey, sizeof(sc->sc_mkey));

	bcopy(mkey, sc->sc_ivkey, sizeof(sc->sc_ivkey));
	mkey += sizeof(sc->sc_ivkey);

	/*
	 * The authentication key is: akey = HMAC_SHA512(Master-Key, 0x11)
	 */
	if ((sc->sc_flags & G_ELI_FLAG_AUTH) != 0) {
		g_eli_crypto_hmac(mkey, G_ELI_MAXKEYLEN, "\x11", 1,
		    sc->sc_akey, 0);
	} else {
		arc4rand(sc->sc_akey, sizeof(sc->sc_akey), 0);
	}

	/* Initialize encryption keys. */
	g_eli_key_init(sc);

	if (sc->sc_flags & G_ELI_FLAG_AUTH) {
		/*
		 * Precalculate SHA256 for HMAC key generation.
		 * This is expensive operation and we can do it only once now or
		 * for every access to sector, so now will be much better.
		 */
		SHA256_Init(&sc->sc_akeyctx);
		SHA256_Update(&sc->sc_akeyctx, sc->sc_akey,
		    sizeof(sc->sc_akey));
	}
	/*
	 * Precalculate SHA256 for IV generation.
	 * This is expensive operation and we can do it only once now or for
	 * every access to sector, so now will be much better.
	 */
	switch (sc->sc_ealgo) {
	case CRYPTO_AES_XTS:
		break;
	default:
		SHA256_Init(&sc->sc_ivctx);
		SHA256_Update(&sc->sc_ivctx, sc->sc_ivkey,
		    sizeof(sc->sc_ivkey));
		break;
	}
}
示例#10
0
文件: ip_id.c 项目: Pieter-was/osv
u_int16_t
ip_randomid(void)
{
	u_int16_t new_id;

	mtx_lock(&id_mtx);
	/*
	 * To avoid a conflict with the zeros that the array is initially
	 * filled with, we never hand out an id of zero.
	 */
	new_id = 0;
	do {
		arc4rand(&new_id, sizeof(new_id), 0);
	} while (bit_test(id_bits, new_id) || new_id == 0);
	bit_clear(id_bits, id_array[array_ptr]);
	bit_set(id_bits, new_id);
	id_array[array_ptr] = new_id;
	array_ptr++;
	if (array_ptr == array_size)
		array_ptr = 0;

	mtx_unlock(&id_mtx);
	return (new_id);
}
示例#11
0
/*
 * Apply a symmetric encryption/decryption algorithm.
 */
static int
swcr_encdec(struct cryptodesc *crd, struct swcr_data *sw, caddr_t buf,
    int flags)
{
	unsigned char iv[EALG_MAX_BLOCK_LEN], blk[EALG_MAX_BLOCK_LEN], *idat;
	unsigned char *ivp, piv[EALG_MAX_BLOCK_LEN];
	struct enc_xform *exf;
	int i, k, j, blks;

	exf = sw->sw_exf;
	blks = exf->blocksize;

	/* Check for non-padded data */
	if (crd->crd_len % blks)
		return EINVAL;

	/* Initialize the IV */
	if (crd->crd_flags & CRD_F_ENCRYPT) {
		/* IV explicitly provided ? */
		if (crd->crd_flags & CRD_F_IV_EXPLICIT)
			bcopy(crd->crd_iv, iv, blks);
		else
			arc4rand(iv, blks, 0);

		/* Do we need to write the IV */
		if (!(crd->crd_flags & CRD_F_IV_PRESENT))
			crypto_copyback(flags, buf, crd->crd_inject, blks, iv);

	} else {	/* Decryption */
			/* IV explicitly provided ? */
		if (crd->crd_flags & CRD_F_IV_EXPLICIT)
			bcopy(crd->crd_iv, iv, blks);
		else {
			/* Get IV off buf */
			crypto_copydata(flags, buf, crd->crd_inject, blks, iv);
		}
	}

	if (crd->crd_flags & CRD_F_KEY_EXPLICIT) {
		int error; 

		if (sw->sw_kschedule)
			exf->zerokey(&(sw->sw_kschedule));
		error = exf->setkey(&sw->sw_kschedule,
				crd->crd_key, crd->crd_klen / 8);
		if (error)
			return (error);
	}

	ivp = iv;

	/*
	 * xforms that provide a reinit method perform all IV
	 * handling themselves.
	 */
	if (exf->reinit)
		exf->reinit(sw->sw_kschedule, iv);

	if (flags & CRYPTO_F_IMBUF) {
		struct mbuf *m = (struct mbuf *) buf;

		/* Find beginning of data */
		m = m_getptr(m, crd->crd_skip, &k);
		if (m == NULL)
			return EINVAL;

		i = crd->crd_len;

		while (i > 0) {
			/*
			 * If there's insufficient data at the end of
			 * an mbuf, we have to do some copying.
			 */
			if (m->m_len < k + blks && m->m_len != k) {
				m_copydata(m, k, blks, blk);

				/* Actual encryption/decryption */
				if (exf->reinit) {
					if (crd->crd_flags & CRD_F_ENCRYPT) {
						exf->encrypt(sw->sw_kschedule,
						    blk);
					} else {
						exf->decrypt(sw->sw_kschedule,
						    blk);
					}
				} else if (crd->crd_flags & CRD_F_ENCRYPT) {
					/* XOR with previous block */
					for (j = 0; j < blks; j++)
						blk[j] ^= ivp[j];

					exf->encrypt(sw->sw_kschedule, blk);

					/*
					 * Keep encrypted block for XOR'ing
					 * with next block
					 */
					bcopy(blk, iv, blks);
					ivp = iv;
				} else {	/* decrypt */
					/*	
					 * Keep encrypted block for XOR'ing
					 * with next block
					 */
					if (ivp == iv)
						bcopy(blk, piv, blks);
					else
						bcopy(blk, iv, blks);

					exf->decrypt(sw->sw_kschedule, blk);

					/* XOR with previous block */
					for (j = 0; j < blks; j++)
						blk[j] ^= ivp[j];

					if (ivp == iv)
						bcopy(piv, iv, blks);
					else
						ivp = iv;
				}

				/* Copy back decrypted block */
				m_copyback(m, k, blks, blk);

				/* Advance pointer */
				m = m_getptr(m, k + blks, &k);
				if (m == NULL)
					return EINVAL;

				i -= blks;

				/* Could be done... */
				if (i == 0)
					break;
			}

			/* Skip possibly empty mbufs */
			if (k == m->m_len) {
				for (m = m->m_next; m && m->m_len == 0;
				    m = m->m_next)
					;
				k = 0;
			}

			/* Sanity check */
			if (m == NULL)
				return EINVAL;

			/*
			 * Warning: idat may point to garbage here, but
			 * we only use it in the while() loop, only if
			 * there are indeed enough data.
			 */
			idat = mtod(m, unsigned char *) + k;

	   		while (m->m_len >= k + blks && i > 0) {
				if (exf->reinit) {
					if (crd->crd_flags & CRD_F_ENCRYPT) {
						exf->encrypt(sw->sw_kschedule,
						    idat);
					} else {
						exf->decrypt(sw->sw_kschedule,
						    idat);
					}
				} else if (crd->crd_flags & CRD_F_ENCRYPT) {
					/* XOR with previous block/IV */
					for (j = 0; j < blks; j++)
						idat[j] ^= ivp[j];

					exf->encrypt(sw->sw_kschedule, idat);
					ivp = idat;
				} else {	/* decrypt */
					/*
					 * Keep encrypted block to be used
					 * in next block's processing.
					 */
					if (ivp == iv)
						bcopy(idat, piv, blks);
					else
						bcopy(idat, iv, blks);

					exf->decrypt(sw->sw_kschedule, idat);

					/* XOR with previous block/IV */
					for (j = 0; j < blks; j++)
						idat[j] ^= ivp[j];

					if (ivp == iv)
						bcopy(piv, iv, blks);
					else
						ivp = iv;
				}

				idat += blks;
				k += blks;
				i -= blks;
			}
		}

		return 0; /* Done with mbuf encryption/decryption */
	} else if (flags & CRYPTO_F_IOV) {
示例#12
0
/*
 * Copy strings out to the new process address space, constructing new arg
 * and env vector tables. Return a pointer to the base so that it can be used
 * as the initial stack pointer.
 */
static register_t *
linux_copyout_strings(struct image_params *imgp)
{
	int argc, envc;
	char **vectp;
	char *stringp, *destp;
	register_t *stack_base;
	struct ps_strings *arginfo;
	char canary[LINUX_AT_RANDOM_LEN];
	size_t execpath_len;
	struct proc *p;

	/*
	 * Calculate string base and vector table pointers.
	 */
	if (imgp->execpath != NULL && imgp->auxargs != NULL)
		execpath_len = strlen(imgp->execpath) + 1;
	else
		execpath_len = 0;

	p = imgp->proc;
	arginfo = (struct ps_strings *)p->p_sysent->sv_psstrings;
	destp =	(caddr_t)arginfo - SPARE_USRSPACE -
	    roundup(sizeof(canary), sizeof(char *)) -
	    roundup(execpath_len, sizeof(char *)) -
	    roundup(ARG_MAX - imgp->args->stringspace, sizeof(char *));

	if (execpath_len != 0) {
		imgp->execpathp = (uintptr_t)arginfo - execpath_len;
		copyout(imgp->execpath, (void *)imgp->execpathp, execpath_len);
	}

	/*
	 * Prepare the canary for SSP.
	 */
	arc4rand(canary, sizeof(canary), 0);
	imgp->canary = (uintptr_t)arginfo -
	    roundup(execpath_len, sizeof(char *)) -
	    roundup(sizeof(canary), sizeof(char *));
	copyout(canary, (void *)imgp->canary, sizeof(canary));

	/*
	 * If we have a valid auxargs ptr, prepare some room
	 * on the stack.
	 */
	if (imgp->auxargs) {
		/*
		 * 'AT_COUNT*2' is size for the ELF Auxargs data. This is for
		 * lower compatibility.
		 */
		imgp->auxarg_size = (imgp->auxarg_size) ? imgp->auxarg_size :
		    (LINUX_AT_COUNT * 2);

		/*
		 * The '+ 2' is for the null pointers at the end of each of
		 * the arg and env vector sets,and imgp->auxarg_size is room
		 * for argument of Runtime loader.
		 */
		vectp = (char **)(destp - (imgp->args->argc +
		    imgp->args->envc + 2 + imgp->auxarg_size) * sizeof(char *));

	} else {
		/*
		 * The '+ 2' is for the null pointers at the end of each of
		 * the arg and env vector sets
		 */
		vectp = (char **)(destp - (imgp->args->argc +
		    imgp->args->envc + 2) * sizeof(char *));
	}

	/*
	 * vectp also becomes our initial stack base
	 */
	stack_base = (register_t *)vectp;

	stringp = imgp->args->begin_argv;
	argc = imgp->args->argc;
	envc = imgp->args->envc;

	/*
	 * Copy out strings - arguments and environment.
	 */
	copyout(stringp, destp, ARG_MAX - imgp->args->stringspace);

	/*
	 * Fill in "ps_strings" struct for ps, w, etc.
	 */
	suword(&arginfo->ps_argvstr, (long)(intptr_t)vectp);
	suword(&arginfo->ps_nargvstr, argc);

	/*
	 * Fill in argument portion of vector table.
	 */
	for (; argc > 0; --argc) {
		suword(vectp++, (long)(intptr_t)destp);
		while (*stringp++ != 0)
			destp++;
		destp++;
	}

	/* a null vector table pointer separates the argp's from the envp's */
	suword(vectp++, 0);

	suword(&arginfo->ps_envstr, (long)(intptr_t)vectp);
	suword(&arginfo->ps_nenvstr, envc);

	/*
	 * Fill in environment portion of vector table.
	 */
	for (; envc > 0; --envc) {
		suword(vectp++, (long)(intptr_t)destp);
		while (*stringp++ != 0)
			destp++;
		destp++;
	}

	/* end of vector table is a null pointer */
	suword(vectp, 0);
	return (stack_base);
}
示例#13
0
u_int
read_random(void *buf, u_int count)
{
    arc4rand(buf, count, 0);
    return (count);
}
示例#14
0
int
cfcs_init(void)
{
	struct cfcs_softc *softc;
	struct ccb_setasync csa;
	struct ctl_frontend *fe;
#ifdef NEEDTOPORT
	char wwnn[8];
#endif
	int retval;

	/* Don't continue if CTL is disabled */
	if (ctl_disable != 0)
		return (0);

	softc = &cfcs_softc;
	retval = 0;
	bzero(softc, sizeof(*softc));
	sprintf(softc->lock_desc, "ctl2cam");
	mtx_init(&softc->lock, softc->lock_desc, NULL, MTX_DEF);
	fe = &softc->fe;

	fe->port_type = CTL_PORT_INTERNAL;
	/* XXX KDM what should the real number be here? */
	fe->num_requested_ctl_io = 4096;
	snprintf(softc->port_name, sizeof(softc->port_name), "ctl2cam");
	fe->port_name = softc->port_name;
	fe->port_online = cfcs_online;
	fe->port_offline = cfcs_offline;
	fe->onoff_arg = softc;
	fe->targ_enable = cfcs_targ_enable;
	fe->targ_disable = cfcs_targ_disable;
	fe->lun_enable = cfcs_lun_enable;
	fe->lun_disable = cfcs_lun_disable;
	fe->targ_lun_arg = softc;
	fe->fe_datamove = cfcs_datamove;
	fe->fe_done = cfcs_done;

	/* XXX KDM what should we report here? */
	/* XXX These should probably be fetched from CTL. */
	fe->max_targets = 1;
	fe->max_target_id = 15;

	retval = ctl_frontend_register(fe, /*master_SC*/ 1);
	if (retval != 0) {
		printf("%s: ctl_frontend_register() failed with error %d!\n",
		       __func__, retval);
		mtx_destroy(&softc->lock);
		return (1);
	}

	/*
	 * Get the WWNN out of the database, and create a WWPN as well.
	 */
#ifdef NEEDTOPORT
	ddb_GetWWNN((char *)wwnn);
	softc->wwnn = be64dec(wwnn);
	softc->wwpn = softc->wwnn + (softc->fe.targ_port & 0xff);
#endif

	/*
	 * If the CTL frontend didn't tell us what our WWNN/WWPN is, go
	 * ahead and set something random.
	 */
	if (fe->wwnn == 0) {
		uint64_t random_bits;

		arc4rand(&random_bits, sizeof(random_bits), 0);
		softc->wwnn = (random_bits & 0x0000000fffffff00ULL) |
			/* Company ID */ 0x5000000000000000ULL |
			/* NL-Port */    0x0300;
		softc->wwpn = softc->wwnn + fe->targ_port + 1;
		fe->wwnn = softc->wwnn;
		fe->wwpn = softc->wwpn;
	} else {
		softc->wwnn = fe->wwnn;
		softc->wwpn = fe->wwpn;
	}

	mtx_lock(&softc->lock);
	softc->devq = cam_simq_alloc(fe->num_requested_ctl_io);
	if (softc->devq == NULL) {
		printf("%s: error allocating devq\n", __func__);
		retval = ENOMEM;
		goto bailout;
	}

	softc->sim = cam_sim_alloc(cfcs_action, cfcs_poll, softc->port_name,
				   softc, /*unit*/ 0, &softc->lock, 1,
				   fe->num_requested_ctl_io, softc->devq);
	if (softc->sim == NULL) {
		printf("%s: error allocating SIM\n", __func__);
		retval = ENOMEM;
		goto bailout;
	}

	if (xpt_bus_register(softc->sim, NULL, 0) != CAM_SUCCESS) {
		printf("%s: error registering SIM\n", __func__);
		retval = ENOMEM;
		goto bailout;
	}

	if (xpt_create_path(&softc->path, /*periph*/NULL,
			    cam_sim_path(softc->sim),
			    CAM_TARGET_WILDCARD,
			    CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
		printf("%s: error creating path\n", __func__);
		xpt_bus_deregister(cam_sim_path(softc->sim));
		retval = 1;
		goto bailout;
	}

	xpt_setup_ccb(&csa.ccb_h, softc->path, CAM_PRIORITY_NONE);
	csa.ccb_h.func_code = XPT_SASYNC_CB;
	csa.event_enable = AC_LOST_DEVICE;
	csa.callback = cfcs_async;
        csa.callback_arg = softc->sim;
        xpt_action((union ccb *)&csa);

	mtx_unlock(&softc->lock);

	return (retval);

bailout:
	if (softc->sim)
		cam_sim_free(softc->sim, /*free_devq*/ TRUE);
	else if (softc->devq)
		cam_simq_free(softc->devq);
	mtx_unlock(&softc->lock);
	mtx_destroy(&softc->lock);

	return (retval);
}
示例#15
0
int
cfcs_init(void)
{
	struct cfcs_softc *softc;
	struct ccb_setasync csa;
	struct ctl_port *port;
	int retval;

	softc = &cfcs_softc;
	bzero(softc, sizeof(*softc));
	mtx_init(&softc->lock, "ctl2cam", NULL, MTX_DEF);
	port = &softc->port;

	port->frontend = &cfcs_frontend;
	port->port_type = CTL_PORT_INTERNAL;
	/* XXX KDM what should the real number be here? */
	port->num_requested_ctl_io = 4096;
	snprintf(softc->port_name, sizeof(softc->port_name), "camsim");
	port->port_name = softc->port_name;
	port->port_online = cfcs_online;
	port->port_offline = cfcs_offline;
	port->onoff_arg = softc;
	port->fe_datamove = cfcs_datamove;
	port->fe_done = cfcs_done;

	/* XXX KDM what should we report here? */
	/* XXX These should probably be fetched from CTL. */
	port->max_targets = 1;
	port->max_target_id = 15;
	port->targ_port = -1;

	retval = ctl_port_register(port);
	if (retval != 0) {
		printf("%s: ctl_port_register() failed with error %d!\n",
		       __func__, retval);
		mtx_destroy(&softc->lock);
		return (retval);
	}

	/*
	 * If the CTL frontend didn't tell us what our WWNN/WWPN is, go
	 * ahead and set something random.
	 */
	if (port->wwnn == 0) {
		uint64_t random_bits;

		arc4rand(&random_bits, sizeof(random_bits), 0);
		softc->wwnn = (random_bits & 0x0000000fffffff00ULL) |
			/* Company ID */ 0x5000000000000000ULL |
			/* NL-Port */    0x0300;
		softc->wwpn = softc->wwnn + port->targ_port + 1;
		ctl_port_set_wwns(port, true, softc->wwnn, true, softc->wwpn);
	} else {
		softc->wwnn = port->wwnn;
		softc->wwpn = port->wwpn;
	}

	mtx_lock(&softc->lock);
	softc->devq = cam_simq_alloc(port->num_requested_ctl_io);
	if (softc->devq == NULL) {
		printf("%s: error allocating devq\n", __func__);
		retval = ENOMEM;
		goto bailout;
	}

	softc->sim = cam_sim_alloc(cfcs_action, cfcs_poll, softc->port_name,
				   softc, /*unit*/ 0, &softc->lock, 1,
				   port->num_requested_ctl_io, softc->devq);
	if (softc->sim == NULL) {
		printf("%s: error allocating SIM\n", __func__);
		retval = ENOMEM;
		goto bailout;
	}

	if (xpt_bus_register(softc->sim, NULL, 0) != CAM_SUCCESS) {
		printf("%s: error registering SIM\n", __func__);
		retval = ENOMEM;
		goto bailout;
	}

	if (xpt_create_path(&softc->path, /*periph*/NULL,
			    cam_sim_path(softc->sim),
			    CAM_TARGET_WILDCARD,
			    CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
		printf("%s: error creating path\n", __func__);
		xpt_bus_deregister(cam_sim_path(softc->sim));
		retval = EINVAL;
		goto bailout;
	}

	xpt_setup_ccb(&csa.ccb_h, softc->path, CAM_PRIORITY_NONE);
	csa.ccb_h.func_code = XPT_SASYNC_CB;
	csa.event_enable = AC_LOST_DEVICE;
	csa.callback = cfcs_async;
        csa.callback_arg = softc->sim;
        xpt_action((union ccb *)&csa);

	mtx_unlock(&softc->lock);

	return (retval);

bailout:
	if (softc->sim)
		cam_sim_free(softc->sim, /*free_devq*/ TRUE);
	else if (softc->devq)
		cam_simq_free(softc->devq);
	mtx_unlock(&softc->lock);
	mtx_destroy(&softc->lock);

	return (retval);
}