root/arch/um/drivers/port_user.c

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

DEFINITIONS

This source file includes following definitions.
  1. port_init
  2. port_free
  3. port_open
  4. port_close
  5. port_listen_fd
  6. port_pre_exec
  7. port_connection

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{linux.intel,addtoit}.com)
   4  */
   5 
   6 #include <stdio.h>
   7 #include <stdlib.h>
   8 #include <errno.h>
   9 #include <termios.h>
  10 #include <unistd.h>
  11 #include <netinet/in.h>
  12 #include "chan_user.h"
  13 #include <os.h>
  14 #include "port.h"
  15 #include <um_malloc.h>
  16 
  17 struct port_chan {
  18         int raw;
  19         struct termios tt;
  20         void *kernel_data;
  21         char dev[sizeof("32768\0")];
  22 };
  23 
  24 static void *port_init(char *str, int device, const struct chan_opts *opts)
  25 {
  26         struct port_chan *data;
  27         void *kern_data;
  28         char *end;
  29         int port;
  30 
  31         if (*str != ':') {
  32                 printk(UM_KERN_ERR "port_init : channel type 'port' must "
  33                        "specify a port number\n");
  34                 return NULL;
  35         }
  36         str++;
  37         port = strtoul(str, &end, 0);
  38         if ((*end != '\0') || (end == str)) {
  39                 printk(UM_KERN_ERR "port_init : couldn't parse port '%s'\n",
  40                        str);
  41                 return NULL;
  42         }
  43 
  44         kern_data = port_data(port);
  45         if (kern_data == NULL)
  46                 return NULL;
  47 
  48         data = uml_kmalloc(sizeof(*data), UM_GFP_KERNEL);
  49         if (data == NULL)
  50                 goto err;
  51 
  52         *data = ((struct port_chan) { .raw              = opts->raw,
  53                                       .kernel_data      = kern_data });
  54         sprintf(data->dev, "%d", port);
  55 
  56         return data;
  57  err:
  58         port_kern_free(kern_data);
  59         return NULL;
  60 }
  61 
  62 static void port_free(void *d)
  63 {
  64         struct port_chan *data = d;
  65 
  66         port_kern_free(data->kernel_data);
  67         kfree(data);
  68 }
  69 
  70 static int port_open(int input, int output, int primary, void *d,
  71                      char **dev_out)
  72 {
  73         struct port_chan *data = d;
  74         int fd, err;
  75 
  76         fd = port_wait(data->kernel_data);
  77         if ((fd >= 0) && data->raw) {
  78                 CATCH_EINTR(err = tcgetattr(fd, &data->tt));
  79                 if (err)
  80                         return err;
  81 
  82                 err = raw(fd);
  83                 if (err)
  84                         return err;
  85         }
  86         *dev_out = data->dev;
  87         return fd;
  88 }
  89 
  90 static void port_close(int fd, void *d)
  91 {
  92         struct port_chan *data = d;
  93 
  94         port_remove_dev(data->kernel_data);
  95         os_close_file(fd);
  96 }
  97 
  98 const struct chan_ops port_ops = {
  99         .type           = "port",
 100         .init           = port_init,
 101         .open           = port_open,
 102         .close          = port_close,
 103         .read           = generic_read,
 104         .write          = generic_write,
 105         .console_write  = generic_console_write,
 106         .window_size    = generic_window_size,
 107         .free           = port_free,
 108         .winch          = 1,
 109 };
 110 
 111 int port_listen_fd(int port)
 112 {
 113         struct sockaddr_in addr;
 114         int fd, err, arg;
 115 
 116         fd = socket(PF_INET, SOCK_STREAM, 0);
 117         if (fd == -1)
 118                 return -errno;
 119 
 120         arg = 1;
 121         if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &arg, sizeof(arg)) < 0) {
 122                 err = -errno;
 123                 goto out;
 124         }
 125 
 126         addr.sin_family = AF_INET;
 127         addr.sin_port = htons(port);
 128         addr.sin_addr.s_addr = htonl(INADDR_ANY);
 129         if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
 130                 err = -errno;
 131                 goto out;
 132         }
 133 
 134         if (listen(fd, 1) < 0) {
 135                 err = -errno;
 136                 goto out;
 137         }
 138 
 139         err = os_set_fd_block(fd, 0);
 140         if (err < 0)
 141                 goto out;
 142 
 143         return fd;
 144  out:
 145         close(fd);
 146         return err;
 147 }
 148 
 149 struct port_pre_exec_data {
 150         int sock_fd;
 151         int pipe_fd;
 152 };
 153 
 154 static void port_pre_exec(void *arg)
 155 {
 156         struct port_pre_exec_data *data = arg;
 157 
 158         dup2(data->sock_fd, 0);
 159         dup2(data->sock_fd, 1);
 160         dup2(data->sock_fd, 2);
 161         close(data->sock_fd);
 162         dup2(data->pipe_fd, 3);
 163         shutdown(3, SHUT_RD);
 164         close(data->pipe_fd);
 165 }
 166 
 167 int port_connection(int fd, int *socket, int *pid_out)
 168 {
 169         int new, err;
 170         char *argv[] = { "/usr/sbin/in.telnetd", "-L",
 171                          OS_LIB_PATH "/uml/port-helper", NULL };
 172         struct port_pre_exec_data data;
 173 
 174         new = accept(fd, NULL, 0);
 175         if (new < 0)
 176                 return -errno;
 177 
 178         err = os_pipe(socket, 0, 0);
 179         if (err < 0)
 180                 goto out_close;
 181 
 182         data = ((struct port_pre_exec_data)
 183                 { .sock_fd              = new,
 184                   .pipe_fd              = socket[1] });
 185 
 186         err = run_helper(port_pre_exec, &data, argv);
 187         if (err < 0)
 188                 goto out_shutdown;
 189 
 190         *pid_out = err;
 191         return new;
 192 
 193  out_shutdown:
 194         shutdown(socket[0], SHUT_RDWR);
 195         close(socket[0]);
 196         shutdown(socket[1], SHUT_RDWR);
 197         close(socket[1]);
 198  out_close:
 199         close(new);
 200         return err;
 201 }

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