From: Roberto Sassu <roberto.sassu@huawei.com>
Move bpfilter_send_req() to usermode_driver.c and rename it to
umd_send_recv(). Make the latter independent from the message format by
passing to it the pointers to the request and reply message buffers and the
respective lengths, and by merely doing read/write operations.
From umd_send_recv(), remove the call to __stop_umh() and returning
reply.status, which is message format-specific. Let the callers of
umd_send_recv(), such as bpfilter_process_sockopt(), call shutdown_umh()
and evaluate the reply. Consequently, remove __stop_umh(), since in
bpfilter_process_sockopt() the CONFIG_INET condition is always true.
In addition to the original bpfilter_send_req() implementation, support
partial reads and writes, so that callers are not limited by the length of
the message to send or receive. Currently, the pipe supports receiving
64 KB at once.
Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
---
include/linux/usermode_driver.h | 2 ++
kernel/usermode_driver.c | 47 ++++++++++++++++++++++++++++++-
net/bpfilter/bpfilter_kern.c | 50 +++++++++------------------------
3 files changed, 62 insertions(+), 37 deletions(-)
@@ -15,5 +15,7 @@ int umd_load_blob(struct umd_info *info, const void *data, size_t len);
int umd_unload_blob(struct umd_info *info);
int fork_usermode_driver(struct umd_info *info);
void umd_cleanup_helper(struct umd_info *info);
+int umd_send_recv(struct umd_info *info, void *in, size_t in_len, void *out,
+ size_t out_len);
#endif /* __LINUX_USERMODE_DRIVER_H__ */
@@ -188,4 +188,49 @@ int fork_usermode_driver(struct umd_info *info)
}
EXPORT_SYMBOL_GPL(fork_usermode_driver);
-
+/**
+ * umd_send_recv - send/receive a message through the pipe
+ * @info: user mode driver info
+ * @in: request message
+ * @in_len: size of @in
+ * @out: reply message
+ * @out_len: size of @out
+ *
+ * Send a message to the user space process through the created pipe and read
+ * the reply. Partial reads and writes are supported.
+ *
+ * Return: Zero on success, -EFAULT otherwise.
+ */
+int umd_send_recv(struct umd_info *info, void *in, size_t in_len, void *out,
+ size_t out_len)
+{
+ loff_t pos, offset;
+ ssize_t n;
+
+ if (!info->tgid)
+ return -EFAULT;
+ pos = 0;
+ offset = 0;
+ while (in_len) {
+ n = kernel_write(info->pipe_to_umh, in + offset, in_len, &pos);
+ if (n <= 0) {
+ pr_err("write fail %zd\n", n);
+ return -EFAULT;
+ }
+ in_len -= n;
+ offset += n;
+ }
+ pos = 0;
+ offset = 0;
+ while (out_len) {
+ n = kernel_read(info->pipe_from_umh, out + offset, out_len, &pos);
+ if (n <= 0) {
+ pr_err("read fail %zd\n", n);
+ return -EFAULT;
+ }
+ out_len -= n;
+ offset += n;
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(umd_send_recv);
@@ -25,40 +25,6 @@ static void shutdown_umh(void)
}
}
-static void __stop_umh(void)
-{
- if (IS_ENABLED(CONFIG_INET))
- shutdown_umh();
-}
-
-static int bpfilter_send_req(struct mbox_request *req)
-{
- struct mbox_reply reply;
- loff_t pos = 0;
- ssize_t n;
-
- if (!bpfilter_ops.info.tgid)
- return -EFAULT;
- pos = 0;
- n = kernel_write(bpfilter_ops.info.pipe_to_umh, req, sizeof(*req),
- &pos);
- if (n != sizeof(*req)) {
- pr_err("write fail %zd\n", n);
- goto stop;
- }
- pos = 0;
- n = kernel_read(bpfilter_ops.info.pipe_from_umh, &reply, sizeof(reply),
- &pos);
- if (n != sizeof(reply)) {
- pr_err("read fail %zd\n", n);
- goto stop;
- }
- return reply.status;
-stop:
- __stop_umh();
- return -EFAULT;
-}
-
static int bpfilter_process_sockopt(struct sock *sk, int optname,
sockptr_t optval, unsigned int optlen,
bool is_set)
@@ -70,16 +36,27 @@ static int bpfilter_process_sockopt(struct sock *sk, int optname,
.addr = (uintptr_t)optval.user,
.len = optlen,
};
+ struct mbox_reply reply;
+ int err;
+
if (sockptr_is_kernel(optval)) {
pr_err("kernel access not supported\n");
return -EFAULT;
}
- return bpfilter_send_req(&req);
+ err = umd_send_recv(&bpfilter_ops.info, &req, sizeof(req), &reply,
+ sizeof(reply));
+ if (err) {
+ shutdown_umh();
+ return err;
+ }
+
+ return reply.status;
}
static int start_umh(void)
{
struct mbox_request req = { .pid = current->pid };
+ struct mbox_reply reply;
int err;
/* fork usermode process */
@@ -89,7 +66,8 @@ static int start_umh(void)
pr_info("Loaded bpfilter_umh pid %d\n", pid_nr(bpfilter_ops.info.tgid));
/* health check that usermode process started correctly */
- if (bpfilter_send_req(&req) != 0) {
+ if (umd_send_recv(&bpfilter_ops.info, &req, sizeof(req), &reply,
+ sizeof(reply)) != 0 || reply.status != 0) {
shutdown_umh();
return -EFAULT;
}