@@ -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;
}