|
Packit Service |
4684c1 |
/*
|
|
Packit Service |
4684c1 |
* Copyright (C) 2019 Red Hat, Inc.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* Author: Daiki Ueno
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* This file is part of GnuTLS.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* The GnuTLS is free software; you can redistribute it and/or
|
|
Packit Service |
4684c1 |
* modify it under the terms of the GNU Lesser General Public License
|
|
Packit Service |
4684c1 |
* as published by the Free Software Foundation; either version 2.1 of
|
|
Packit Service |
4684c1 |
* the License, or (at your option) any later version.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* This library is distributed in the hope that it will be useful, but
|
|
Packit Service |
4684c1 |
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit Service |
4684c1 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit Service |
4684c1 |
* Lesser General Public License for more details.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* You should have received a copy of the GNU Lesser General Public License
|
|
Packit Service |
4684c1 |
* along with this program. If not, see <https://www.gnu.org/licenses/>
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
#include "gnutls_int.h"
|
|
Packit Service |
4684c1 |
#include "iov.h"
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/**
|
|
Packit Service |
4684c1 |
* _gnutls_iov_iter_init:
|
|
Packit Service |
4684c1 |
* @iter: the iterator
|
|
Packit Service |
4684c1 |
* @iov: the data buffers
|
|
Packit Service |
4684c1 |
* @iov_count: the number of data buffers
|
|
Packit Service |
4684c1 |
* @block_size: block size to iterate
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* Initialize the iterator.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise
|
|
Packit Service |
4684c1 |
* an error code is returned
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
int
|
|
Packit Service |
4684c1 |
_gnutls_iov_iter_init(struct iov_iter_st *iter,
|
|
Packit Service |
4684c1 |
const giovec_t *iov, size_t iov_count,
|
|
Packit Service |
4684c1 |
size_t block_size)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
if (unlikely(block_size > MAX_CIPHER_BLOCK_SIZE))
|
|
Packit Service |
4684c1 |
return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
iter->iov = iov;
|
|
Packit Service |
4684c1 |
iter->iov_count = iov_count;
|
|
Packit Service |
4684c1 |
iter->iov_index = 0;
|
|
Packit Service |
4684c1 |
iter->iov_offset = 0;
|
|
Packit Service |
4684c1 |
iter->block_size = block_size;
|
|
Packit Service |
4684c1 |
iter->block_offset = 0;
|
|
Packit Service |
4684c1 |
return 0;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/**
|
|
Packit Service |
4684c1 |
* _gnutls_iov_iter_next:
|
|
Packit Service |
4684c1 |
* @iter: the iterator
|
|
Packit Service |
4684c1 |
* @data: the return location of extracted data
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* Retrieve block(s) pointed by @iter and advance it to the next
|
|
Packit Service |
4684c1 |
* position. It returns the number of bytes in @data. At the end of
|
|
Packit Service |
4684c1 |
* iteration, 0 is returned.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* If the data stored in @iter is not multiple of the block size, the
|
|
Packit Service |
4684c1 |
* remaining data is stored in the "block" field of @iter with the
|
|
Packit Service |
4684c1 |
* size stored in the "block_offset" field.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* Returns: On success, a value greater than or equal to zero is
|
|
Packit Service |
4684c1 |
* returned, otherwise a negative error code is returned
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
ssize_t
|
|
Packit Service |
4684c1 |
_gnutls_iov_iter_next(struct iov_iter_st *iter, uint8_t **data)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
while (iter->iov_index < iter->iov_count) {
|
|
Packit Service |
4684c1 |
const giovec_t *iov = &iter->iov[iter->iov_index];
|
|
Packit Service |
4684c1 |
uint8_t *p = iov->iov_base;
|
|
Packit Service |
4684c1 |
size_t len = iov->iov_len;
|
|
Packit Service |
4684c1 |
size_t block_left;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (!p) {
|
|
Packit Service |
4684c1 |
// skip NULL iov entries, else we run into issues below
|
|
Packit Service |
4684c1 |
iter->iov_index++;
|
|
Packit Service |
4684c1 |
continue;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (unlikely(len < iter->iov_offset))
|
|
Packit Service |
4684c1 |
return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
|
|
Packit Service |
4684c1 |
len -= iter->iov_offset;
|
|
Packit Service |
4684c1 |
p += iter->iov_offset;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* We have at least one full block, return a whole set
|
|
Packit Service |
4684c1 |
* of full blocks immediately. */
|
|
Packit Service |
4684c1 |
if (iter->block_offset == 0 && len >= iter->block_size) {
|
|
Packit Service |
4684c1 |
if ((len % iter->block_size) == 0) {
|
|
Packit Service |
4684c1 |
iter->iov_index++;
|
|
Packit Service |
4684c1 |
iter->iov_offset = 0;
|
|
Packit Service |
4684c1 |
} else {
|
|
Packit Service |
4684c1 |
len -= (len % iter->block_size);
|
|
Packit Service |
4684c1 |
iter->iov_offset += len;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* Return the blocks. */
|
|
Packit Service |
4684c1 |
*data = p;
|
|
Packit Service |
4684c1 |
return len;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* We can complete one full block to return. */
|
|
Packit Service |
4684c1 |
block_left = iter->block_size - iter->block_offset;
|
|
Packit Service |
4684c1 |
if (len >= block_left) {
|
|
Packit Service |
4684c1 |
memcpy(iter->block + iter->block_offset, p, block_left);
|
|
Packit Service |
4684c1 |
if (len == block_left) {
|
|
Packit Service |
4684c1 |
iter->iov_index++;
|
|
Packit Service |
4684c1 |
iter->iov_offset = 0;
|
|
Packit Service |
4684c1 |
} else
|
|
Packit Service |
4684c1 |
iter->iov_offset += block_left;
|
|
Packit Service |
4684c1 |
iter->block_offset = 0;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* Return the filled block. */
|
|
Packit Service |
4684c1 |
*data = iter->block;
|
|
Packit Service |
4684c1 |
return iter->block_size;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* Not enough data for a full block, store in temp
|
|
Packit Service |
4684c1 |
* memory and continue. */
|
|
Packit Service |
4684c1 |
memcpy(iter->block + iter->block_offset, p, len);
|
|
Packit Service |
4684c1 |
iter->block_offset += len;
|
|
Packit Service |
4684c1 |
iter->iov_index++;
|
|
Packit Service |
4684c1 |
iter->iov_offset = 0;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (iter->block_offset > 0) {
|
|
Packit Service |
4684c1 |
size_t len = iter->block_offset;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* Return the incomplete block. */
|
|
Packit Service |
4684c1 |
*data = iter->block;
|
|
Packit Service |
4684c1 |
iter->block_offset = 0;
|
|
Packit Service |
4684c1 |
return len;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
return 0;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/**
|
|
Packit Service |
4684c1 |
* _gnutls_iov_iter_sync:
|
|
Packit Service |
4684c1 |
* @iter: the iterator
|
|
Packit Service |
4684c1 |
* @data: data returned by _gnutls_iov_iter_next
|
|
Packit Service |
4684c1 |
* @data_size: size of @data
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* Flush the content of temp buffer (if any) to the data buffer.
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
int
|
|
Packit Service |
4684c1 |
_gnutls_iov_iter_sync(struct iov_iter_st *iter, const uint8_t *data,
|
|
Packit Service |
4684c1 |
size_t data_size)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
size_t iov_index;
|
|
Packit Service |
4684c1 |
size_t iov_offset;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* We didn't return the cached block. */
|
|
Packit Service |
4684c1 |
if (data != iter->block)
|
|
Packit Service |
4684c1 |
return 0;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
iov_index = iter->iov_index;
|
|
Packit Service |
4684c1 |
iov_offset = iter->iov_offset;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* When syncing a cache block we walk backwards because we only have a
|
|
Packit Service |
4684c1 |
* pointer to were the block ends in the iovec, walking backwards is
|
|
Packit Service |
4684c1 |
* fine as we are always writing a full block, so the whole content
|
|
Packit Service |
4684c1 |
* is written in the right places:
|
|
Packit Service |
4684c1 |
* iovec: |--0--|---1---|--2--|-3-|
|
|
Packit Service |
4684c1 |
* block: |-----------------------|
|
|
Packit Service |
4684c1 |
* 1st write |---|
|
|
Packit Service |
4684c1 |
* 2nd write |-----
|
|
Packit Service |
4684c1 |
* 3rd write |-------
|
|
Packit Service |
4684c1 |
* last write |-----
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
while (data_size > 0) {
|
|
Packit Service |
4684c1 |
const giovec_t *iov;
|
|
Packit Service |
4684c1 |
uint8_t *p;
|
|
Packit Service |
4684c1 |
size_t to_write;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
while (iov_offset == 0) {
|
|
Packit Service |
4684c1 |
if (unlikely(iov_index == 0))
|
|
Packit Service |
4684c1 |
return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
iov_index--;
|
|
Packit Service |
4684c1 |
iov_offset = iter->iov[iov_index].iov_len;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
iov = &iter->iov[iov_index];
|
|
Packit Service |
4684c1 |
p = iov->iov_base;
|
|
Packit Service |
4684c1 |
to_write = MIN(data_size, iov_offset);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
iov_offset -= to_write;
|
|
Packit Service |
4684c1 |
data_size -= to_write;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
memcpy(p + iov_offset, &iter->block[data_size], to_write);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
return 0;
|
|
Packit Service |
4684c1 |
}
|