]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
greybus: clean up gb_connection_operation_recv()
authorAlex Elder <elder@linaro.org>
Mon, 17 Nov 2014 14:08:39 +0000 (08:08 -0600)
committerGreg Kroah-Hartman <greg@kroah.com>
Mon, 17 Nov 2014 18:41:19 +0000 (10:41 -0800)
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: Alex Elder <elder@linaro.org>
Signed-off-by: Greg Kroah-Hartman <greg@kroah.com>
drivers/staging/greybus/operation.c
drivers/staging/greybus/operation.h

index f1c7dcf7d15d4b71c773f3f64dc058c95d795da3..bc68a5f9be667d84c64004723ef560c61960faff 100644 (file)
@@ -204,6 +204,9 @@ static struct gbuf *gb_operation_gbuf_create(struct gb_operation *operation,
        struct gbuf *gbuf;
        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);
        gbuf = greybus_alloc_gbuf(operation, size, data_out, gfp_flags);
        if (!gbuf)
@@ -355,9 +358,18 @@ int gb_operation_response_send(struct gb_operation *operation)
 }
 
 /*
- * Handle data arriving on a connection.  This is called in
- * interrupt context, so just copy the incoming data into a buffer
- * and do remaining handling via a work queue.
+ * Handle data arriving on a connection.  As soon as we return, the
+ * incoming data buffer will be reused, so we need to copy the data
+ * 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 *data, size_t size)
@@ -370,8 +382,8 @@ void gb_connection_operation_recv(struct gb_connection *connection,
        if (connection->state != GB_CONNECTION_STATE_ENABLED)
                return;
 
-       if (size > GB_OPERATION_MESSAGE_SIZE_MAX) {
-               gb_connection_err(connection, "message too big");
+       if (size < sizeof(*header)) {
+               gb_connection_err(connection, "message too small");
                return;
        }
 
@@ -388,11 +400,12 @@ void gb_connection_operation_recv(struct gb_connection *connection,
                cancel_delayed_work(&operation->timeout_work);
                gb_pending_operation_remove(operation);
                gbuf = operation->response;
-               gbuf->status = GB_OP_SUCCESS;   /* If we got here we're good */
                if (size > gbuf->transfer_buffer_length) {
+                       operation->result = GB_OP_OVERFLOW;
                        gb_connection_err(connection, "recv buffer too small");
                        return;
                }
+               operation->result = GB_OP_SUCCESS;
        } else {
                WARN_ON(msg_size != size);
                operation = gb_operation_create(connection, header->type,
index 4913f720a7cd028f5e385b9eae258331554f5462..f30b162f78b7739abbb76486757b413829dbe7de 100644 (file)
@@ -18,6 +18,7 @@ enum gb_operation_status {
        GB_OP_INTERRUPTED       = 3,
        GB_OP_RETRY             = 4,
        GB_OP_PROTOCOL_BAD      = 5,
+       GB_OP_OVERFLOW          = 6,
        GB_OP_TIMEOUT           = 0xff,
 };