xref: /openbmc/linux/arch/um/drivers/daemon_user.c (revision cbecf716ca618fd44feda6bd9a64a8179d031fc5)
1dbddf429SAlex Dewar // SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds /*
3cd1ae0e4SJeff Dike  * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
41da177e4SLinus Torvalds  * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and
51da177e4SLinus Torvalds  * James Leu (jleu@mindspring.net).
61da177e4SLinus Torvalds  * Copyright (C) 2001 by various other people who didn't put their name here.
71da177e4SLinus Torvalds  */
81da177e4SLinus Torvalds 
91da177e4SLinus Torvalds #include <stdint.h>
10*5e1121cdSIgnat Korchagin #include <string.h>
11cd1ae0e4SJeff Dike #include <unistd.h>
12cd1ae0e4SJeff Dike #include <errno.h>
13cd1ae0e4SJeff Dike #include <sys/types.h>
141da177e4SLinus Torvalds #include <sys/socket.h>
151da177e4SLinus Torvalds #include <sys/time.h>
16cd1ae0e4SJeff Dike #include <sys/un.h>
171da177e4SLinus Torvalds #include "daemon.h"
1837185b33SAl Viro #include <net_user.h>
1937185b33SAl Viro #include <os.h>
2037185b33SAl Viro #include <um_malloc.h>
211da177e4SLinus Torvalds 
221da177e4SLinus Torvalds enum request_type { REQ_NEW_CONTROL };
231da177e4SLinus Torvalds 
241da177e4SLinus Torvalds #define SWITCH_MAGIC 0xfeedface
251da177e4SLinus Torvalds 
261da177e4SLinus Torvalds struct request_v3 {
271da177e4SLinus Torvalds 	uint32_t magic;
281da177e4SLinus Torvalds 	uint32_t version;
291da177e4SLinus Torvalds 	enum request_type type;
301da177e4SLinus Torvalds 	struct sockaddr_un sock;
311da177e4SLinus Torvalds };
321da177e4SLinus Torvalds 
new_addr(void * name,int len)331da177e4SLinus Torvalds static struct sockaddr_un *new_addr(void *name, int len)
341da177e4SLinus Torvalds {
351da177e4SLinus Torvalds 	struct sockaddr_un *sun;
361da177e4SLinus Torvalds 
3743f5b308SJeff Dike 	sun = uml_kmalloc(sizeof(struct sockaddr_un), UM_GFP_KERNEL);
381da177e4SLinus Torvalds 	if (sun == NULL) {
39cd1ae0e4SJeff Dike 		printk(UM_KERN_ERR "new_addr: allocation of sockaddr_un "
40cd1ae0e4SJeff Dike 		       "failed\n");
4156bd194bSJeff Dike 		return NULL;
421da177e4SLinus Torvalds 	}
431da177e4SLinus Torvalds 	sun->sun_family = AF_UNIX;
441da177e4SLinus Torvalds 	memcpy(sun->sun_path, name, len);
4556bd194bSJeff Dike 	return sun;
461da177e4SLinus Torvalds }
471da177e4SLinus Torvalds 
connect_to_switch(struct daemon_data * pri)481da177e4SLinus Torvalds static int connect_to_switch(struct daemon_data *pri)
491da177e4SLinus Torvalds {
501da177e4SLinus Torvalds 	struct sockaddr_un *ctl_addr = pri->ctl_addr;
511da177e4SLinus Torvalds 	struct sockaddr_un *local_addr = pri->local_addr;
521da177e4SLinus Torvalds 	struct sockaddr_un *sun;
531da177e4SLinus Torvalds 	struct request_v3 req;
541da177e4SLinus Torvalds 	int fd, n, err;
551da177e4SLinus Torvalds 
561da177e4SLinus Torvalds 	pri->control = socket(AF_UNIX, SOCK_STREAM, 0);
571da177e4SLinus Torvalds 	if (pri->control < 0) {
58de7b37cdSPaolo 'Blaisorblade' Giarrusso 		err = -errno;
59cd1ae0e4SJeff Dike 		printk(UM_KERN_ERR "daemon_open : control socket failed, "
60cd1ae0e4SJeff Dike 		       "errno = %d\n", -err);
61de7b37cdSPaolo 'Blaisorblade' Giarrusso 		return err;
621da177e4SLinus Torvalds 	}
631da177e4SLinus Torvalds 
641da177e4SLinus Torvalds 	if (connect(pri->control, (struct sockaddr *) ctl_addr,
651da177e4SLinus Torvalds 		   sizeof(*ctl_addr)) < 0) {
661da177e4SLinus Torvalds 		err = -errno;
67cd1ae0e4SJeff Dike 		printk(UM_KERN_ERR "daemon_open : control connect failed, "
68cd1ae0e4SJeff Dike 		       "errno = %d\n", -err);
691da177e4SLinus Torvalds 		goto out;
701da177e4SLinus Torvalds 	}
711da177e4SLinus Torvalds 
721da177e4SLinus Torvalds 	fd = socket(AF_UNIX, SOCK_DGRAM, 0);
731da177e4SLinus Torvalds 	if (fd < 0) {
741da177e4SLinus Torvalds 		err = -errno;
75cd1ae0e4SJeff Dike 		printk(UM_KERN_ERR "daemon_open : data socket failed, "
76cd1ae0e4SJeff Dike 		       "errno = %d\n", -err);
771da177e4SLinus Torvalds 		goto out;
781da177e4SLinus Torvalds 	}
791da177e4SLinus Torvalds 	if (bind(fd, (struct sockaddr *) local_addr, sizeof(*local_addr)) < 0) {
801da177e4SLinus Torvalds 		err = -errno;
81cd1ae0e4SJeff Dike 		printk(UM_KERN_ERR "daemon_open : data bind failed, "
82cd1ae0e4SJeff Dike 		       "errno = %d\n", -err);
831da177e4SLinus Torvalds 		goto out_close;
841da177e4SLinus Torvalds 	}
851da177e4SLinus Torvalds 
8643f5b308SJeff Dike 	sun = uml_kmalloc(sizeof(struct sockaddr_un), UM_GFP_KERNEL);
871da177e4SLinus Torvalds 	if (sun == NULL) {
88cd1ae0e4SJeff Dike 		printk(UM_KERN_ERR "new_addr: allocation of sockaddr_un "
89cd1ae0e4SJeff Dike 		       "failed\n");
901da177e4SLinus Torvalds 		err = -ENOMEM;
911da177e4SLinus Torvalds 		goto out_close;
921da177e4SLinus Torvalds 	}
931da177e4SLinus Torvalds 
941da177e4SLinus Torvalds 	req.magic = SWITCH_MAGIC;
951da177e4SLinus Torvalds 	req.version = SWITCH_VERSION;
961da177e4SLinus Torvalds 	req.type = REQ_NEW_CONTROL;
971da177e4SLinus Torvalds 	req.sock = *local_addr;
98cd1ae0e4SJeff Dike 	n = write(pri->control, &req, sizeof(req));
991da177e4SLinus Torvalds 	if (n != sizeof(req)) {
100cd1ae0e4SJeff Dike 		printk(UM_KERN_ERR "daemon_open : control setup request "
101cd1ae0e4SJeff Dike 		       "failed, err = %d\n", -errno);
1021da177e4SLinus Torvalds 		err = -ENOTCONN;
103ba260e23SPaolo 'Blaisorblade' Giarrusso 		goto out_free;
1041da177e4SLinus Torvalds 	}
1051da177e4SLinus Torvalds 
106cd1ae0e4SJeff Dike 	n = read(pri->control, sun, sizeof(*sun));
1071da177e4SLinus Torvalds 	if (n != sizeof(*sun)) {
108cd1ae0e4SJeff Dike 		printk(UM_KERN_ERR "daemon_open : read of data socket failed, "
109cd1ae0e4SJeff Dike 		       "err = %d\n", -errno);
1101da177e4SLinus Torvalds 		err = -ENOTCONN;
111ba260e23SPaolo 'Blaisorblade' Giarrusso 		goto out_free;
1121da177e4SLinus Torvalds 	}
1131da177e4SLinus Torvalds 
1141da177e4SLinus Torvalds 	pri->data_addr = sun;
11556bd194bSJeff Dike 	return fd;
1161da177e4SLinus Torvalds 
117ba260e23SPaolo 'Blaisorblade' Giarrusso  out_free:
118ba260e23SPaolo 'Blaisorblade' Giarrusso 	kfree(sun);
1191da177e4SLinus Torvalds  out_close:
120cd1ae0e4SJeff Dike 	close(fd);
1211da177e4SLinus Torvalds  out:
122cd1ae0e4SJeff Dike 	close(pri->control);
12356bd194bSJeff Dike 	return err;
1241da177e4SLinus Torvalds }
1251da177e4SLinus Torvalds 
daemon_user_init(void * data,void * dev)126f34d9d2dSJeff Dike static int daemon_user_init(void *data, void *dev)
1271da177e4SLinus Torvalds {
1281da177e4SLinus Torvalds 	struct daemon_data *pri = data;
1291da177e4SLinus Torvalds 	struct timeval tv;
1301da177e4SLinus Torvalds 	struct {
1311da177e4SLinus Torvalds 		char zero;
1321da177e4SLinus Torvalds 		int pid;
1331da177e4SLinus Torvalds 		int usecs;
1341da177e4SLinus Torvalds 	} name;
1351da177e4SLinus Torvalds 
1361da177e4SLinus Torvalds 	if (!strcmp(pri->sock_type, "unix"))
1371da177e4SLinus Torvalds 		pri->ctl_addr = new_addr(pri->ctl_sock,
1381da177e4SLinus Torvalds 					 strlen(pri->ctl_sock) + 1);
1391da177e4SLinus Torvalds 	name.zero = 0;
1401da177e4SLinus Torvalds 	name.pid = os_getpid();
1411da177e4SLinus Torvalds 	gettimeofday(&tv, NULL);
1421da177e4SLinus Torvalds 	name.usecs = tv.tv_usec;
1431da177e4SLinus Torvalds 	pri->local_addr = new_addr(&name, sizeof(name));
1441da177e4SLinus Torvalds 	pri->dev = dev;
1451da177e4SLinus Torvalds 	pri->fd = connect_to_switch(pri);
1461da177e4SLinus Torvalds 	if (pri->fd < 0) {
1471da177e4SLinus Torvalds 		kfree(pri->local_addr);
1481da177e4SLinus Torvalds 		pri->local_addr = NULL;
149f34d9d2dSJeff Dike 		return pri->fd;
1501da177e4SLinus Torvalds 	}
151f34d9d2dSJeff Dike 
152f34d9d2dSJeff Dike 	return 0;
1531da177e4SLinus Torvalds }
1541da177e4SLinus Torvalds 
daemon_open(void * data)1551da177e4SLinus Torvalds static int daemon_open(void *data)
1561da177e4SLinus Torvalds {
1571da177e4SLinus Torvalds 	struct daemon_data *pri = data;
15856bd194bSJeff Dike 	return pri->fd;
1591da177e4SLinus Torvalds }
1601da177e4SLinus Torvalds 
daemon_remove(void * data)1611da177e4SLinus Torvalds static void daemon_remove(void *data)
1621da177e4SLinus Torvalds {
1631da177e4SLinus Torvalds 	struct daemon_data *pri = data;
1641da177e4SLinus Torvalds 
165cd1ae0e4SJeff Dike 	close(pri->fd);
166c42791b6SPaolo 'Blaisorblade' Giarrusso 	pri->fd = -1;
167cd1ae0e4SJeff Dike 	close(pri->control);
168c42791b6SPaolo 'Blaisorblade' Giarrusso 	pri->control = -1;
169c42791b6SPaolo 'Blaisorblade' Giarrusso 
17041f2148aSJesper Juhl 	kfree(pri->data_addr);
171c42791b6SPaolo 'Blaisorblade' Giarrusso 	pri->data_addr = NULL;
17241f2148aSJesper Juhl 	kfree(pri->ctl_addr);
173c42791b6SPaolo 'Blaisorblade' Giarrusso 	pri->ctl_addr = NULL;
17441f2148aSJesper Juhl 	kfree(pri->local_addr);
175c42791b6SPaolo 'Blaisorblade' Giarrusso 	pri->local_addr = NULL;
1761da177e4SLinus Torvalds }
1771da177e4SLinus Torvalds 
daemon_user_write(int fd,void * buf,int len,struct daemon_data * pri)1781da177e4SLinus Torvalds int daemon_user_write(int fd, void *buf, int len, struct daemon_data *pri)
1791da177e4SLinus Torvalds {
1801da177e4SLinus Torvalds 	struct sockaddr_un *data_addr = pri->data_addr;
1811da177e4SLinus Torvalds 
18256bd194bSJeff Dike 	return net_sendto(fd, buf, len, data_addr, sizeof(*data_addr));
1831da177e4SLinus Torvalds }
1841da177e4SLinus Torvalds 
1855e7672ecSJeff Dike const struct net_user_info daemon_user_info = {
1861da177e4SLinus Torvalds 	.init		= daemon_user_init,
1871da177e4SLinus Torvalds 	.open		= daemon_open,
1881da177e4SLinus Torvalds 	.close	 	= NULL,
1891da177e4SLinus Torvalds 	.remove	 	= daemon_remove,
1901da177e4SLinus Torvalds 	.add_address	= NULL,
1911da177e4SLinus Torvalds 	.delete_address = NULL,
192b53f35a8SJeff Dike 	.mtu		= ETH_MAX_PACKET,
193b53f35a8SJeff Dike 	.max_packet	= ETH_MAX_PACKET + ETH_HEADER_OTHER,
1941da177e4SLinus Torvalds };
195