162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) 462306a36Sopenharmony_ci * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and 562306a36Sopenharmony_ci * James Leu (jleu@mindspring.net). 662306a36Sopenharmony_ci * Copyright (C) 2001 by various other people who didn't put their name here. 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <stdint.h> 1062306a36Sopenharmony_ci#include <string.h> 1162306a36Sopenharmony_ci#include <unistd.h> 1262306a36Sopenharmony_ci#include <errno.h> 1362306a36Sopenharmony_ci#include <sys/types.h> 1462306a36Sopenharmony_ci#include <sys/socket.h> 1562306a36Sopenharmony_ci#include <sys/time.h> 1662306a36Sopenharmony_ci#include <sys/un.h> 1762306a36Sopenharmony_ci#include "daemon.h" 1862306a36Sopenharmony_ci#include <net_user.h> 1962306a36Sopenharmony_ci#include <os.h> 2062306a36Sopenharmony_ci#include <um_malloc.h> 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_cienum request_type { REQ_NEW_CONTROL }; 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#define SWITCH_MAGIC 0xfeedface 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_cistruct request_v3 { 2762306a36Sopenharmony_ci uint32_t magic; 2862306a36Sopenharmony_ci uint32_t version; 2962306a36Sopenharmony_ci enum request_type type; 3062306a36Sopenharmony_ci struct sockaddr_un sock; 3162306a36Sopenharmony_ci}; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_cistatic struct sockaddr_un *new_addr(void *name, int len) 3462306a36Sopenharmony_ci{ 3562306a36Sopenharmony_ci struct sockaddr_un *sun; 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci sun = uml_kmalloc(sizeof(struct sockaddr_un), UM_GFP_KERNEL); 3862306a36Sopenharmony_ci if (sun == NULL) { 3962306a36Sopenharmony_ci printk(UM_KERN_ERR "new_addr: allocation of sockaddr_un " 4062306a36Sopenharmony_ci "failed\n"); 4162306a36Sopenharmony_ci return NULL; 4262306a36Sopenharmony_ci } 4362306a36Sopenharmony_ci sun->sun_family = AF_UNIX; 4462306a36Sopenharmony_ci memcpy(sun->sun_path, name, len); 4562306a36Sopenharmony_ci return sun; 4662306a36Sopenharmony_ci} 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_cistatic int connect_to_switch(struct daemon_data *pri) 4962306a36Sopenharmony_ci{ 5062306a36Sopenharmony_ci struct sockaddr_un *ctl_addr = pri->ctl_addr; 5162306a36Sopenharmony_ci struct sockaddr_un *local_addr = pri->local_addr; 5262306a36Sopenharmony_ci struct sockaddr_un *sun; 5362306a36Sopenharmony_ci struct request_v3 req; 5462306a36Sopenharmony_ci int fd, n, err; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci pri->control = socket(AF_UNIX, SOCK_STREAM, 0); 5762306a36Sopenharmony_ci if (pri->control < 0) { 5862306a36Sopenharmony_ci err = -errno; 5962306a36Sopenharmony_ci printk(UM_KERN_ERR "daemon_open : control socket failed, " 6062306a36Sopenharmony_ci "errno = %d\n", -err); 6162306a36Sopenharmony_ci return err; 6262306a36Sopenharmony_ci } 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci if (connect(pri->control, (struct sockaddr *) ctl_addr, 6562306a36Sopenharmony_ci sizeof(*ctl_addr)) < 0) { 6662306a36Sopenharmony_ci err = -errno; 6762306a36Sopenharmony_ci printk(UM_KERN_ERR "daemon_open : control connect failed, " 6862306a36Sopenharmony_ci "errno = %d\n", -err); 6962306a36Sopenharmony_ci goto out; 7062306a36Sopenharmony_ci } 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci fd = socket(AF_UNIX, SOCK_DGRAM, 0); 7362306a36Sopenharmony_ci if (fd < 0) { 7462306a36Sopenharmony_ci err = -errno; 7562306a36Sopenharmony_ci printk(UM_KERN_ERR "daemon_open : data socket failed, " 7662306a36Sopenharmony_ci "errno = %d\n", -err); 7762306a36Sopenharmony_ci goto out; 7862306a36Sopenharmony_ci } 7962306a36Sopenharmony_ci if (bind(fd, (struct sockaddr *) local_addr, sizeof(*local_addr)) < 0) { 8062306a36Sopenharmony_ci err = -errno; 8162306a36Sopenharmony_ci printk(UM_KERN_ERR "daemon_open : data bind failed, " 8262306a36Sopenharmony_ci "errno = %d\n", -err); 8362306a36Sopenharmony_ci goto out_close; 8462306a36Sopenharmony_ci } 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci sun = uml_kmalloc(sizeof(struct sockaddr_un), UM_GFP_KERNEL); 8762306a36Sopenharmony_ci if (sun == NULL) { 8862306a36Sopenharmony_ci printk(UM_KERN_ERR "new_addr: allocation of sockaddr_un " 8962306a36Sopenharmony_ci "failed\n"); 9062306a36Sopenharmony_ci err = -ENOMEM; 9162306a36Sopenharmony_ci goto out_close; 9262306a36Sopenharmony_ci } 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci req.magic = SWITCH_MAGIC; 9562306a36Sopenharmony_ci req.version = SWITCH_VERSION; 9662306a36Sopenharmony_ci req.type = REQ_NEW_CONTROL; 9762306a36Sopenharmony_ci req.sock = *local_addr; 9862306a36Sopenharmony_ci n = write(pri->control, &req, sizeof(req)); 9962306a36Sopenharmony_ci if (n != sizeof(req)) { 10062306a36Sopenharmony_ci printk(UM_KERN_ERR "daemon_open : control setup request " 10162306a36Sopenharmony_ci "failed, err = %d\n", -errno); 10262306a36Sopenharmony_ci err = -ENOTCONN; 10362306a36Sopenharmony_ci goto out_free; 10462306a36Sopenharmony_ci } 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci n = read(pri->control, sun, sizeof(*sun)); 10762306a36Sopenharmony_ci if (n != sizeof(*sun)) { 10862306a36Sopenharmony_ci printk(UM_KERN_ERR "daemon_open : read of data socket failed, " 10962306a36Sopenharmony_ci "err = %d\n", -errno); 11062306a36Sopenharmony_ci err = -ENOTCONN; 11162306a36Sopenharmony_ci goto out_free; 11262306a36Sopenharmony_ci } 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci pri->data_addr = sun; 11562306a36Sopenharmony_ci return fd; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci out_free: 11862306a36Sopenharmony_ci kfree(sun); 11962306a36Sopenharmony_ci out_close: 12062306a36Sopenharmony_ci close(fd); 12162306a36Sopenharmony_ci out: 12262306a36Sopenharmony_ci close(pri->control); 12362306a36Sopenharmony_ci return err; 12462306a36Sopenharmony_ci} 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_cistatic int daemon_user_init(void *data, void *dev) 12762306a36Sopenharmony_ci{ 12862306a36Sopenharmony_ci struct daemon_data *pri = data; 12962306a36Sopenharmony_ci struct timeval tv; 13062306a36Sopenharmony_ci struct { 13162306a36Sopenharmony_ci char zero; 13262306a36Sopenharmony_ci int pid; 13362306a36Sopenharmony_ci int usecs; 13462306a36Sopenharmony_ci } name; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci if (!strcmp(pri->sock_type, "unix")) 13762306a36Sopenharmony_ci pri->ctl_addr = new_addr(pri->ctl_sock, 13862306a36Sopenharmony_ci strlen(pri->ctl_sock) + 1); 13962306a36Sopenharmony_ci name.zero = 0; 14062306a36Sopenharmony_ci name.pid = os_getpid(); 14162306a36Sopenharmony_ci gettimeofday(&tv, NULL); 14262306a36Sopenharmony_ci name.usecs = tv.tv_usec; 14362306a36Sopenharmony_ci pri->local_addr = new_addr(&name, sizeof(name)); 14462306a36Sopenharmony_ci pri->dev = dev; 14562306a36Sopenharmony_ci pri->fd = connect_to_switch(pri); 14662306a36Sopenharmony_ci if (pri->fd < 0) { 14762306a36Sopenharmony_ci kfree(pri->local_addr); 14862306a36Sopenharmony_ci pri->local_addr = NULL; 14962306a36Sopenharmony_ci return pri->fd; 15062306a36Sopenharmony_ci } 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci return 0; 15362306a36Sopenharmony_ci} 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_cistatic int daemon_open(void *data) 15662306a36Sopenharmony_ci{ 15762306a36Sopenharmony_ci struct daemon_data *pri = data; 15862306a36Sopenharmony_ci return pri->fd; 15962306a36Sopenharmony_ci} 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_cistatic void daemon_remove(void *data) 16262306a36Sopenharmony_ci{ 16362306a36Sopenharmony_ci struct daemon_data *pri = data; 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci close(pri->fd); 16662306a36Sopenharmony_ci pri->fd = -1; 16762306a36Sopenharmony_ci close(pri->control); 16862306a36Sopenharmony_ci pri->control = -1; 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci kfree(pri->data_addr); 17162306a36Sopenharmony_ci pri->data_addr = NULL; 17262306a36Sopenharmony_ci kfree(pri->ctl_addr); 17362306a36Sopenharmony_ci pri->ctl_addr = NULL; 17462306a36Sopenharmony_ci kfree(pri->local_addr); 17562306a36Sopenharmony_ci pri->local_addr = NULL; 17662306a36Sopenharmony_ci} 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ciint daemon_user_write(int fd, void *buf, int len, struct daemon_data *pri) 17962306a36Sopenharmony_ci{ 18062306a36Sopenharmony_ci struct sockaddr_un *data_addr = pri->data_addr; 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci return net_sendto(fd, buf, len, data_addr, sizeof(*data_addr)); 18362306a36Sopenharmony_ci} 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ciconst struct net_user_info daemon_user_info = { 18662306a36Sopenharmony_ci .init = daemon_user_init, 18762306a36Sopenharmony_ci .open = daemon_open, 18862306a36Sopenharmony_ci .close = NULL, 18962306a36Sopenharmony_ci .remove = daemon_remove, 19062306a36Sopenharmony_ci .add_address = NULL, 19162306a36Sopenharmony_ci .delete_address = NULL, 19262306a36Sopenharmony_ci .mtu = ETH_MAX_PACKET, 19362306a36Sopenharmony_ci .max_packet = ETH_MAX_PACKET + ETH_HEADER_OTHER, 19462306a36Sopenharmony_ci}; 195