18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2007 Luca Bigliardi (shammash@artha.org).
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#include <stddef.h>
78c2ecf20Sopenharmony_ci#include <errno.h>
88c2ecf20Sopenharmony_ci#include <libvdeplug.h>
98c2ecf20Sopenharmony_ci#include <net_user.h>
108c2ecf20Sopenharmony_ci#include <um_malloc.h>
118c2ecf20Sopenharmony_ci#include "vde.h"
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_cistatic int vde_user_init(void *data, void *dev)
148c2ecf20Sopenharmony_ci{
158c2ecf20Sopenharmony_ci	struct vde_data *pri = data;
168c2ecf20Sopenharmony_ci	VDECONN *conn = NULL;
178c2ecf20Sopenharmony_ci	int err = -EINVAL;
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci	pri->dev = dev;
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci	conn = vde_open(pri->vde_switch, pri->descr, pri->args);
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci	if (conn == NULL) {
248c2ecf20Sopenharmony_ci		err = -errno;
258c2ecf20Sopenharmony_ci		printk(UM_KERN_ERR "vde_user_init: vde_open failed, "
268c2ecf20Sopenharmony_ci		       "errno = %d\n", errno);
278c2ecf20Sopenharmony_ci		return err;
288c2ecf20Sopenharmony_ci	}
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci	printk(UM_KERN_INFO "vde backend - connection opened\n");
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci	pri->conn = conn;
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci	return 0;
358c2ecf20Sopenharmony_ci}
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_cistatic int vde_user_open(void *data)
388c2ecf20Sopenharmony_ci{
398c2ecf20Sopenharmony_ci	struct vde_data *pri = data;
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci	if (pri->conn != NULL)
428c2ecf20Sopenharmony_ci		return vde_datafd(pri->conn);
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci	printk(UM_KERN_WARNING "vde_open - we have no VDECONN to open");
458c2ecf20Sopenharmony_ci	return -EINVAL;
468c2ecf20Sopenharmony_ci}
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_cistatic void vde_remove(void *data)
498c2ecf20Sopenharmony_ci{
508c2ecf20Sopenharmony_ci	struct vde_data *pri = data;
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci	if (pri->conn != NULL) {
538c2ecf20Sopenharmony_ci		printk(UM_KERN_INFO "vde backend - closing connection\n");
548c2ecf20Sopenharmony_ci		vde_close(pri->conn);
558c2ecf20Sopenharmony_ci		pri->conn = NULL;
568c2ecf20Sopenharmony_ci		kfree(pri->args);
578c2ecf20Sopenharmony_ci		pri->args = NULL;
588c2ecf20Sopenharmony_ci		return;
598c2ecf20Sopenharmony_ci	}
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci	printk(UM_KERN_WARNING "vde_remove - we have no VDECONN to remove");
628c2ecf20Sopenharmony_ci}
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ciconst struct net_user_info vde_user_info = {
658c2ecf20Sopenharmony_ci	.init		= vde_user_init,
668c2ecf20Sopenharmony_ci	.open		= vde_user_open,
678c2ecf20Sopenharmony_ci	.close	 	= NULL,
688c2ecf20Sopenharmony_ci	.remove	 	= vde_remove,
698c2ecf20Sopenharmony_ci	.add_address	= NULL,
708c2ecf20Sopenharmony_ci	.delete_address = NULL,
718c2ecf20Sopenharmony_ci	.mtu		= ETH_MAX_PACKET,
728c2ecf20Sopenharmony_ci	.max_packet	= ETH_MAX_PACKET + ETH_HEADER_OTHER,
738c2ecf20Sopenharmony_ci};
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_civoid vde_init_libstuff(struct vde_data *vpri, struct vde_init *init)
768c2ecf20Sopenharmony_ci{
778c2ecf20Sopenharmony_ci	struct vde_open_args *args;
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	vpri->args = uml_kmalloc(sizeof(struct vde_open_args), UM_GFP_KERNEL);
808c2ecf20Sopenharmony_ci	if (vpri->args == NULL) {
818c2ecf20Sopenharmony_ci		printk(UM_KERN_ERR "vde_init_libstuff - vde_open_args "
828c2ecf20Sopenharmony_ci		       "allocation failed");
838c2ecf20Sopenharmony_ci		return;
848c2ecf20Sopenharmony_ci	}
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	args = vpri->args;
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	args->port = init->port;
898c2ecf20Sopenharmony_ci	args->group = init->group;
908c2ecf20Sopenharmony_ci	args->mode = init->mode ? init->mode : 0700;
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci	args->port ?  printk("port %d", args->port) :
938c2ecf20Sopenharmony_ci		printk("undefined port");
948c2ecf20Sopenharmony_ci}
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ciint vde_user_read(void *conn, void *buf, int len)
978c2ecf20Sopenharmony_ci{
988c2ecf20Sopenharmony_ci	VDECONN *vconn = conn;
998c2ecf20Sopenharmony_ci	int rv;
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	if (vconn == NULL)
1028c2ecf20Sopenharmony_ci		return 0;
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci	rv = vde_recv(vconn, buf, len, 0);
1058c2ecf20Sopenharmony_ci	if (rv < 0) {
1068c2ecf20Sopenharmony_ci		if (errno == EAGAIN)
1078c2ecf20Sopenharmony_ci			return 0;
1088c2ecf20Sopenharmony_ci		return -errno;
1098c2ecf20Sopenharmony_ci	}
1108c2ecf20Sopenharmony_ci	else if (rv == 0)
1118c2ecf20Sopenharmony_ci		return -ENOTCONN;
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	return rv;
1148c2ecf20Sopenharmony_ci}
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ciint vde_user_write(void *conn, void *buf, int len)
1178c2ecf20Sopenharmony_ci{
1188c2ecf20Sopenharmony_ci	VDECONN *vconn = conn;
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	if (vconn == NULL)
1218c2ecf20Sopenharmony_ci		return 0;
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	return vde_send(vconn, buf, len, 0);
1248c2ecf20Sopenharmony_ci}
1258c2ecf20Sopenharmony_ci
126