summaryrefslogtreecommitdiff
path: root/extra/i2c_pseudo/i2c-pseudo.c
diff options
context:
space:
mode:
Diffstat (limited to 'extra/i2c_pseudo/i2c-pseudo.c')
-rw-r--r--extra/i2c_pseudo/i2c-pseudo.c122
1 files changed, 108 insertions, 14 deletions
diff --git a/extra/i2c_pseudo/i2c-pseudo.c b/extra/i2c_pseudo/i2c-pseudo.c
index 2fbac6dc1f..69fc9dbc52 100644
--- a/extra/i2c_pseudo/i2c-pseudo.c
+++ b/extra/i2c_pseudo/i2c-pseudo.c
@@ -27,8 +27,7 @@
#include <linux/types.h>
#include <linux/uaccess.h>
#include <linux/wait.h>
-
-#include "anprintf.h"
+#include <stdarg.h>
/* Minimum i2cp_limit module parameter value. */
#define I2CP_ADAPTERS_MIN 0
@@ -102,8 +101,10 @@ static const char i2cp_ctrlr_data_sep_char = ':';
#define STRING_NEQ(in_str, in_size, other_str) \
(in_size != strlen(other_str) || memcmp(other_str, in_str, in_size))
-#define STR_HELPER(x) #x
-#define STR(x) STR_HELPER(x)
+#define STR_HELPER(num) #num
+#define STR(num) STR_HELPER(num)
+
+#define CONST_STRLEN(str) (sizeof(str) - 1)
/*
* The number of pseudo I2C adapters permitted. This default value can be
@@ -657,7 +658,7 @@ struct i2cp_cmd_mxfer_reply_data {
};
struct i2cp_cmd_set_name_suffix_data {
- char name_suffix[FIELD_SIZEOF(struct i2c_adapter, name)];
+ char name_suffix[sizeof_field(struct i2c_adapter, name)];
size_t name_suffix_len;
};
@@ -754,6 +755,97 @@ struct i2cp_rsp_master_xfer {
size_t buf_start_plus_one;
};
+/* vanprintf - See anprintf() documentation. */
+static ssize_t vanprintf(char **out, ssize_t max_size, gfp_t gfp,
+ const char *fmt, va_list ap)
+{
+ int ret;
+ ssize_t buf_size;
+ char *buf = NULL;
+ va_list args1;
+
+ va_copy(args1, ap);
+ ret = vsnprintf(NULL, 0, fmt, ap);
+ if (ret < 0)
+ goto fail_before_args1;
+ if (max_size >= 0 && ret > max_size) {
+ ret = -ERANGE;
+ goto fail_before_args1;
+ }
+
+ buf_size = ret + 1;
+ buf = kmalloc(buf_size, gfp);
+ if (buf == NULL) {
+ ret = -ENOMEM;
+ goto fail_before_args1;
+ }
+
+ ret = vsnprintf(buf, buf_size, fmt, args1);
+ va_end(args1);
+ if (ret < 0)
+ goto fail_after_args1;
+ if (ret + 1 != buf_size) {
+ ret = -ENOTRECOVERABLE;
+ goto fail_after_args1;
+ }
+
+ *out = buf;
+ return ret;
+
+ fail_before_args1:
+ va_end(args1);
+ fail_after_args1:
+ kfree(buf);
+ if (ret >= 0)
+ ret = -ENOTRECOVERABLE;
+ return ret;
+}
+
+/*
+ * anprintf - Format a string and place it into a newly allocated buffer.
+ * @out: Address of the pointer to place the buffer address into. Will only be
+ * written to with a successful positive return value.
+ * @max_size: If non-negative, the maximum buffer size that this function will
+ * attempt to allocate. If the formatted string including trailing null
+ * character would not fit, no buffer will be allocated, and an error will
+ * be returned. (Thus max_size of 0 will always result in an error.)
+ * @gfp: GFP flags for kmalloc().
+ * @fmt: The format string to use.
+ * @...: Arguments for the format string.
+ *
+ * Return value meanings:
+ *
+ * >=0: A buffer of this size was allocated and its address written to *out.
+ * The caller now owns the buffer and is responsible for freeing it with
+ * kfree(). The final character in the buffer, not counted in this
+ * return value, is the trailing null. This is the same return value
+ * meaning as snprintf(3).
+ *
+ * <0: An error occurred. Negate the return value for the error number.
+ * @out will not have been written to. Errors that might come from
+ * snprintf(3) may come from this function as well. Additionally, the
+ * following errors may occur from this function:
+ *
+ * ERANGE: A buffer larger than @max_size would be needed to fit the
+ * formatted string including its trailing null character.
+ *
+ * ENOMEM: Allocation of the output buffer failed.
+ *
+ * ENOTRECOVERABLE: An unexpected condition occurred. This may indicate
+ * a bug.
+ */
+static ssize_t anprintf(char **out, ssize_t max_size, gfp_t gfp,
+ const char *fmt, ...)
+{
+ ssize_t ret;
+ va_list args;
+
+ va_start(args, fmt);
+ ret = vanprintf(out, max_size, gfp, fmt, args);
+ va_end(args);
+ return ret;
+}
+
static ssize_t i2cp_rsp_buffer_formatter(void *data, char **out)
{
struct i2cp_rsp_buffer *rsp_buf;
@@ -1763,7 +1855,7 @@ static int i2cp_cmd_set_timeout_cmd_completer(void *data,
static const struct i2cp_cmd i2cp_cmds[] = {
[I2CP_CMD_MXFER_REPLY_IDX] = {
.cmd_string = I2CP_MXFER_REPLY_CMD,
- .cmd_size = strlen(I2CP_MXFER_REPLY_CMD),
+ .cmd_size = CONST_STRLEN(I2CP_MXFER_REPLY_CMD),
.data_creator = i2cp_cmd_mxfer_reply_data_creator,
.data_shutdown = i2cp_cmd_mxfer_reply_data_shutdown,
.data_destroyer = i2cp_cmd_mxfer_reply_data_destroyer,
@@ -1773,35 +1865,35 @@ static const struct i2cp_cmd i2cp_cmds[] = {
},
[I2CP_CMD_ADAP_START_IDX] = {
.cmd_string = I2CP_ADAP_START_CMD,
- .cmd_size = strlen(I2CP_ADAP_START_CMD),
+ .cmd_size = CONST_STRLEN(I2CP_ADAP_START_CMD),
.header_receiver = i2cp_cmd_adap_start_header_receiver,
.data_receiver = i2cp_cmd_adap_start_data_receiver,
.cmd_completer = i2cp_cmd_adap_start_cmd_completer,
},
[I2CP_CMD_ADAP_SHUTDOWN_IDX] = {
.cmd_string = I2CP_ADAP_SHUTDOWN_CMD,
- .cmd_size = strlen(I2CP_ADAP_SHUTDOWN_CMD),
+ .cmd_size = CONST_STRLEN(I2CP_ADAP_SHUTDOWN_CMD),
.header_receiver = i2cp_cmd_adap_shutdown_header_receiver,
.data_receiver = i2cp_cmd_adap_shutdown_data_receiver,
.cmd_completer = i2cp_cmd_adap_shutdown_cmd_completer,
},
[I2CP_CMD_GET_NUMBER_IDX] = {
.cmd_string = I2CP_GET_NUMBER_CMD,
- .cmd_size = strlen(I2CP_GET_NUMBER_CMD),
+ .cmd_size = CONST_STRLEN(I2CP_GET_NUMBER_CMD),
.header_receiver = i2cp_cmd_get_number_header_receiver,
.data_receiver = i2cp_cmd_get_number_data_receiver,
.cmd_completer = i2cp_cmd_get_number_cmd_completer,
},
[I2CP_CMD_GET_PSEUDO_ID_IDX] = {
.cmd_string = I2CP_GET_PSEUDO_ID_CMD,
- .cmd_size = strlen(I2CP_GET_PSEUDO_ID_CMD),
+ .cmd_size = CONST_STRLEN(I2CP_GET_PSEUDO_ID_CMD),
.header_receiver = i2cp_cmd_get_pseudo_id_header_receiver,
.data_receiver = i2cp_cmd_get_pseudo_id_data_receiver,
.cmd_completer = i2cp_cmd_get_pseudo_id_cmd_completer,
},
[I2CP_CMD_SET_NAME_SUFFIX_IDX] = {
.cmd_string = I2CP_SET_NAME_SUFFIX_CMD,
- .cmd_size = strlen(I2CP_SET_NAME_SUFFIX_CMD),
+ .cmd_size = CONST_STRLEN(I2CP_SET_NAME_SUFFIX_CMD),
.data_creator = i2cp_cmd_set_name_suffix_data_creator,
.data_destroyer = i2cp_cmd_set_name_suffix_data_destroyer,
.header_receiver = i2cp_cmd_set_name_suffix_header_receiver,
@@ -1810,7 +1902,7 @@ static const struct i2cp_cmd i2cp_cmds[] = {
},
[I2CP_CMD_SET_TIMEOUT_IDX] = {
.cmd_string = I2CP_SET_TIMEOUT_CMD,
- .cmd_size = strlen(I2CP_SET_TIMEOUT_CMD),
+ .cmd_size = CONST_STRLEN(I2CP_SET_TIMEOUT_CMD),
.data_creator = i2cp_cmd_set_timeout_data_creator,
.data_destroyer = i2cp_cmd_set_timeout_data_destroyer,
.header_receiver = i2cp_cmd_set_timeout_header_receiver,
@@ -2114,7 +2206,7 @@ static int i2cp_cdev_open(struct inode *inodep, struct file *filep)
this_pseudo = i2cp_device;
/* I2C pseudo adapter controllers are not seekable. */
- nonseekable_open(inodep, filep);
+ stream_open(inodep, filep);
/* Refuse fsnotify events. Modeled after /dev/ptmx implementation. */
filep->f_mode |= FMODE_NONOTIFY;
@@ -2810,8 +2902,10 @@ static ssize_t i2cp_cdev_write(struct file *filep, const char __user *buf,
ret = -ENOMEM;
goto free_kbuf;
}
- if (copy_from_user(kbuf, buf, count))
+ if (copy_from_user(kbuf, buf, count)) {
+ ret = -EFAULT;
goto free_kbuf;
+ }
start = kbuf;
remaining = count;