18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) 48c2ecf20Sopenharmony_ci * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and 58c2ecf20Sopenharmony_ci * James Leu (jleu@mindspring.net). 68c2ecf20Sopenharmony_ci * Copyright (C) 2001 by various other people who didn't put their name here. 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <stdint.h> 108c2ecf20Sopenharmony_ci#include <string.h> 118c2ecf20Sopenharmony_ci#include <unistd.h> 128c2ecf20Sopenharmony_ci#include <errno.h> 138c2ecf20Sopenharmony_ci#include <sys/types.h> 148c2ecf20Sopenharmony_ci#include <sys/socket.h> 158c2ecf20Sopenharmony_ci#include <sys/time.h> 168c2ecf20Sopenharmony_ci#include <sys/un.h> 178c2ecf20Sopenharmony_ci#include "daemon.h" 188c2ecf20Sopenharmony_ci#include <net_user.h> 198c2ecf20Sopenharmony_ci#include <os.h> 208c2ecf20Sopenharmony_ci#include <um_malloc.h> 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_cienum request_type { REQ_NEW_CONTROL }; 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#define SWITCH_MAGIC 0xfeedface 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_cistruct request_v3 { 278c2ecf20Sopenharmony_ci uint32_t magic; 288c2ecf20Sopenharmony_ci uint32_t version; 298c2ecf20Sopenharmony_ci enum request_type type; 308c2ecf20Sopenharmony_ci struct sockaddr_un sock; 318c2ecf20Sopenharmony_ci}; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_cistatic struct sockaddr_un *new_addr(void *name, int len) 348c2ecf20Sopenharmony_ci{ 358c2ecf20Sopenharmony_ci struct sockaddr_un *sun; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci sun = uml_kmalloc(sizeof(struct sockaddr_un), UM_GFP_KERNEL); 388c2ecf20Sopenharmony_ci if (sun == NULL) { 398c2ecf20Sopenharmony_ci printk(UM_KERN_ERR "new_addr: allocation of sockaddr_un " 408c2ecf20Sopenharmony_ci "failed\n"); 418c2ecf20Sopenharmony_ci return NULL; 428c2ecf20Sopenharmony_ci } 438c2ecf20Sopenharmony_ci sun->sun_family = AF_UNIX; 448c2ecf20Sopenharmony_ci memcpy(sun->sun_path, name, len); 458c2ecf20Sopenharmony_ci return sun; 468c2ecf20Sopenharmony_ci} 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cistatic int connect_to_switch(struct daemon_data *pri) 498c2ecf20Sopenharmony_ci{ 508c2ecf20Sopenharmony_ci struct sockaddr_un *ctl_addr = pri->ctl_addr; 518c2ecf20Sopenharmony_ci struct sockaddr_un *local_addr = pri->local_addr; 528c2ecf20Sopenharmony_ci struct sockaddr_un *sun; 538c2ecf20Sopenharmony_ci struct request_v3 req; 548c2ecf20Sopenharmony_ci int fd, n, err; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci pri->control = socket(AF_UNIX, SOCK_STREAM, 0); 578c2ecf20Sopenharmony_ci if (pri->control < 0) { 588c2ecf20Sopenharmony_ci err = -errno; 598c2ecf20Sopenharmony_ci printk(UM_KERN_ERR "daemon_open : control socket failed, " 608c2ecf20Sopenharmony_ci "errno = %d\n", -err); 618c2ecf20Sopenharmony_ci return err; 628c2ecf20Sopenharmony_ci } 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci if (connect(pri->control, (struct sockaddr *) ctl_addr, 658c2ecf20Sopenharmony_ci sizeof(*ctl_addr)) < 0) { 668c2ecf20Sopenharmony_ci err = -errno; 678c2ecf20Sopenharmony_ci printk(UM_KERN_ERR "daemon_open : control connect failed, " 688c2ecf20Sopenharmony_ci "errno = %d\n", -err); 698c2ecf20Sopenharmony_ci goto out; 708c2ecf20Sopenharmony_ci } 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci fd = socket(AF_UNIX, SOCK_DGRAM, 0); 738c2ecf20Sopenharmony_ci if (fd < 0) { 748c2ecf20Sopenharmony_ci err = -errno; 758c2ecf20Sopenharmony_ci printk(UM_KERN_ERR "daemon_open : data socket failed, " 768c2ecf20Sopenharmony_ci "errno = %d\n", -err); 778c2ecf20Sopenharmony_ci goto out; 788c2ecf20Sopenharmony_ci } 798c2ecf20Sopenharmony_ci if (bind(fd, (struct sockaddr *) local_addr, sizeof(*local_addr)) < 0) { 808c2ecf20Sopenharmony_ci err = -errno; 818c2ecf20Sopenharmony_ci printk(UM_KERN_ERR "daemon_open : data bind failed, " 828c2ecf20Sopenharmony_ci "errno = %d\n", -err); 838c2ecf20Sopenharmony_ci goto out_close; 848c2ecf20Sopenharmony_ci } 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci sun = uml_kmalloc(sizeof(struct sockaddr_un), UM_GFP_KERNEL); 878c2ecf20Sopenharmony_ci if (sun == NULL) { 888c2ecf20Sopenharmony_ci printk(UM_KERN_ERR "new_addr: allocation of sockaddr_un " 898c2ecf20Sopenharmony_ci "failed\n"); 908c2ecf20Sopenharmony_ci err = -ENOMEM; 918c2ecf20Sopenharmony_ci goto out_close; 928c2ecf20Sopenharmony_ci } 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci req.magic = SWITCH_MAGIC; 958c2ecf20Sopenharmony_ci req.version = SWITCH_VERSION; 968c2ecf20Sopenharmony_ci req.type = REQ_NEW_CONTROL; 978c2ecf20Sopenharmony_ci req.sock = *local_addr; 988c2ecf20Sopenharmony_ci n = write(pri->control, &req, sizeof(req)); 998c2ecf20Sopenharmony_ci if (n != sizeof(req)) { 1008c2ecf20Sopenharmony_ci printk(UM_KERN_ERR "daemon_open : control setup request " 1018c2ecf20Sopenharmony_ci "failed, err = %d\n", -errno); 1028c2ecf20Sopenharmony_ci err = -ENOTCONN; 1038c2ecf20Sopenharmony_ci goto out_free; 1048c2ecf20Sopenharmony_ci } 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci n = read(pri->control, sun, sizeof(*sun)); 1078c2ecf20Sopenharmony_ci if (n != sizeof(*sun)) { 1088c2ecf20Sopenharmony_ci printk(UM_KERN_ERR "daemon_open : read of data socket failed, " 1098c2ecf20Sopenharmony_ci "err = %d\n", -errno); 1108c2ecf20Sopenharmony_ci err = -ENOTCONN; 1118c2ecf20Sopenharmony_ci goto out_free; 1128c2ecf20Sopenharmony_ci } 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci pri->data_addr = sun; 1158c2ecf20Sopenharmony_ci return fd; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci out_free: 1188c2ecf20Sopenharmony_ci kfree(sun); 1198c2ecf20Sopenharmony_ci out_close: 1208c2ecf20Sopenharmony_ci close(fd); 1218c2ecf20Sopenharmony_ci out: 1228c2ecf20Sopenharmony_ci close(pri->control); 1238c2ecf20Sopenharmony_ci return err; 1248c2ecf20Sopenharmony_ci} 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_cistatic int daemon_user_init(void *data, void *dev) 1278c2ecf20Sopenharmony_ci{ 1288c2ecf20Sopenharmony_ci struct daemon_data *pri = data; 1298c2ecf20Sopenharmony_ci struct timeval tv; 1308c2ecf20Sopenharmony_ci struct { 1318c2ecf20Sopenharmony_ci char zero; 1328c2ecf20Sopenharmony_ci int pid; 1338c2ecf20Sopenharmony_ci int usecs; 1348c2ecf20Sopenharmony_ci } name; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci if (!strcmp(pri->sock_type, "unix")) 1378c2ecf20Sopenharmony_ci pri->ctl_addr = new_addr(pri->ctl_sock, 1388c2ecf20Sopenharmony_ci strlen(pri->ctl_sock) + 1); 1398c2ecf20Sopenharmony_ci name.zero = 0; 1408c2ecf20Sopenharmony_ci name.pid = os_getpid(); 1418c2ecf20Sopenharmony_ci gettimeofday(&tv, NULL); 1428c2ecf20Sopenharmony_ci name.usecs = tv.tv_usec; 1438c2ecf20Sopenharmony_ci pri->local_addr = new_addr(&name, sizeof(name)); 1448c2ecf20Sopenharmony_ci pri->dev = dev; 1458c2ecf20Sopenharmony_ci pri->fd = connect_to_switch(pri); 1468c2ecf20Sopenharmony_ci if (pri->fd < 0) { 1478c2ecf20Sopenharmony_ci kfree(pri->local_addr); 1488c2ecf20Sopenharmony_ci pri->local_addr = NULL; 1498c2ecf20Sopenharmony_ci return pri->fd; 1508c2ecf20Sopenharmony_ci } 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci return 0; 1538c2ecf20Sopenharmony_ci} 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_cistatic int daemon_open(void *data) 1568c2ecf20Sopenharmony_ci{ 1578c2ecf20Sopenharmony_ci struct daemon_data *pri = data; 1588c2ecf20Sopenharmony_ci return pri->fd; 1598c2ecf20Sopenharmony_ci} 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_cistatic void daemon_remove(void *data) 1628c2ecf20Sopenharmony_ci{ 1638c2ecf20Sopenharmony_ci struct daemon_data *pri = data; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci close(pri->fd); 1668c2ecf20Sopenharmony_ci pri->fd = -1; 1678c2ecf20Sopenharmony_ci close(pri->control); 1688c2ecf20Sopenharmony_ci pri->control = -1; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci kfree(pri->data_addr); 1718c2ecf20Sopenharmony_ci pri->data_addr = NULL; 1728c2ecf20Sopenharmony_ci kfree(pri->ctl_addr); 1738c2ecf20Sopenharmony_ci pri->ctl_addr = NULL; 1748c2ecf20Sopenharmony_ci kfree(pri->local_addr); 1758c2ecf20Sopenharmony_ci pri->local_addr = NULL; 1768c2ecf20Sopenharmony_ci} 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ciint daemon_user_write(int fd, void *buf, int len, struct daemon_data *pri) 1798c2ecf20Sopenharmony_ci{ 1808c2ecf20Sopenharmony_ci struct sockaddr_un *data_addr = pri->data_addr; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci return net_sendto(fd, buf, len, data_addr, sizeof(*data_addr)); 1838c2ecf20Sopenharmony_ci} 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ciconst struct net_user_info daemon_user_info = { 1868c2ecf20Sopenharmony_ci .init = daemon_user_init, 1878c2ecf20Sopenharmony_ci .open = daemon_open, 1888c2ecf20Sopenharmony_ci .close = NULL, 1898c2ecf20Sopenharmony_ci .remove = daemon_remove, 1908c2ecf20Sopenharmony_ci .add_address = NULL, 1918c2ecf20Sopenharmony_ci .delete_address = NULL, 1928c2ecf20Sopenharmony_ci .mtu = ETH_MAX_PACKET, 1938c2ecf20Sopenharmony_ci .max_packet = ETH_MAX_PACKET + ETH_HEADER_OTHER, 1948c2ecf20Sopenharmony_ci}; 195