xref: /titanic_51/usr/src/uts/common/crypto/io/arcfour.c (revision 694c35faa87b858ecdadfe4fc592615f4eefbb07)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
56a1073f8Skrishna  * Common Development and Distribution License (the "License").
66a1073f8Skrishna  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
2295014fbbSDan OpenSolaris Anderson  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate /*
277c478bd9Sstevel@tonic-gate  * RC4 provider for the Kernel Cryptographic Framework (KCF)
287c478bd9Sstevel@tonic-gate  */
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate #include <sys/types.h>
317c478bd9Sstevel@tonic-gate #include <sys/systm.h>
327c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
337c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
347c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
357c478bd9Sstevel@tonic-gate #include <sys/crypto/common.h>
367c478bd9Sstevel@tonic-gate #include <sys/crypto/spi.h>
377c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
387c478bd9Sstevel@tonic-gate #include <sys/strsun.h>
397c478bd9Sstevel@tonic-gate #include <arcfour.h>
407c478bd9Sstevel@tonic-gate 
417c478bd9Sstevel@tonic-gate extern struct mod_ops mod_cryptoops;
427c478bd9Sstevel@tonic-gate 
437c478bd9Sstevel@tonic-gate /*
447c478bd9Sstevel@tonic-gate  * Module linkage information for the kernel.
457c478bd9Sstevel@tonic-gate  */
467c478bd9Sstevel@tonic-gate static struct modlcrypto modlcrypto = {
477c478bd9Sstevel@tonic-gate 	&mod_cryptoops,
48d2b32306Smcpowers 	"RC4 Kernel SW Provider"
497c478bd9Sstevel@tonic-gate };
507c478bd9Sstevel@tonic-gate 
517c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = {
527c478bd9Sstevel@tonic-gate 	MODREV_1,
537c478bd9Sstevel@tonic-gate 	(void *)&modlcrypto,
547c478bd9Sstevel@tonic-gate 	NULL
557c478bd9Sstevel@tonic-gate };
567c478bd9Sstevel@tonic-gate 
577c478bd9Sstevel@tonic-gate /*
587c478bd9Sstevel@tonic-gate  * CSPI information (entry points, provider info, etc.)
597c478bd9Sstevel@tonic-gate  */
607c478bd9Sstevel@tonic-gate 
617c478bd9Sstevel@tonic-gate #define	RC4_MECH_INFO_TYPE	0
627c478bd9Sstevel@tonic-gate /*
637c478bd9Sstevel@tonic-gate  * Mechanism info structure passed to KCF during registration.
647c478bd9Sstevel@tonic-gate  */
657c478bd9Sstevel@tonic-gate static crypto_mech_info_t rc4_mech_info_tab[] = {
667c478bd9Sstevel@tonic-gate 	{SUN_CKM_RC4, RC4_MECH_INFO_TYPE,
677c478bd9Sstevel@tonic-gate 	    CRYPTO_FG_ENCRYPT | CRYPTO_FG_ENCRYPT_ATOMIC |
687c478bd9Sstevel@tonic-gate 	    CRYPTO_FG_DECRYPT | CRYPTO_FG_DECRYPT_ATOMIC,
697c478bd9Sstevel@tonic-gate 	    ARCFOUR_MIN_KEY_BITS, ARCFOUR_MAX_KEY_BITS,
706a1073f8Skrishna 	    CRYPTO_KEYSIZE_UNIT_IN_BITS | CRYPTO_CAN_SHARE_OPSTATE}
717c478bd9Sstevel@tonic-gate };
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate static void rc4_provider_status(crypto_provider_handle_t, uint_t *);
747c478bd9Sstevel@tonic-gate 
757c478bd9Sstevel@tonic-gate static crypto_control_ops_t rc4_control_ops = {
767c478bd9Sstevel@tonic-gate 	rc4_provider_status
777c478bd9Sstevel@tonic-gate };
787c478bd9Sstevel@tonic-gate 
797c478bd9Sstevel@tonic-gate static int rc4_common_init(crypto_ctx_t *, crypto_mechanism_t *,
807c478bd9Sstevel@tonic-gate     crypto_key_t *, crypto_spi_ctx_template_t, crypto_req_handle_t);
817c478bd9Sstevel@tonic-gate 
827c478bd9Sstevel@tonic-gate static int rc4_crypt_update(crypto_ctx_t *, crypto_data_t *, crypto_data_t *,
837c478bd9Sstevel@tonic-gate     crypto_req_handle_t);
847c478bd9Sstevel@tonic-gate 
857c478bd9Sstevel@tonic-gate static int rc4_crypt_final(crypto_ctx_t *, crypto_data_t *,
867c478bd9Sstevel@tonic-gate     crypto_req_handle_t);
877c478bd9Sstevel@tonic-gate 
887c478bd9Sstevel@tonic-gate static int rc4_crypt(crypto_ctx_t *, crypto_data_t *, crypto_data_t *,
897c478bd9Sstevel@tonic-gate     crypto_req_handle_t);
907c478bd9Sstevel@tonic-gate 
917c478bd9Sstevel@tonic-gate static int rc4_crypt_atomic(crypto_provider_handle_t, crypto_session_id_t,
927c478bd9Sstevel@tonic-gate     crypto_mechanism_t *, crypto_key_t *, crypto_data_t *,
937c478bd9Sstevel@tonic-gate     crypto_data_t *, crypto_spi_ctx_template_t, crypto_req_handle_t);
947c478bd9Sstevel@tonic-gate 
957c478bd9Sstevel@tonic-gate 
967c478bd9Sstevel@tonic-gate static crypto_cipher_ops_t rc4_cipher_ops = {
977c478bd9Sstevel@tonic-gate 	rc4_common_init,
987c478bd9Sstevel@tonic-gate 	rc4_crypt,
997c478bd9Sstevel@tonic-gate 	rc4_crypt_update,
1007c478bd9Sstevel@tonic-gate 	rc4_crypt_final,
1017c478bd9Sstevel@tonic-gate 	rc4_crypt_atomic,
1027c478bd9Sstevel@tonic-gate 	rc4_common_init,
1037c478bd9Sstevel@tonic-gate 	rc4_crypt,
1047c478bd9Sstevel@tonic-gate 	rc4_crypt_update,
1057c478bd9Sstevel@tonic-gate 	rc4_crypt_final,
1067c478bd9Sstevel@tonic-gate 	rc4_crypt_atomic
1077c478bd9Sstevel@tonic-gate };
1087c478bd9Sstevel@tonic-gate 
1097c478bd9Sstevel@tonic-gate static int rc4_free_context(crypto_ctx_t *);
1107c478bd9Sstevel@tonic-gate 
1117c478bd9Sstevel@tonic-gate static crypto_ctx_ops_t rc4_ctx_ops = {
1127c478bd9Sstevel@tonic-gate 	NULL,
1137c478bd9Sstevel@tonic-gate 	rc4_free_context
1147c478bd9Sstevel@tonic-gate };
1157c478bd9Sstevel@tonic-gate 
1167c478bd9Sstevel@tonic-gate static crypto_ops_t rc4_crypto_ops = {
1177c478bd9Sstevel@tonic-gate 	&rc4_control_ops,
1187c478bd9Sstevel@tonic-gate 	NULL,
1197c478bd9Sstevel@tonic-gate 	&rc4_cipher_ops,
1207c478bd9Sstevel@tonic-gate 	NULL,
1217c478bd9Sstevel@tonic-gate 	NULL,
1227c478bd9Sstevel@tonic-gate 	NULL,
1237c478bd9Sstevel@tonic-gate 	NULL,
1247c478bd9Sstevel@tonic-gate 	NULL,
1257c478bd9Sstevel@tonic-gate 	NULL,
1267c478bd9Sstevel@tonic-gate 	NULL,
1277c478bd9Sstevel@tonic-gate 	NULL,
1287c478bd9Sstevel@tonic-gate 	NULL,
1297c478bd9Sstevel@tonic-gate 	NULL,
1307c478bd9Sstevel@tonic-gate 	&rc4_ctx_ops
1317c478bd9Sstevel@tonic-gate };
1327c478bd9Sstevel@tonic-gate 
1337c478bd9Sstevel@tonic-gate static crypto_provider_info_t rc4_prov_info = {
1347c478bd9Sstevel@tonic-gate 	CRYPTO_SPI_VERSION_1,
1357c478bd9Sstevel@tonic-gate 	"RC4 Software Provider",
1367c478bd9Sstevel@tonic-gate 	CRYPTO_SW_PROVIDER,
1377c478bd9Sstevel@tonic-gate 	{&modlinkage},
1387c478bd9Sstevel@tonic-gate 	NULL,
1397c478bd9Sstevel@tonic-gate 	&rc4_crypto_ops,
1407c478bd9Sstevel@tonic-gate 	sizeof (rc4_mech_info_tab)/sizeof (crypto_mech_info_t),
1417c478bd9Sstevel@tonic-gate 	rc4_mech_info_tab
1427c478bd9Sstevel@tonic-gate };
1437c478bd9Sstevel@tonic-gate 
1447c478bd9Sstevel@tonic-gate static crypto_kcf_provider_handle_t rc4_prov_handle = NULL;
1457c478bd9Sstevel@tonic-gate 
1467c478bd9Sstevel@tonic-gate static mblk_t *advance_position(mblk_t *, off_t, uchar_t **);
1477c478bd9Sstevel@tonic-gate static int crypto_arcfour_crypt(ARCFour_key *, uchar_t *, crypto_data_t *,
1487c478bd9Sstevel@tonic-gate     int);
1497c478bd9Sstevel@tonic-gate 
1507c478bd9Sstevel@tonic-gate int
1517c478bd9Sstevel@tonic-gate _init(void)
1527c478bd9Sstevel@tonic-gate {
1537c478bd9Sstevel@tonic-gate 	int ret;
1547c478bd9Sstevel@tonic-gate 
155*d3b2efc7SAnthony Scarpino 	if ((ret = mod_install(&modlinkage)) != 0)
156*d3b2efc7SAnthony Scarpino 		return (ret);
157*d3b2efc7SAnthony Scarpino 
158*d3b2efc7SAnthony Scarpino 	/* Register with KCF.  If the registration fails, remove the module. */
159*d3b2efc7SAnthony Scarpino 	if (crypto_register_provider(&rc4_prov_info, &rc4_prov_handle)) {
160*d3b2efc7SAnthony Scarpino 		(void) mod_remove(&modlinkage);
1617c478bd9Sstevel@tonic-gate 		return (EACCES);
1627c478bd9Sstevel@tonic-gate 	}
1637c478bd9Sstevel@tonic-gate 
1647c478bd9Sstevel@tonic-gate 	return (0);
1657c478bd9Sstevel@tonic-gate }
1667c478bd9Sstevel@tonic-gate 
1677c478bd9Sstevel@tonic-gate int
1687c478bd9Sstevel@tonic-gate _fini(void)
1697c478bd9Sstevel@tonic-gate {
170*d3b2efc7SAnthony Scarpino 	/* Unregister from KCF if module is registered */
1717c478bd9Sstevel@tonic-gate 	if (rc4_prov_handle != NULL) {
172*d3b2efc7SAnthony Scarpino 		if (crypto_unregister_provider(rc4_prov_handle))
1737c478bd9Sstevel@tonic-gate 			return (EBUSY);
174*d3b2efc7SAnthony Scarpino 
1757c478bd9Sstevel@tonic-gate 		rc4_prov_handle = NULL;
1767c478bd9Sstevel@tonic-gate 	}
1777c478bd9Sstevel@tonic-gate 
1787c478bd9Sstevel@tonic-gate 	return (mod_remove(&modlinkage));
1797c478bd9Sstevel@tonic-gate }
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate int
1827c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
1837c478bd9Sstevel@tonic-gate {
1847c478bd9Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
1857c478bd9Sstevel@tonic-gate }
1867c478bd9Sstevel@tonic-gate 
1877c478bd9Sstevel@tonic-gate 
1887c478bd9Sstevel@tonic-gate /*
1897c478bd9Sstevel@tonic-gate  * KCF software provider control entry points.
1907c478bd9Sstevel@tonic-gate  */
1917c478bd9Sstevel@tonic-gate /* ARGSUSED */
1927c478bd9Sstevel@tonic-gate static void
1937c478bd9Sstevel@tonic-gate rc4_provider_status(crypto_provider_handle_t provider, uint_t *status)
1947c478bd9Sstevel@tonic-gate {
1957c478bd9Sstevel@tonic-gate 	*status = CRYPTO_PROVIDER_READY;
1967c478bd9Sstevel@tonic-gate }
1977c478bd9Sstevel@tonic-gate 
1987c478bd9Sstevel@tonic-gate /* ARGSUSED */
1997c478bd9Sstevel@tonic-gate static int
2007c478bd9Sstevel@tonic-gate rc4_common_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism,
2017c478bd9Sstevel@tonic-gate     crypto_key_t *key, crypto_spi_ctx_template_t template,
2027c478bd9Sstevel@tonic-gate     crypto_req_handle_t req)
2037c478bd9Sstevel@tonic-gate {
2047c478bd9Sstevel@tonic-gate 	ARCFour_key *keystream;
2057c478bd9Sstevel@tonic-gate 
2067c478bd9Sstevel@tonic-gate 	if ((mechanism)->cm_type != RC4_MECH_INFO_TYPE)
2077c478bd9Sstevel@tonic-gate 		return (CRYPTO_MECHANISM_INVALID);
2087c478bd9Sstevel@tonic-gate 
2097c478bd9Sstevel@tonic-gate 	if (key->ck_format != CRYPTO_KEY_RAW)
2107c478bd9Sstevel@tonic-gate 		return (CRYPTO_KEY_TYPE_INCONSISTENT);
2117c478bd9Sstevel@tonic-gate 
2127c478bd9Sstevel@tonic-gate 	if (key->ck_length < ARCFOUR_MIN_KEY_BITS ||
2137c478bd9Sstevel@tonic-gate 	    key->ck_length > ARCFOUR_MAX_KEY_BITS) {
2147c478bd9Sstevel@tonic-gate 		return (CRYPTO_KEY_SIZE_RANGE);
2157c478bd9Sstevel@tonic-gate 	}
2167c478bd9Sstevel@tonic-gate 
2177c478bd9Sstevel@tonic-gate 	/*
2187c478bd9Sstevel@tonic-gate 	 * Allocate an RC4 key stream.
2197c478bd9Sstevel@tonic-gate 	 */
2207c478bd9Sstevel@tonic-gate 	if ((keystream = kmem_alloc(sizeof (ARCFour_key),
2217c478bd9Sstevel@tonic-gate 	    crypto_kmflag(req))) == NULL)
2227c478bd9Sstevel@tonic-gate 		return (CRYPTO_HOST_MEMORY);
2237c478bd9Sstevel@tonic-gate 
22495014fbbSDan OpenSolaris Anderson 	arcfour_key_init(keystream, key->ck_data,
22595014fbbSDan OpenSolaris Anderson 	    CRYPTO_BITS2BYTES(key->ck_length));
2267c478bd9Sstevel@tonic-gate 
2277c478bd9Sstevel@tonic-gate 	ctx->cc_provider_private = keystream;
2287c478bd9Sstevel@tonic-gate 
2297c478bd9Sstevel@tonic-gate 	return (CRYPTO_SUCCESS);
2307c478bd9Sstevel@tonic-gate }
2317c478bd9Sstevel@tonic-gate 
2327c478bd9Sstevel@tonic-gate static int
2337c478bd9Sstevel@tonic-gate rc4_crypt(crypto_ctx_t *ctx, crypto_data_t *input, crypto_data_t *output,
2347c478bd9Sstevel@tonic-gate     crypto_req_handle_t req)
2357c478bd9Sstevel@tonic-gate {
2367c478bd9Sstevel@tonic-gate 	int ret;
2377c478bd9Sstevel@tonic-gate 
2387c478bd9Sstevel@tonic-gate 	ret = rc4_crypt_update(ctx, input, output, req);
2397c478bd9Sstevel@tonic-gate 
2407c478bd9Sstevel@tonic-gate 	if (ret != CRYPTO_BUFFER_TOO_SMALL)
2417c478bd9Sstevel@tonic-gate 		(void) rc4_free_context(ctx);
2427c478bd9Sstevel@tonic-gate 
2437c478bd9Sstevel@tonic-gate 	return (ret);
2447c478bd9Sstevel@tonic-gate }
2457c478bd9Sstevel@tonic-gate 
2467c478bd9Sstevel@tonic-gate /* ARGSUSED */
2477c478bd9Sstevel@tonic-gate static int
2487c478bd9Sstevel@tonic-gate rc4_crypt_update(crypto_ctx_t *ctx, crypto_data_t *input, crypto_data_t *output,
2497c478bd9Sstevel@tonic-gate     crypto_req_handle_t req)
2507c478bd9Sstevel@tonic-gate {
2517c478bd9Sstevel@tonic-gate 	int ret = CRYPTO_SUCCESS;
2527c478bd9Sstevel@tonic-gate 
2537c478bd9Sstevel@tonic-gate 	ARCFour_key *key;
2547c478bd9Sstevel@tonic-gate 	off_t saveoffset;
2557c478bd9Sstevel@tonic-gate 
2567c478bd9Sstevel@tonic-gate 	ASSERT(ctx->cc_provider_private != NULL);
2577c478bd9Sstevel@tonic-gate 
2586a1073f8Skrishna 	if ((ctx->cc_flags & CRYPTO_USE_OPSTATE) && ctx->cc_opstate != NULL)
2596a1073f8Skrishna 		key = ctx->cc_opstate;
2606a1073f8Skrishna 	else
2617c478bd9Sstevel@tonic-gate 		key = ctx->cc_provider_private;
2627c478bd9Sstevel@tonic-gate 
2637c478bd9Sstevel@tonic-gate 	/* Simple case: in-line encipherment */
2647c478bd9Sstevel@tonic-gate 
2657c478bd9Sstevel@tonic-gate 	if (output == NULL) {
2667c478bd9Sstevel@tonic-gate 		switch (input->cd_format) {
2677c478bd9Sstevel@tonic-gate 		case CRYPTO_DATA_RAW: {
2687c478bd9Sstevel@tonic-gate 			char *start, *end;
2697c478bd9Sstevel@tonic-gate 			start = input->cd_raw.iov_base + input->cd_offset;
2707c478bd9Sstevel@tonic-gate 
2717c478bd9Sstevel@tonic-gate 			end =  input->cd_raw.iov_base + input->cd_raw.iov_len;
2727c478bd9Sstevel@tonic-gate 
2737c478bd9Sstevel@tonic-gate 			if (start + input->cd_length > end)
2747c478bd9Sstevel@tonic-gate 				return (CRYPTO_DATA_INVALID);
2757c478bd9Sstevel@tonic-gate 
2767c478bd9Sstevel@tonic-gate 			arcfour_crypt(key, (uchar_t *)start, (uchar_t *)start,
2777c478bd9Sstevel@tonic-gate 			    input->cd_length);
2787c478bd9Sstevel@tonic-gate 			break;
2797c478bd9Sstevel@tonic-gate 		}
2807c478bd9Sstevel@tonic-gate 		case CRYPTO_DATA_MBLK: {
2817c478bd9Sstevel@tonic-gate 			uchar_t *start, *end;
2827c478bd9Sstevel@tonic-gate 			size_t len, left;
2837c478bd9Sstevel@tonic-gate 			mblk_t *mp = input->cd_mp, *mp1, *mp2;
2847c478bd9Sstevel@tonic-gate 
2857c478bd9Sstevel@tonic-gate 			ASSERT(mp != NULL);
2867c478bd9Sstevel@tonic-gate 
2877c478bd9Sstevel@tonic-gate 			mp1 = advance_position(mp, input->cd_offset, &start);
2887c478bd9Sstevel@tonic-gate 
2897c478bd9Sstevel@tonic-gate 			if (mp1 == NULL)
2907c478bd9Sstevel@tonic-gate 				return (CRYPTO_DATA_LEN_RANGE);
2917c478bd9Sstevel@tonic-gate 
2927c478bd9Sstevel@tonic-gate 			mp2 = advance_position(mp, input->cd_offset +
2937c478bd9Sstevel@tonic-gate 			    input->cd_length, &end);
2947c478bd9Sstevel@tonic-gate 
2957c478bd9Sstevel@tonic-gate 			if (mp2 == NULL)
2967c478bd9Sstevel@tonic-gate 				return (CRYPTO_DATA_LEN_RANGE);
2977c478bd9Sstevel@tonic-gate 
2987c478bd9Sstevel@tonic-gate 			left = input->cd_length;
2997c478bd9Sstevel@tonic-gate 			while (mp1 != NULL) {
30092a8e44dSDan OpenSolaris Anderson 				if (_PTRDIFF(mp1->b_wptr, start) > left) {
3017c478bd9Sstevel@tonic-gate 					len = left;
3027c478bd9Sstevel@tonic-gate 					arcfour_crypt(key, start, start, len);
3037c478bd9Sstevel@tonic-gate 					mp1 = NULL;
3047c478bd9Sstevel@tonic-gate 				} else {
30592a8e44dSDan OpenSolaris Anderson 					len = _PTRDIFF(mp1->b_wptr, start);
3067c478bd9Sstevel@tonic-gate 					arcfour_crypt(key, start, start, len);
3077c478bd9Sstevel@tonic-gate 					mp1 = mp1->b_cont;
3087c478bd9Sstevel@tonic-gate 					start = mp1->b_rptr;
3097c478bd9Sstevel@tonic-gate 					left -= len;
3107c478bd9Sstevel@tonic-gate 				}
3117c478bd9Sstevel@tonic-gate 			}
3127c478bd9Sstevel@tonic-gate 			break;
3137c478bd9Sstevel@tonic-gate 		}
3147c478bd9Sstevel@tonic-gate 		case CRYPTO_DATA_UIO: {
3157c478bd9Sstevel@tonic-gate 			uio_t *uiop = input->cd_uio;
3167c478bd9Sstevel@tonic-gate 			off_t offset = input->cd_offset;
3177c478bd9Sstevel@tonic-gate 			size_t length = input->cd_length;
3187c478bd9Sstevel@tonic-gate 			uint_t vec_idx;
3197c478bd9Sstevel@tonic-gate 			size_t cur_len;
3207c478bd9Sstevel@tonic-gate 
3217c478bd9Sstevel@tonic-gate 			/*
3227c478bd9Sstevel@tonic-gate 			 * Jump to the first iovec containing data to be
3237c478bd9Sstevel@tonic-gate 			 * processed.
3247c478bd9Sstevel@tonic-gate 			 */
3257c478bd9Sstevel@tonic-gate 			for (vec_idx = 0; vec_idx < uiop->uio_iovcnt &&
3267c478bd9Sstevel@tonic-gate 			    offset >= uiop->uio_iov[vec_idx].iov_len;
327d2b32306Smcpowers 			    offset -= uiop->uio_iov[vec_idx++].iov_len)
328d2b32306Smcpowers 				;
3297c478bd9Sstevel@tonic-gate 			if (vec_idx == uiop->uio_iovcnt) {
3307c478bd9Sstevel@tonic-gate 				return (CRYPTO_DATA_LEN_RANGE);
3317c478bd9Sstevel@tonic-gate 			}
3327c478bd9Sstevel@tonic-gate 
3337c478bd9Sstevel@tonic-gate 			/*
3347c478bd9Sstevel@tonic-gate 			 * Now process the iovecs.
3357c478bd9Sstevel@tonic-gate 			 */
3367c478bd9Sstevel@tonic-gate 			while (vec_idx < uiop->uio_iovcnt && length > 0) {
3377c478bd9Sstevel@tonic-gate 				uchar_t *start;
3387c478bd9Sstevel@tonic-gate 				iovec_t *iovp = &(uiop->uio_iov[vec_idx]);
3397c478bd9Sstevel@tonic-gate 
3407c478bd9Sstevel@tonic-gate 				cur_len = MIN(iovp->iov_len - offset, length);
3417c478bd9Sstevel@tonic-gate 
3427c478bd9Sstevel@tonic-gate 				start = (uchar_t *)(iovp->iov_base + offset);
3437c478bd9Sstevel@tonic-gate 				arcfour_crypt(key, start + offset,
3447c478bd9Sstevel@tonic-gate 				    start + offset, cur_len);
3457c478bd9Sstevel@tonic-gate 
3467c478bd9Sstevel@tonic-gate 				length -= cur_len;
3477c478bd9Sstevel@tonic-gate 				vec_idx++;
3487c478bd9Sstevel@tonic-gate 				offset = 0;
3497c478bd9Sstevel@tonic-gate 			}
3507c478bd9Sstevel@tonic-gate 
3517c478bd9Sstevel@tonic-gate 			if (vec_idx == uiop->uio_iovcnt && length > 0) {
3527c478bd9Sstevel@tonic-gate 
3537c478bd9Sstevel@tonic-gate 				return (CRYPTO_DATA_LEN_RANGE);
3547c478bd9Sstevel@tonic-gate 			}
3557c478bd9Sstevel@tonic-gate 			break;
3567c478bd9Sstevel@tonic-gate 		}
3577c478bd9Sstevel@tonic-gate 		}
3587c478bd9Sstevel@tonic-gate 		return (CRYPTO_SUCCESS);
3597c478bd9Sstevel@tonic-gate 	}
3607c478bd9Sstevel@tonic-gate 
3617c478bd9Sstevel@tonic-gate 	/*
3627c478bd9Sstevel@tonic-gate 	 * We need to just return the length needed to store the output.
3637c478bd9Sstevel@tonic-gate 	 * We should not destroy the context for the following case.
3647c478bd9Sstevel@tonic-gate 	 */
3657c478bd9Sstevel@tonic-gate 
3667c478bd9Sstevel@tonic-gate 	if (input->cd_length > output->cd_length) {
3677c478bd9Sstevel@tonic-gate 		output->cd_length = input->cd_length;
3687c478bd9Sstevel@tonic-gate 		return (CRYPTO_BUFFER_TOO_SMALL);
3697c478bd9Sstevel@tonic-gate 	}
3707c478bd9Sstevel@tonic-gate 
3717c478bd9Sstevel@tonic-gate 	saveoffset = output->cd_offset;
3727c478bd9Sstevel@tonic-gate 
3737c478bd9Sstevel@tonic-gate 	switch (input->cd_format) {
3747c478bd9Sstevel@tonic-gate 	case CRYPTO_DATA_RAW: {
3757c478bd9Sstevel@tonic-gate 		char *start, *end;
3767c478bd9Sstevel@tonic-gate 		start = input->cd_raw.iov_base + input->cd_offset;
3777c478bd9Sstevel@tonic-gate 
3787c478bd9Sstevel@tonic-gate 		end =  input->cd_raw.iov_base + input->cd_raw.iov_len;
3797c478bd9Sstevel@tonic-gate 
3807c478bd9Sstevel@tonic-gate 		if (start + input->cd_length > end)
3817c478bd9Sstevel@tonic-gate 			return (CRYPTO_DATA_LEN_RANGE);
3827c478bd9Sstevel@tonic-gate 
3837c478bd9Sstevel@tonic-gate 		ret = crypto_arcfour_crypt(key, (uchar_t *)start, output,
3847c478bd9Sstevel@tonic-gate 		    input->cd_length);
3857c478bd9Sstevel@tonic-gate 
3867c478bd9Sstevel@tonic-gate 		if (ret != CRYPTO_SUCCESS)
3877c478bd9Sstevel@tonic-gate 			return (ret);
3887c478bd9Sstevel@tonic-gate 		break;
3897c478bd9Sstevel@tonic-gate 	}
3907c478bd9Sstevel@tonic-gate 	case CRYPTO_DATA_MBLK: {
3917c478bd9Sstevel@tonic-gate 		uchar_t *start, *end;
3927c478bd9Sstevel@tonic-gate 		size_t len, left;
3937c478bd9Sstevel@tonic-gate 		mblk_t *mp = input->cd_mp, *mp1, *mp2;
3947c478bd9Sstevel@tonic-gate 
3957c478bd9Sstevel@tonic-gate 		ASSERT(mp != NULL);
3967c478bd9Sstevel@tonic-gate 
3977c478bd9Sstevel@tonic-gate 		mp1 = advance_position(mp, input->cd_offset, &start);
3987c478bd9Sstevel@tonic-gate 
3997c478bd9Sstevel@tonic-gate 		if (mp1 == NULL)
4007c478bd9Sstevel@tonic-gate 			return (CRYPTO_DATA_LEN_RANGE);
4017c478bd9Sstevel@tonic-gate 
4027c478bd9Sstevel@tonic-gate 		mp2 = advance_position(mp, input->cd_offset + input->cd_length,
4037c478bd9Sstevel@tonic-gate 		    &end);
4047c478bd9Sstevel@tonic-gate 
4057c478bd9Sstevel@tonic-gate 		if (mp2 == NULL)
4067c478bd9Sstevel@tonic-gate 			return (CRYPTO_DATA_LEN_RANGE);
4077c478bd9Sstevel@tonic-gate 
4087c478bd9Sstevel@tonic-gate 		left = input->cd_length;
4097c478bd9Sstevel@tonic-gate 		while (mp1 != NULL) {
41092a8e44dSDan OpenSolaris Anderson 			if (_PTRDIFF(mp1->b_wptr, start) > left) {
4117c478bd9Sstevel@tonic-gate 				len = left;
4127c478bd9Sstevel@tonic-gate 				ret = crypto_arcfour_crypt(key, start, output,
4137c478bd9Sstevel@tonic-gate 				    len);
4147c478bd9Sstevel@tonic-gate 				if (ret != CRYPTO_SUCCESS)
4157c478bd9Sstevel@tonic-gate 					return (ret);
4167c478bd9Sstevel@tonic-gate 				mp1 = NULL;
4177c478bd9Sstevel@tonic-gate 			} else {
41892a8e44dSDan OpenSolaris Anderson 				len = _PTRDIFF(mp1->b_wptr, start);
4197c478bd9Sstevel@tonic-gate 				ret = crypto_arcfour_crypt(key, start, output,
4207c478bd9Sstevel@tonic-gate 				    len);
4217c478bd9Sstevel@tonic-gate 				if (ret != CRYPTO_SUCCESS)
4227c478bd9Sstevel@tonic-gate 					return (ret);
4237c478bd9Sstevel@tonic-gate 				mp1 = mp1->b_cont;
4247c478bd9Sstevel@tonic-gate 				start = mp1->b_rptr;
4257c478bd9Sstevel@tonic-gate 				left -= len;
4267c478bd9Sstevel@tonic-gate 				output->cd_offset += len;
4277c478bd9Sstevel@tonic-gate 			}
4287c478bd9Sstevel@tonic-gate 		}
4297c478bd9Sstevel@tonic-gate 		break;
4307c478bd9Sstevel@tonic-gate 	}
4317c478bd9Sstevel@tonic-gate 	case CRYPTO_DATA_UIO: {
4327c478bd9Sstevel@tonic-gate 		uio_t *uiop = input->cd_uio;
4337c478bd9Sstevel@tonic-gate 		off_t offset = input->cd_offset;
4347c478bd9Sstevel@tonic-gate 		size_t length = input->cd_length;
4357c478bd9Sstevel@tonic-gate 		uint_t vec_idx;
4367c478bd9Sstevel@tonic-gate 		size_t cur_len;
4377c478bd9Sstevel@tonic-gate 
4387c478bd9Sstevel@tonic-gate 		/*
4397c478bd9Sstevel@tonic-gate 		 * Jump to the first iovec containing data to be
4407c478bd9Sstevel@tonic-gate 		 * processed.
4417c478bd9Sstevel@tonic-gate 		 */
4427c478bd9Sstevel@tonic-gate 		for (vec_idx = 0; vec_idx < uiop->uio_iovcnt &&
4437c478bd9Sstevel@tonic-gate 		    offset >= uiop->uio_iov[vec_idx].iov_len;
444d2b32306Smcpowers 		    offset -= uiop->uio_iov[vec_idx++].iov_len)
445d2b32306Smcpowers 			;
4467c478bd9Sstevel@tonic-gate 		if (vec_idx == uiop->uio_iovcnt) {
4477c478bd9Sstevel@tonic-gate 			return (CRYPTO_DATA_LEN_RANGE);
4487c478bd9Sstevel@tonic-gate 		}
4497c478bd9Sstevel@tonic-gate 
4507c478bd9Sstevel@tonic-gate 		/*
4517c478bd9Sstevel@tonic-gate 		 * Now process the iovecs.
4527c478bd9Sstevel@tonic-gate 		 */
4537c478bd9Sstevel@tonic-gate 		while (vec_idx < uiop->uio_iovcnt && length > 0) {
4547c478bd9Sstevel@tonic-gate 			uchar_t *start;
4557c478bd9Sstevel@tonic-gate 			iovec_t *iovp = &(uiop->uio_iov[vec_idx]);
4567c478bd9Sstevel@tonic-gate 			cur_len = MIN(iovp->iov_len - offset, length);
4577c478bd9Sstevel@tonic-gate 
4587c478bd9Sstevel@tonic-gate 			start = (uchar_t *)(iovp->iov_base + offset);
4597c478bd9Sstevel@tonic-gate 			ret = crypto_arcfour_crypt(key, start + offset,
4607c478bd9Sstevel@tonic-gate 			    output, cur_len);
4617c478bd9Sstevel@tonic-gate 			if (ret != CRYPTO_SUCCESS)
4627c478bd9Sstevel@tonic-gate 				return (ret);
4637c478bd9Sstevel@tonic-gate 
4647c478bd9Sstevel@tonic-gate 			length -= cur_len;
4657c478bd9Sstevel@tonic-gate 			vec_idx++;
4667c478bd9Sstevel@tonic-gate 			offset = 0;
4677c478bd9Sstevel@tonic-gate 			output->cd_offset += cur_len;
4687c478bd9Sstevel@tonic-gate 		}
4697c478bd9Sstevel@tonic-gate 
4707c478bd9Sstevel@tonic-gate 		if (vec_idx == uiop->uio_iovcnt && length > 0) {
4717c478bd9Sstevel@tonic-gate 
4727c478bd9Sstevel@tonic-gate 			return (CRYPTO_DATA_LEN_RANGE);
4737c478bd9Sstevel@tonic-gate 		}
4747c478bd9Sstevel@tonic-gate 	}
4757c478bd9Sstevel@tonic-gate 	}
4767c478bd9Sstevel@tonic-gate 
4777c478bd9Sstevel@tonic-gate 	output->cd_offset = saveoffset;
4787c478bd9Sstevel@tonic-gate 	output->cd_length = input->cd_length;
4797c478bd9Sstevel@tonic-gate 
4807c478bd9Sstevel@tonic-gate 	return (ret);
4817c478bd9Sstevel@tonic-gate }
4827c478bd9Sstevel@tonic-gate 
4837c478bd9Sstevel@tonic-gate /* ARGSUSED */
4847c478bd9Sstevel@tonic-gate static int rc4_crypt_final(crypto_ctx_t *ctx, crypto_data_t *data,
4857c478bd9Sstevel@tonic-gate     crypto_req_handle_t req)
4867c478bd9Sstevel@tonic-gate {
4877c478bd9Sstevel@tonic-gate 	/* No final part for streams ciphers. Just free the context */
4887c478bd9Sstevel@tonic-gate 	if (data != NULL)
4897c478bd9Sstevel@tonic-gate 		data->cd_length = 0;
4907c478bd9Sstevel@tonic-gate 
4917c478bd9Sstevel@tonic-gate 	return (rc4_free_context(ctx));
4927c478bd9Sstevel@tonic-gate }
4937c478bd9Sstevel@tonic-gate 
4947c478bd9Sstevel@tonic-gate /* ARGSUSED */
4957c478bd9Sstevel@tonic-gate static int
4967c478bd9Sstevel@tonic-gate rc4_crypt_atomic(crypto_provider_handle_t handle, crypto_session_id_t session,
4977c478bd9Sstevel@tonic-gate     crypto_mechanism_t *mechanism, crypto_key_t *key, crypto_data_t *input,
4987c478bd9Sstevel@tonic-gate     crypto_data_t *output, crypto_spi_ctx_template_t template,
4997c478bd9Sstevel@tonic-gate     crypto_req_handle_t req)
5007c478bd9Sstevel@tonic-gate {
5017c478bd9Sstevel@tonic-gate 	crypto_ctx_t ctx;
5027c478bd9Sstevel@tonic-gate 	int ret;
5037c478bd9Sstevel@tonic-gate 
5046a1073f8Skrishna 	bzero(&ctx, sizeof (crypto_ctx_t));
5057c478bd9Sstevel@tonic-gate 	ret = rc4_common_init(&ctx, mechanism, key, template, req);
5067c478bd9Sstevel@tonic-gate 
5077c478bd9Sstevel@tonic-gate 	if (ret != CRYPTO_SUCCESS)
5087c478bd9Sstevel@tonic-gate 		return (ret);
5097c478bd9Sstevel@tonic-gate 
5107c478bd9Sstevel@tonic-gate 	ret = rc4_crypt_update(&ctx, input, output, req);
5117c478bd9Sstevel@tonic-gate 
5127c478bd9Sstevel@tonic-gate 	(void) rc4_free_context(&ctx);
5137c478bd9Sstevel@tonic-gate 
5147c478bd9Sstevel@tonic-gate 	return (ret);
5157c478bd9Sstevel@tonic-gate }
5167c478bd9Sstevel@tonic-gate 
5177c478bd9Sstevel@tonic-gate /* ARGSUSED */
5187c478bd9Sstevel@tonic-gate static int
5197c478bd9Sstevel@tonic-gate rc4_free_context(crypto_ctx_t *ctx)
5207c478bd9Sstevel@tonic-gate {
5217c478bd9Sstevel@tonic-gate 	ARCFour_key *keystream = ctx->cc_provider_private;
5227c478bd9Sstevel@tonic-gate 
5237c478bd9Sstevel@tonic-gate 	if (keystream != NULL) {
5247c478bd9Sstevel@tonic-gate 		bzero(keystream, sizeof (ARCFour_key));
5257c478bd9Sstevel@tonic-gate 		kmem_free(keystream, sizeof (ARCFour_key));
5267c478bd9Sstevel@tonic-gate 		ctx->cc_provider_private = NULL;
5277c478bd9Sstevel@tonic-gate 	}
5287c478bd9Sstevel@tonic-gate 
5297c478bd9Sstevel@tonic-gate 	return (CRYPTO_SUCCESS);
5307c478bd9Sstevel@tonic-gate }
5317c478bd9Sstevel@tonic-gate 
5327c478bd9Sstevel@tonic-gate /* Encrypts a contiguous input 'in' into the 'out' crypto_data_t */
5337c478bd9Sstevel@tonic-gate 
5347c478bd9Sstevel@tonic-gate static int
5357c478bd9Sstevel@tonic-gate crypto_arcfour_crypt(ARCFour_key *key, uchar_t *in, crypto_data_t *out,
5367c478bd9Sstevel@tonic-gate     int length)
5377c478bd9Sstevel@tonic-gate {
5387c478bd9Sstevel@tonic-gate 	switch (out->cd_format) {
5397c478bd9Sstevel@tonic-gate 		case CRYPTO_DATA_RAW: {
5407c478bd9Sstevel@tonic-gate 			uchar_t *start, *end;
5417c478bd9Sstevel@tonic-gate 			start = (uchar_t *)(out->cd_raw.iov_base +
5427c478bd9Sstevel@tonic-gate 			    out->cd_offset);
5437c478bd9Sstevel@tonic-gate 
5447c478bd9Sstevel@tonic-gate 			end = (uchar_t *)(out->cd_raw.iov_base +
5457c478bd9Sstevel@tonic-gate 			    out->cd_raw.iov_len);
5467c478bd9Sstevel@tonic-gate 
5477c478bd9Sstevel@tonic-gate 			if (start + out->cd_length > end)
5487c478bd9Sstevel@tonic-gate 				return (CRYPTO_DATA_LEN_RANGE);
5497c478bd9Sstevel@tonic-gate 
5507c478bd9Sstevel@tonic-gate 			arcfour_crypt(key, in, start, length);
5517c478bd9Sstevel@tonic-gate 
5527c478bd9Sstevel@tonic-gate 			return (CRYPTO_SUCCESS);
5537c478bd9Sstevel@tonic-gate 		}
5547c478bd9Sstevel@tonic-gate 		case CRYPTO_DATA_MBLK: {
5557c478bd9Sstevel@tonic-gate 			uchar_t *start, *end;
5567c478bd9Sstevel@tonic-gate 			size_t len, left;
5577c478bd9Sstevel@tonic-gate 			mblk_t *mp = out->cd_mp, *mp1, *mp2;
5587c478bd9Sstevel@tonic-gate 
5597c478bd9Sstevel@tonic-gate 			ASSERT(mp != NULL);
5607c478bd9Sstevel@tonic-gate 
5617c478bd9Sstevel@tonic-gate 			mp1 = advance_position(mp, out->cd_offset, &start);
5627c478bd9Sstevel@tonic-gate 
5637c478bd9Sstevel@tonic-gate 			if (mp1 == NULL)
5647c478bd9Sstevel@tonic-gate 				return (CRYPTO_DATA_LEN_RANGE);
5657c478bd9Sstevel@tonic-gate 
5667c478bd9Sstevel@tonic-gate 			mp2 = advance_position(mp, out->cd_offset +
5677c478bd9Sstevel@tonic-gate 			    out->cd_length, &end);
5687c478bd9Sstevel@tonic-gate 
5697c478bd9Sstevel@tonic-gate 			if (mp2 == NULL)
5707c478bd9Sstevel@tonic-gate 				return (CRYPTO_DATA_LEN_RANGE);
5717c478bd9Sstevel@tonic-gate 
5727c478bd9Sstevel@tonic-gate 			left = length;
5737c478bd9Sstevel@tonic-gate 			while (mp1 != NULL) {
57492a8e44dSDan OpenSolaris Anderson 				if (_PTRDIFF(mp1->b_wptr, start) > left) {
5757c478bd9Sstevel@tonic-gate 					len = left;
5767c478bd9Sstevel@tonic-gate 					arcfour_crypt(key, in, start, len);
5777c478bd9Sstevel@tonic-gate 					mp1 = NULL;
5787c478bd9Sstevel@tonic-gate 				} else {
57992a8e44dSDan OpenSolaris Anderson 					len = _PTRDIFF(mp1->b_wptr, start);
5807c478bd9Sstevel@tonic-gate 					arcfour_crypt(key, in, start, len);
5817c478bd9Sstevel@tonic-gate 					mp1 = mp1->b_cont;
5827c478bd9Sstevel@tonic-gate 					start = mp1->b_rptr;
5837c478bd9Sstevel@tonic-gate 					left -= len;
5847c478bd9Sstevel@tonic-gate 				}
5857c478bd9Sstevel@tonic-gate 			}
5867c478bd9Sstevel@tonic-gate 			break;
5877c478bd9Sstevel@tonic-gate 		}
5887c478bd9Sstevel@tonic-gate 		case CRYPTO_DATA_UIO: {
5897c478bd9Sstevel@tonic-gate 			uio_t *uiop = out->cd_uio;
5907c478bd9Sstevel@tonic-gate 			off_t offset = out->cd_offset;
5917c478bd9Sstevel@tonic-gate 			size_t len = length;
5927c478bd9Sstevel@tonic-gate 			uint_t vec_idx;
5937c478bd9Sstevel@tonic-gate 			size_t cur_len;
5947c478bd9Sstevel@tonic-gate 
5957c478bd9Sstevel@tonic-gate 			/*
5967c478bd9Sstevel@tonic-gate 			 * Jump to the first iovec containing data to be
5977c478bd9Sstevel@tonic-gate 			 * processed.
5987c478bd9Sstevel@tonic-gate 			 */
5997c478bd9Sstevel@tonic-gate 			for (vec_idx = 0; vec_idx < uiop->uio_iovcnt &&
6007c478bd9Sstevel@tonic-gate 			    offset >= uiop->uio_iov[vec_idx].iov_len;
601d2b32306Smcpowers 			    offset -= uiop->uio_iov[vec_idx++].iov_len)
602d2b32306Smcpowers 				;
6037c478bd9Sstevel@tonic-gate 			if (vec_idx == uiop->uio_iovcnt) {
6047c478bd9Sstevel@tonic-gate 				return (CRYPTO_DATA_LEN_RANGE);
6057c478bd9Sstevel@tonic-gate 			}
6067c478bd9Sstevel@tonic-gate 
6077c478bd9Sstevel@tonic-gate 			/*
6087c478bd9Sstevel@tonic-gate 			 * Now process the iovecs.
6097c478bd9Sstevel@tonic-gate 			 */
6107c478bd9Sstevel@tonic-gate 			while (vec_idx < uiop->uio_iovcnt && len > 0) {
6117c478bd9Sstevel@tonic-gate 				uchar_t *start;
6127c478bd9Sstevel@tonic-gate 				iovec_t *iovp = &(uiop->uio_iov[vec_idx]);
6137c478bd9Sstevel@tonic-gate 				cur_len = MIN(iovp->iov_len - offset, len);
6147c478bd9Sstevel@tonic-gate 
6157c478bd9Sstevel@tonic-gate 				start = (uchar_t *)(iovp->iov_base + offset);
6167c478bd9Sstevel@tonic-gate 				arcfour_crypt(key, start + offset,
6177c478bd9Sstevel@tonic-gate 				    start + offset, cur_len);
6187c478bd9Sstevel@tonic-gate 
6197c478bd9Sstevel@tonic-gate 				len -= cur_len;
6207c478bd9Sstevel@tonic-gate 				vec_idx++;
6217c478bd9Sstevel@tonic-gate 				offset = 0;
6227c478bd9Sstevel@tonic-gate 			}
6237c478bd9Sstevel@tonic-gate 
6247c478bd9Sstevel@tonic-gate 			if (vec_idx == uiop->uio_iovcnt && len > 0) {
6257c478bd9Sstevel@tonic-gate 				return (CRYPTO_DATA_LEN_RANGE);
6267c478bd9Sstevel@tonic-gate 			}
6277c478bd9Sstevel@tonic-gate 			break;
6287c478bd9Sstevel@tonic-gate 		}
6297c478bd9Sstevel@tonic-gate 		default:
6307c478bd9Sstevel@tonic-gate 			return (CRYPTO_DATA_INVALID);
6317c478bd9Sstevel@tonic-gate 	}
6327c478bd9Sstevel@tonic-gate 	return (CRYPTO_SUCCESS);
6337c478bd9Sstevel@tonic-gate }
6347c478bd9Sstevel@tonic-gate 
6357c478bd9Sstevel@tonic-gate /*
6367c478bd9Sstevel@tonic-gate  * Advances 'offset' bytes from the beginning of the first block in 'mp',
6377c478bd9Sstevel@tonic-gate  * possibly jumping across b_cont boundary
6387c478bd9Sstevel@tonic-gate  * '*cpp' is set to the position of the byte we want, and the block where
6397c478bd9Sstevel@tonic-gate  * 'cpp' is returned.
6407c478bd9Sstevel@tonic-gate  */
6417c478bd9Sstevel@tonic-gate static mblk_t *
6427c478bd9Sstevel@tonic-gate advance_position(mblk_t *mp, off_t offset, uchar_t **cpp)
6437c478bd9Sstevel@tonic-gate {
6447c478bd9Sstevel@tonic-gate 	mblk_t *mp1 = mp;
6457c478bd9Sstevel@tonic-gate 	size_t l;
6467c478bd9Sstevel@tonic-gate 	off_t o = offset;
6477c478bd9Sstevel@tonic-gate 
6487c478bd9Sstevel@tonic-gate 	while (mp1 != NULL) {
6497c478bd9Sstevel@tonic-gate 		l = MBLKL(mp1);
6507c478bd9Sstevel@tonic-gate 
6517c478bd9Sstevel@tonic-gate 		if (l <= o) {
6527c478bd9Sstevel@tonic-gate 			o -= l;
6537c478bd9Sstevel@tonic-gate 			mp1 = mp1->b_cont;
6547c478bd9Sstevel@tonic-gate 		} else {
6557c478bd9Sstevel@tonic-gate 			*cpp = (uchar_t *)(mp1->b_rptr + o);
6567c478bd9Sstevel@tonic-gate 			break;
6577c478bd9Sstevel@tonic-gate 		}
6587c478bd9Sstevel@tonic-gate 	}
6597c478bd9Sstevel@tonic-gate 	return (mp1);
6607c478bd9Sstevel@tonic-gate }
661