root/arch/um/os-Linux/drivers/ethertap_user.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. etap_user_init
  2. etap_change
  3. etap_open_addr
  4. etap_close_addr
  5. etap_pre_exec
  6. etap_tramp
  7. etap_open
  8. etap_close
  9. etap_add_addr
  10. etap_del_addr

   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 <stdio.h>
  10 #include <unistd.h>
  11 #include <errno.h>
  12 #include <string.h>
  13 #include <sys/socket.h>
  14 #include <sys/wait.h>
  15 #include "etap.h"
  16 #include <os.h>
  17 #include <net_user.h>
  18 #include <um_malloc.h>
  19 
  20 #define MAX_PACKET ETH_MAX_PACKET
  21 
  22 static int etap_user_init(void *data, void *dev)
  23 {
  24         struct ethertap_data *pri = data;
  25 
  26         pri->dev = dev;
  27         return 0;
  28 }
  29 
  30 struct addr_change {
  31         enum { ADD_ADDR, DEL_ADDR } what;
  32         unsigned char addr[4];
  33         unsigned char netmask[4];
  34 };
  35 
  36 static void etap_change(int op, unsigned char *addr, unsigned char *netmask,
  37                         int fd)
  38 {
  39         struct addr_change change;
  40         char *output;
  41         int n;
  42 
  43         change.what = op;
  44         memcpy(change.addr, addr, sizeof(change.addr));
  45         memcpy(change.netmask, netmask, sizeof(change.netmask));
  46         CATCH_EINTR(n = write(fd, &change, sizeof(change)));
  47         if (n != sizeof(change)) {
  48                 printk(UM_KERN_ERR "etap_change - request failed, err = %d\n",
  49                        errno);
  50                 return;
  51         }
  52 
  53         output = uml_kmalloc(UM_KERN_PAGE_SIZE, UM_GFP_KERNEL);
  54         if (output == NULL)
  55                 printk(UM_KERN_ERR "etap_change : Failed to allocate output "
  56                        "buffer\n");
  57         read_output(fd, output, UM_KERN_PAGE_SIZE);
  58         if (output != NULL) {
  59                 printk("%s", output);
  60                 kfree(output);
  61         }
  62 }
  63 
  64 static void etap_open_addr(unsigned char *addr, unsigned char *netmask,
  65                            void *arg)
  66 {
  67         etap_change(ADD_ADDR, addr, netmask, *((int *) arg));
  68 }
  69 
  70 static void etap_close_addr(unsigned char *addr, unsigned char *netmask,
  71                             void *arg)
  72 {
  73         etap_change(DEL_ADDR, addr, netmask, *((int *) arg));
  74 }
  75 
  76 struct etap_pre_exec_data {
  77         int control_remote;
  78         int control_me;
  79         int data_me;
  80 };
  81 
  82 static void etap_pre_exec(void *arg)
  83 {
  84         struct etap_pre_exec_data *data = arg;
  85 
  86         dup2(data->control_remote, 1);
  87         close(data->data_me);
  88         close(data->control_me);
  89 }
  90 
  91 static int etap_tramp(char *dev, char *gate, int control_me,
  92                       int control_remote, int data_me, int data_remote)
  93 {
  94         struct etap_pre_exec_data pe_data;
  95         int pid, err, n;
  96         char version_buf[sizeof("nnnnn\0")];
  97         char data_fd_buf[sizeof("nnnnnn\0")];
  98         char gate_buf[sizeof("nnn.nnn.nnn.nnn\0")];
  99         char *setup_args[] = { "uml_net", version_buf, "ethertap", dev,
 100                                data_fd_buf, gate_buf, NULL };
 101         char *nosetup_args[] = { "uml_net", version_buf, "ethertap",
 102                                  dev, data_fd_buf, NULL };
 103         char **args, c;
 104 
 105         sprintf(data_fd_buf, "%d", data_remote);
 106         sprintf(version_buf, "%d", UML_NET_VERSION);
 107         if (gate != NULL) {
 108                 strncpy(gate_buf, gate, 15);
 109                 args = setup_args;
 110         }
 111         else args = nosetup_args;
 112 
 113         err = 0;
 114         pe_data.control_remote = control_remote;
 115         pe_data.control_me = control_me;
 116         pe_data.data_me = data_me;
 117         pid = run_helper(etap_pre_exec, &pe_data, args);
 118 
 119         if (pid < 0)
 120                 err = pid;
 121         close(data_remote);
 122         close(control_remote);
 123         CATCH_EINTR(n = read(control_me, &c, sizeof(c)));
 124         if (n != sizeof(c)) {
 125                 err = -errno;
 126                 printk(UM_KERN_ERR "etap_tramp : read of status failed, "
 127                        "err = %d\n", -err);
 128                 return err;
 129         }
 130         if (c != 1) {
 131                 printk(UM_KERN_ERR "etap_tramp : uml_net failed\n");
 132                 err = helper_wait(pid);
 133         }
 134         return err;
 135 }
 136 
 137 static int etap_open(void *data)
 138 {
 139         struct ethertap_data *pri = data;
 140         char *output;
 141         int data_fds[2], control_fds[2], err, output_len;
 142 
 143         err = tap_open_common(pri->dev, pri->gate_addr);
 144         if (err)
 145                 return err;
 146 
 147         err = socketpair(AF_UNIX, SOCK_DGRAM, 0, data_fds);
 148         if (err) {
 149                 err = -errno;
 150                 printk(UM_KERN_ERR "etap_open - data socketpair failed - "
 151                        "err = %d\n", errno);
 152                 return err;
 153         }
 154 
 155         err = socketpair(AF_UNIX, SOCK_STREAM, 0, control_fds);
 156         if (err) {
 157                 err = -errno;
 158                 printk(UM_KERN_ERR "etap_open - control socketpair failed - "
 159                        "err = %d\n", errno);
 160                 goto out_close_data;
 161         }
 162 
 163         err = etap_tramp(pri->dev_name, pri->gate_addr, control_fds[0],
 164                          control_fds[1], data_fds[0], data_fds[1]);
 165         output_len = UM_KERN_PAGE_SIZE;
 166         output = uml_kmalloc(output_len, UM_GFP_KERNEL);
 167         read_output(control_fds[0], output, output_len);
 168 
 169         if (output == NULL)
 170                 printk(UM_KERN_ERR "etap_open : failed to allocate output "
 171                        "buffer\n");
 172         else {
 173                 printk("%s", output);
 174                 kfree(output);
 175         }
 176 
 177         if (err < 0) {
 178                 printk(UM_KERN_ERR "etap_tramp failed - err = %d\n", -err);
 179                 goto out_close_control;
 180         }
 181 
 182         pri->data_fd = data_fds[0];
 183         pri->control_fd = control_fds[0];
 184         iter_addresses(pri->dev, etap_open_addr, &pri->control_fd);
 185         return data_fds[0];
 186 
 187 out_close_control:
 188         close(control_fds[0]);
 189         close(control_fds[1]);
 190 out_close_data:
 191         close(data_fds[0]);
 192         close(data_fds[1]);
 193         return err;
 194 }
 195 
 196 static void etap_close(int fd, void *data)
 197 {
 198         struct ethertap_data *pri = data;
 199 
 200         iter_addresses(pri->dev, etap_close_addr, &pri->control_fd);
 201         close(fd);
 202 
 203         if (shutdown(pri->data_fd, SHUT_RDWR) < 0)
 204                 printk(UM_KERN_ERR "etap_close - shutdown data socket failed, "
 205                        "errno = %d\n", errno);
 206 
 207         if (shutdown(pri->control_fd, SHUT_RDWR) < 0)
 208                 printk(UM_KERN_ERR "etap_close - shutdown control socket "
 209                        "failed, errno = %d\n", errno);
 210 
 211         close(pri->data_fd);
 212         pri->data_fd = -1;
 213         close(pri->control_fd);
 214         pri->control_fd = -1;
 215 }
 216 
 217 static void etap_add_addr(unsigned char *addr, unsigned char *netmask,
 218                           void *data)
 219 {
 220         struct ethertap_data *pri = data;
 221 
 222         tap_check_ips(pri->gate_addr, addr);
 223         if (pri->control_fd == -1)
 224                 return;
 225         etap_open_addr(addr, netmask, &pri->control_fd);
 226 }
 227 
 228 static void etap_del_addr(unsigned char *addr, unsigned char *netmask,
 229                           void *data)
 230 {
 231         struct ethertap_data *pri = data;
 232 
 233         if (pri->control_fd == -1)
 234                 return;
 235 
 236         etap_close_addr(addr, netmask, &pri->control_fd);
 237 }
 238 
 239 const struct net_user_info ethertap_user_info = {
 240         .init           = etap_user_init,
 241         .open           = etap_open,
 242         .close          = etap_close,
 243         .remove         = NULL,
 244         .add_address    = etap_add_addr,
 245         .delete_address = etap_del_addr,
 246         .mtu            = ETH_MAX_PACKET,
 247         .max_packet     = ETH_MAX_PACKET + ETH_HEADER_ETHERTAP,
 248 };

/* [<][>][^][v][top][bottom][index][help] */