linux/arch/um/drivers/slip_user.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright (C) 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
   4 */
   5
   6#include <stdio.h>
   7#include <stdlib.h>
   8#include <unistd.h>
   9#include <errno.h>
  10#include <fcntl.h>
  11#include <string.h>
  12#include <termios.h>
  13#include <sys/wait.h>
  14#include <net_user.h>
  15#include <os.h>
  16#include "slip.h"
  17#include <um_malloc.h>
  18
  19static int slip_user_init(void *data, void *dev)
  20{
  21        struct slip_data *pri = data;
  22
  23        pri->dev = dev;
  24        return 0;
  25}
  26
  27static int set_up_tty(int fd)
  28{
  29        int i;
  30        struct termios tios;
  31
  32        if (tcgetattr(fd, &tios) < 0) {
  33                printk(UM_KERN_ERR "could not get initial terminal "
  34                       "attributes\n");
  35                return -1;
  36        }
  37
  38        tios.c_cflag = CS8 | CREAD | HUPCL | CLOCAL;
  39        tios.c_iflag = IGNBRK | IGNPAR;
  40        tios.c_oflag = 0;
  41        tios.c_lflag = 0;
  42        for (i = 0; i < NCCS; i++)
  43                tios.c_cc[i] = 0;
  44        tios.c_cc[VMIN] = 1;
  45        tios.c_cc[VTIME] = 0;
  46
  47        cfsetospeed(&tios, B38400);
  48        cfsetispeed(&tios, B38400);
  49
  50        if (tcsetattr(fd, TCSAFLUSH, &tios) < 0) {
  51                printk(UM_KERN_ERR "failed to set terminal attributes\n");
  52                return -1;
  53        }
  54        return 0;
  55}
  56
  57struct slip_pre_exec_data {
  58        int stdin_fd;
  59        int stdout_fd;
  60        int close_me;
  61};
  62
  63static void slip_pre_exec(void *arg)
  64{
  65        struct slip_pre_exec_data *data = arg;
  66
  67        if (data->stdin_fd >= 0)
  68                dup2(data->stdin_fd, 0);
  69        dup2(data->stdout_fd, 1);
  70        if (data->close_me >= 0)
  71                close(data->close_me);
  72}
  73
  74static int slip_tramp(char **argv, int fd)
  75{
  76        struct slip_pre_exec_data pe_data;
  77        char *output;
  78        int pid, fds[2], err, output_len;
  79
  80        err = os_pipe(fds, 1, 0);
  81        if (err < 0) {
  82                printk(UM_KERN_ERR "slip_tramp : pipe failed, err = %d\n",
  83                       -err);
  84                goto out;
  85        }
  86
  87        err = 0;
  88        pe_data.stdin_fd = fd;
  89        pe_data.stdout_fd = fds[1];
  90        pe_data.close_me = fds[0];
  91        err = run_helper(slip_pre_exec, &pe_data, argv);
  92        if (err < 0)
  93                goto out_close;
  94        pid = err;
  95
  96        output_len = UM_KERN_PAGE_SIZE;
  97        output = uml_kmalloc(output_len, UM_GFP_KERNEL);
  98        if (output == NULL) {
  99                printk(UM_KERN_ERR "slip_tramp : failed to allocate output "
 100                       "buffer\n");
 101                os_kill_process(pid, 1);
 102                err = -ENOMEM;
 103                goto out_close;
 104        }
 105
 106        close(fds[1]);
 107        read_output(fds[0], output, output_len);
 108        printk("%s", output);
 109
 110        err = helper_wait(pid);
 111        close(fds[0]);
 112
 113        kfree(output);
 114        return err;
 115
 116out_close:
 117        close(fds[0]);
 118        close(fds[1]);
 119out:
 120        return err;
 121}
 122
 123static int slip_open(void *data)
 124{
 125        struct slip_data *pri = data;
 126        char version_buf[sizeof("nnnnn\0")];
 127        char gate_buf[sizeof("nnn.nnn.nnn.nnn\0")];
 128        char *argv[] = { "uml_net", version_buf, "slip", "up", gate_buf,
 129                         NULL };
 130        int sfd, mfd, err;
 131
 132        err = get_pty();
 133        if (err < 0) {
 134                printk(UM_KERN_ERR "slip-open : Failed to open pty, err = %d\n",
 135                       -err);
 136                goto out;
 137        }
 138        mfd = err;
 139
 140        err = open(ptsname(mfd), O_RDWR, 0);
 141        if (err < 0) {
 142                printk(UM_KERN_ERR "Couldn't open tty for slip line, "
 143                       "err = %d\n", -err);
 144                goto out_close;
 145        }
 146        sfd = err;
 147
 148        err = set_up_tty(sfd);
 149        if (err)
 150                goto out_close2;
 151
 152        pri->slave = sfd;
 153        pri->slip.pos = 0;
 154        pri->slip.esc = 0;
 155        if (pri->gate_addr != NULL) {
 156                sprintf(version_buf, "%d", UML_NET_VERSION);
 157                strcpy(gate_buf, pri->gate_addr);
 158
 159                err = slip_tramp(argv, sfd);
 160
 161                if (err < 0) {
 162                        printk(UM_KERN_ERR "slip_tramp failed - err = %d\n",
 163                               -err);
 164                        goto out_close2;
 165                }
 166                err = os_get_ifname(pri->slave, pri->name);
 167                if (err < 0) {
 168                        printk(UM_KERN_ERR "get_ifname failed, err = %d\n",
 169                               -err);
 170                        goto out_close2;
 171                }
 172                iter_addresses(pri->dev, open_addr, pri->name);
 173        }
 174        else {
 175                err = os_set_slip(sfd);
 176                if (err < 0) {
 177                        printk(UM_KERN_ERR "Failed to set slip discipline "
 178                               "encapsulation - err = %d\n", -err);
 179                        goto out_close2;
 180                }
 181        }
 182        return mfd;
 183out_close2:
 184        close(sfd);
 185out_close:
 186        close(mfd);
 187out:
 188        return err;
 189}
 190
 191static void slip_close(int fd, void *data)
 192{
 193        struct slip_data *pri = data;
 194        char version_buf[sizeof("nnnnn\0")];
 195        char *argv[] = { "uml_net", version_buf, "slip", "down", pri->name,
 196                         NULL };
 197        int err;
 198
 199        if (pri->gate_addr != NULL)
 200                iter_addresses(pri->dev, close_addr, pri->name);
 201
 202        sprintf(version_buf, "%d", UML_NET_VERSION);
 203
 204        err = slip_tramp(argv, pri->slave);
 205
 206        if (err != 0)
 207                printk(UM_KERN_ERR "slip_tramp failed - errno = %d\n", -err);
 208        close(fd);
 209        close(pri->slave);
 210        pri->slave = -1;
 211}
 212
 213int slip_user_read(int fd, void *buf, int len, struct slip_data *pri)
 214{
 215        return slip_proto_read(fd, buf, len, &pri->slip);
 216}
 217
 218int slip_user_write(int fd, void *buf, int len, struct slip_data *pri)
 219{
 220        return slip_proto_write(fd, buf, len, &pri->slip);
 221}
 222
 223static void slip_add_addr(unsigned char *addr, unsigned char *netmask,
 224                          void *data)
 225{
 226        struct slip_data *pri = data;
 227
 228        if (pri->slave < 0)
 229                return;
 230        open_addr(addr, netmask, pri->name);
 231}
 232
 233static void slip_del_addr(unsigned char *addr, unsigned char *netmask,
 234                            void *data)
 235{
 236        struct slip_data *pri = data;
 237
 238        if (pri->slave < 0)
 239                return;
 240        close_addr(addr, netmask, pri->name);
 241}
 242
 243const struct net_user_info slip_user_info = {
 244        .init           = slip_user_init,
 245        .open           = slip_open,
 246        .close          = slip_close,
 247        .remove         = NULL,
 248        .add_address    = slip_add_addr,
 249        .delete_address = slip_del_addr,
 250        .mtu            = BUF_SIZE,
 251        .max_packet     = BUF_SIZE,
 252};
 253