return -ENOBUFS;
}
+/**
+ * Concatenate I/O buffers into a single buffer
+ *
+ * @v list List of I/O buffers
+ * @ret iobuf Concatenated I/O buffer, or NULL on allocation failure
+ *
+ * After a successful concatenation, the list will be empty.
+ */
+struct io_buffer * iob_concatenate ( struct list_head *list ) {
+ struct io_buffer *iobuf;
+ struct io_buffer *tmp;
+ struct io_buffer *concatenated;
+ size_t len = 0;
+
+ /* If the list contains only a single entry, avoid an
+ * unnecessary additional allocation.
+ */
+ if ( list_is_singular ( list ) ) {
+ iobuf = list_first_entry ( list, struct io_buffer, list );
+ INIT_LIST_HEAD ( list );
+ return iobuf;
+ }
+
+ /* Calculate total length */
+ list_for_each_entry ( iobuf, list, list )
+ len += iob_len ( iobuf );
+
+ /* Allocate new I/O buffer */
+ concatenated = alloc_iob_raw ( len, __alignof__ ( *iobuf ), 0 );
+ if ( ! concatenated )
+ return NULL;
+
+ /* Move data to new I/O buffer */
+ list_for_each_entry_safe ( iobuf, tmp, list, list ) {
+ list_del ( &iobuf->list );
+ memcpy ( iob_put ( concatenated, iob_len ( iobuf ) ),
+ iobuf->data, iob_len ( iobuf ) );
+ free_iob ( iobuf );
+ }
+
+ return concatenated;
+}
#define EINFO_EINVAL_MAC \
__einfo_uniqify ( EINFO_EINVAL, 0x0d, \
"Invalid MAC" )
-#define EINVAL_NON_DATA __einfo_error ( EINFO_EINVAL_NON_DATA )
-#define EINFO_EINVAL_NON_DATA \
- __einfo_uniqify ( EINFO_EINVAL, 0x0e, \
- "Overlength non-data record" )
#define EIO_ALERT __einfo_error ( EINFO_EIO_ALERT )
#define EINFO_EIO_ALERT \
__einfo_uniqify ( EINFO_EINVAL, 0x01, \
#define EINFO_ENOMEM_RX_DATA \
__einfo_uniqify ( EINFO_ENOMEM, 0x07, \
"Not enough space for received data" )
+#define ENOMEM_RX_CONCAT __einfo_error ( EINFO_ENOMEM_RX_CONCAT )
+#define EINFO_ENOMEM_RX_CONCAT \
+ __einfo_uniqify ( EINFO_ENOMEM, 0x08, \
+ "Not enough space to concatenate received data" )
#define ENOTSUP_CIPHER __einfo_error ( EINFO_ENOTSUP_CIPHER )
#define EINFO_ENOTSUP_CIPHER \
__einfo_uniqify ( EINFO_ENOTSUP, 0x01, \
return 0;
}
- /* For all other records, fail unless we have exactly one I/O buffer */
- iobuf = list_first_entry ( rx_data, struct io_buffer, list );
- assert ( iobuf != NULL );
- list_del ( &iobuf->list );
- if ( ! list_empty ( rx_data ) ) {
- DBGC ( tls, "TLS %p overlength non-data record\n", tls );
- free_iob ( iobuf );
- return -EINVAL_NON_DATA;
+ /* For all other records, merge into a single I/O buffer */
+ iobuf = iob_concatenate ( rx_data );
+ if ( ! iobuf ) {
+ DBGC ( tls, "TLS %p could not concatenate non-data record "
+ "type %d\n", tls, type );
+ return -ENOMEM_RX_CONCAT;
}
/* Determine handler */