Commit 78496db0 authored by Alex Elder's avatar Alex Elder Committed by Greg Kroah-Hartman

greybus: clean up gb_connection_operation_recv()

This patch does some cleanup of gb_connection_operation_recv().
    - Improve the header comments
    - Verify message is big enough for header before interpreting
      beginning of the message as a header
    - Verify at buffer creation time rather than receive time that
      no operation buffer is bigger than the maximum allowed.  We
      can then compare the incoming data size against the buffer.
    - When a response message arrives, record its status in the
      operation result, not in the buffer status.
    - Record a buffer overflow as an operation error.
Signed-off-by: default avatarAlex Elder <elder@linaro.org>
Signed-off-by: default avatarGreg Kroah-Hartman <greg@kroah.com>
parent b37716f6
...@@ -204,6 +204,9 @@ static struct gbuf *gb_operation_gbuf_create(struct gb_operation *operation, ...@@ -204,6 +204,9 @@ static struct gbuf *gb_operation_gbuf_create(struct gb_operation *operation,
struct gbuf *gbuf; struct gbuf *gbuf;
gfp_t gfp_flags = data_out ? GFP_KERNEL : GFP_ATOMIC; gfp_t gfp_flags = data_out ? GFP_KERNEL : GFP_ATOMIC;
if (size > GB_OPERATION_MESSAGE_SIZE_MAX)
return NULL; /* Message too big */
size += sizeof(*header); size += sizeof(*header);
gbuf = greybus_alloc_gbuf(operation, size, data_out, gfp_flags); gbuf = greybus_alloc_gbuf(operation, size, data_out, gfp_flags);
if (!gbuf) if (!gbuf)
...@@ -355,9 +358,18 @@ int gb_operation_response_send(struct gb_operation *operation) ...@@ -355,9 +358,18 @@ int gb_operation_response_send(struct gb_operation *operation)
} }
/* /*
* Handle data arriving on a connection. This is called in * Handle data arriving on a connection. As soon as we return, the
* interrupt context, so just copy the incoming data into a buffer * incoming data buffer will be reused, so we need to copy the data
* and do remaining handling via a work queue. * into one of our own operation message buffers.
*
* If the incoming data is an operation response message, look up
* the operation and copy the incoming data into its response
* buffer. Otherwise allocate a new operation and copy the incoming
* data into its request buffer.
*
* This is called in interrupt context, so just copy the incoming
* data into the buffer and do remaining handling via a work queue.
*
*/ */
void gb_connection_operation_recv(struct gb_connection *connection, void gb_connection_operation_recv(struct gb_connection *connection,
void *data, size_t size) void *data, size_t size)
...@@ -370,8 +382,8 @@ void gb_connection_operation_recv(struct gb_connection *connection, ...@@ -370,8 +382,8 @@ void gb_connection_operation_recv(struct gb_connection *connection,
if (connection->state != GB_CONNECTION_STATE_ENABLED) if (connection->state != GB_CONNECTION_STATE_ENABLED)
return; return;
if (size > GB_OPERATION_MESSAGE_SIZE_MAX) { if (size < sizeof(*header)) {
gb_connection_err(connection, "message too big"); gb_connection_err(connection, "message too small");
return; return;
} }
...@@ -388,11 +400,12 @@ void gb_connection_operation_recv(struct gb_connection *connection, ...@@ -388,11 +400,12 @@ void gb_connection_operation_recv(struct gb_connection *connection,
cancel_delayed_work(&operation->timeout_work); cancel_delayed_work(&operation->timeout_work);
gb_pending_operation_remove(operation); gb_pending_operation_remove(operation);
gbuf = operation->response; gbuf = operation->response;
gbuf->status = GB_OP_SUCCESS; /* If we got here we're good */
if (size > gbuf->transfer_buffer_length) { if (size > gbuf->transfer_buffer_length) {
operation->result = GB_OP_OVERFLOW;
gb_connection_err(connection, "recv buffer too small"); gb_connection_err(connection, "recv buffer too small");
return; return;
} }
operation->result = GB_OP_SUCCESS;
} else { } else {
WARN_ON(msg_size != size); WARN_ON(msg_size != size);
operation = gb_operation_create(connection, header->type, operation = gb_operation_create(connection, header->type,
......
...@@ -18,6 +18,7 @@ enum gb_operation_status { ...@@ -18,6 +18,7 @@ enum gb_operation_status {
GB_OP_INTERRUPTED = 3, GB_OP_INTERRUPTED = 3,
GB_OP_RETRY = 4, GB_OP_RETRY = 4,
GB_OP_PROTOCOL_BAD = 5, GB_OP_PROTOCOL_BAD = 5,
GB_OP_OVERFLOW = 6,
GB_OP_TIMEOUT = 0xff, GB_OP_TIMEOUT = 0xff,
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment