1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) 4 * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and 5 * James Leu (jleu@mindspring.net). 6 * Copyright (C) 2001 by various other people who didn't put their name here. 7 */ 8 9 #include <stdint.h> 10 #include <string.h> 11 #include <unistd.h> 12 #include <errno.h> 13 #include <sys/types.h> 14 #include <sys/socket.h> 15 #include <sys/time.h> 16 #include <sys/un.h> 17 #include "daemon.h" 18 #include <net_user.h> 19 #include <os.h> 20 #include <um_malloc.h> 21 22 enum request_type { REQ_NEW_CONTROL }; 23 24 #define SWITCH_MAGIC 0xfeedface 25 26 struct request_v3 { 27 uint32_t magic; 28 uint32_t version; 29 enum request_type type; 30 struct sockaddr_un sock; 31 }; 32 33 static struct sockaddr_un *new_addr(void *name, int len) 34 { 35 struct sockaddr_un *sun; 36 37 sun = uml_kmalloc(sizeof(struct sockaddr_un), UM_GFP_KERNEL); 38 if (sun == NULL) { 39 printk(UM_KERN_ERR "new_addr: allocation of sockaddr_un " 40 "failed\n"); 41 return NULL; 42 } 43 sun->sun_family = AF_UNIX; 44 memcpy(sun->sun_path, name, len); 45 return sun; 46 } 47 48 static int connect_to_switch(struct daemon_data *pri) 49 { 50 struct sockaddr_un *ctl_addr = pri->ctl_addr; 51 struct sockaddr_un *local_addr = pri->local_addr; 52 struct sockaddr_un *sun; 53 struct request_v3 req; 54 int fd, n, err; 55 56 pri->control = socket(AF_UNIX, SOCK_STREAM, 0); 57 if (pri->control < 0) { 58 err = -errno; 59 printk(UM_KERN_ERR "daemon_open : control socket failed, " 60 "errno = %d\n", -err); 61 return err; 62 } 63 64 if (connect(pri->control, (struct sockaddr *) ctl_addr, 65 sizeof(*ctl_addr)) < 0) { 66 err = -errno; 67 printk(UM_KERN_ERR "daemon_open : control connect failed, " 68 "errno = %d\n", -err); 69 goto out; 70 } 71 72 fd = socket(AF_UNIX, SOCK_DGRAM, 0); 73 if (fd < 0) { 74 err = -errno; 75 printk(UM_KERN_ERR "daemon_open : data socket failed, " 76 "errno = %d\n", -err); 77 goto out; 78 } 79 if (bind(fd, (struct sockaddr *) local_addr, sizeof(*local_addr)) < 0) { 80 err = -errno; 81 printk(UM_KERN_ERR "daemon_open : data bind failed, " 82 "errno = %d\n", -err); 83 goto out_close; 84 } 85 86 sun = uml_kmalloc(sizeof(struct sockaddr_un), UM_GFP_KERNEL); 87 if (sun == NULL) { 88 printk(UM_KERN_ERR "new_addr: allocation of sockaddr_un " 89 "failed\n"); 90 err = -ENOMEM; 91 goto out_close; 92 } 93 94 req.magic = SWITCH_MAGIC; 95 req.version = SWITCH_VERSION; 96 req.type = REQ_NEW_CONTROL; 97 req.sock = *local_addr; 98 n = write(pri->control, &req, sizeof(req)); 99 if (n != sizeof(req)) { 100 printk(UM_KERN_ERR "daemon_open : control setup request " 101 "failed, err = %d\n", -errno); 102 err = -ENOTCONN; 103 goto out_free; 104 } 105 106 n = read(pri->control, sun, sizeof(*sun)); 107 if (n != sizeof(*sun)) { 108 printk(UM_KERN_ERR "daemon_open : read of data socket failed, " 109 "err = %d\n", -errno); 110 err = -ENOTCONN; 111 goto out_free; 112 } 113 114 pri->data_addr = sun; 115 return fd; 116 117 out_free: 118 kfree(sun); 119 out_close: 120 close(fd); 121 out: 122 close(pri->control); 123 return err; 124 } 125 126 static int daemon_user_init(void *data, void *dev) 127 { 128 struct daemon_data *pri = data; 129 struct timeval tv; 130 struct { 131 char zero; 132 int pid; 133 int usecs; 134 } name; 135 136 if (!strcmp(pri->sock_type, "unix")) 137 pri->ctl_addr = new_addr(pri->ctl_sock, 138 strlen(pri->ctl_sock) + 1); 139 name.zero = 0; 140 name.pid = os_getpid(); 141 gettimeofday(&tv, NULL); 142 name.usecs = tv.tv_usec; 143 pri->local_addr = new_addr(&name, sizeof(name)); 144 pri->dev = dev; 145 pri->fd = connect_to_switch(pri); 146 if (pri->fd < 0) { 147 kfree(pri->local_addr); 148 pri->local_addr = NULL; 149 return pri->fd; 150 } 151 152 return 0; 153 } 154 155 static int daemon_open(void *data) 156 { 157 struct daemon_data *pri = data; 158 return pri->fd; 159 } 160 161 static void daemon_remove(void *data) 162 { 163 struct daemon_data *pri = data; 164 165 close(pri->fd); 166 pri->fd = -1; 167 close(pri->control); 168 pri->control = -1; 169 170 kfree(pri->data_addr); 171 pri->data_addr = NULL; 172 kfree(pri->ctl_addr); 173 pri->ctl_addr = NULL; 174 kfree(pri->local_addr); 175 pri->local_addr = NULL; 176 } 177 178 int daemon_user_write(int fd, void *buf, int len, struct daemon_data *pri) 179 { 180 struct sockaddr_un *data_addr = pri->data_addr; 181 182 return net_sendto(fd, buf, len, data_addr, sizeof(*data_addr)); 183 } 184 185 const struct net_user_info daemon_user_info = { 186 .init = daemon_user_init, 187 .open = daemon_open, 188 .close = NULL, 189 .remove = daemon_remove, 190 .add_address = NULL, 191 .delete_address = NULL, 192 .mtu = ETH_MAX_PACKET, 193 .max_packet = ETH_MAX_PACKET + ETH_HEADER_OTHER, 194 }; 195
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.