162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <unistd.h>
762306a36Sopenharmony_ci#include <errno.h>
862306a36Sopenharmony_ci#include <string.h>
962306a36Sopenharmony_ci#include <sys/wait.h>
1062306a36Sopenharmony_ci#include <net_user.h>
1162306a36Sopenharmony_ci#include <os.h>
1262306a36Sopenharmony_ci#include "slirp.h"
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_cistatic int slirp_user_init(void *data, void *dev)
1562306a36Sopenharmony_ci{
1662306a36Sopenharmony_ci	struct slirp_data *pri = data;
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci	pri->dev = dev;
1962306a36Sopenharmony_ci	return 0;
2062306a36Sopenharmony_ci}
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_cistruct slirp_pre_exec_data {
2362306a36Sopenharmony_ci	int stdin_fd;
2462306a36Sopenharmony_ci	int stdout_fd;
2562306a36Sopenharmony_ci};
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_cistatic void slirp_pre_exec(void *arg)
2862306a36Sopenharmony_ci{
2962306a36Sopenharmony_ci	struct slirp_pre_exec_data *data = arg;
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci	if (data->stdin_fd != -1)
3262306a36Sopenharmony_ci		dup2(data->stdin_fd, 0);
3362306a36Sopenharmony_ci	if (data->stdout_fd != -1)
3462306a36Sopenharmony_ci		dup2(data->stdout_fd, 1);
3562306a36Sopenharmony_ci}
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_cistatic int slirp_tramp(char **argv, int fd)
3862306a36Sopenharmony_ci{
3962306a36Sopenharmony_ci	struct slirp_pre_exec_data pe_data;
4062306a36Sopenharmony_ci	int pid;
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci	pe_data.stdin_fd = fd;
4362306a36Sopenharmony_ci	pe_data.stdout_fd = fd;
4462306a36Sopenharmony_ci	pid = run_helper(slirp_pre_exec, &pe_data, argv);
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci	return pid;
4762306a36Sopenharmony_ci}
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_cistatic int slirp_open(void *data)
5062306a36Sopenharmony_ci{
5162306a36Sopenharmony_ci	struct slirp_data *pri = data;
5262306a36Sopenharmony_ci	int fds[2], pid, err;
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	err = os_pipe(fds, 1, 1);
5562306a36Sopenharmony_ci	if (err)
5662306a36Sopenharmony_ci		return err;
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	err = slirp_tramp(pri->argw.argv, fds[1]);
5962306a36Sopenharmony_ci	if (err < 0) {
6062306a36Sopenharmony_ci		printk(UM_KERN_ERR "slirp_tramp failed - errno = %d\n", -err);
6162306a36Sopenharmony_ci		goto out;
6262306a36Sopenharmony_ci	}
6362306a36Sopenharmony_ci	pid = err;
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci	pri->slave = fds[1];
6662306a36Sopenharmony_ci	pri->slip.pos = 0;
6762306a36Sopenharmony_ci	pri->slip.esc = 0;
6862306a36Sopenharmony_ci	pri->pid = err;
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	return fds[0];
7162306a36Sopenharmony_ciout:
7262306a36Sopenharmony_ci	close(fds[0]);
7362306a36Sopenharmony_ci	close(fds[1]);
7462306a36Sopenharmony_ci	return err;
7562306a36Sopenharmony_ci}
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_cistatic void slirp_close(int fd, void *data)
7862306a36Sopenharmony_ci{
7962306a36Sopenharmony_ci	struct slirp_data *pri = data;
8062306a36Sopenharmony_ci	int err;
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	close(fd);
8362306a36Sopenharmony_ci	close(pri->slave);
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	pri->slave = -1;
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	if (pri->pid<1) {
8862306a36Sopenharmony_ci		printk(UM_KERN_ERR "slirp_close: no child process to shut "
8962306a36Sopenharmony_ci		       "down\n");
9062306a36Sopenharmony_ci		return;
9162306a36Sopenharmony_ci	}
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci#if 0
9462306a36Sopenharmony_ci	if (kill(pri->pid, SIGHUP)<0) {
9562306a36Sopenharmony_ci		printk(UM_KERN_ERR "slirp_close: sending hangup to %d failed "
9662306a36Sopenharmony_ci		       "(%d)\n", pri->pid, errno);
9762306a36Sopenharmony_ci	}
9862306a36Sopenharmony_ci#endif
9962306a36Sopenharmony_ci	err = helper_wait(pri->pid);
10062306a36Sopenharmony_ci	if (err < 0)
10162306a36Sopenharmony_ci		return;
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	pri->pid = -1;
10462306a36Sopenharmony_ci}
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ciint slirp_user_read(int fd, void *buf, int len, struct slirp_data *pri)
10762306a36Sopenharmony_ci{
10862306a36Sopenharmony_ci	return slip_proto_read(fd, buf, len, &pri->slip);
10962306a36Sopenharmony_ci}
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ciint slirp_user_write(int fd, void *buf, int len, struct slirp_data *pri)
11262306a36Sopenharmony_ci{
11362306a36Sopenharmony_ci	return slip_proto_write(fd, buf, len, &pri->slip);
11462306a36Sopenharmony_ci}
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ciconst struct net_user_info slirp_user_info = {
11762306a36Sopenharmony_ci	.init		= slirp_user_init,
11862306a36Sopenharmony_ci	.open		= slirp_open,
11962306a36Sopenharmony_ci	.close	 	= slirp_close,
12062306a36Sopenharmony_ci	.remove	 	= NULL,
12162306a36Sopenharmony_ci	.add_address	= NULL,
12262306a36Sopenharmony_ci	.delete_address = NULL,
12362306a36Sopenharmony_ci	.mtu		= BUF_SIZE,
12462306a36Sopenharmony_ci	.max_packet	= BUF_SIZE,
12562306a36Sopenharmony_ci};
126