linux/arch/um/drivers/slip_user.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
   3 * Licensed under the GPL.
   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 <sys/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        if (set_up_tty(sfd))
 149                goto out_close2;
 150
 151        pri->slave = sfd;
 152        pri->slip.pos = 0;
 153        pri->slip.esc = 0;
 154        if (pri->gate_addr != NULL) {
 155                sprintf(version_buf, "%d", UML_NET_VERSION);
 156                strcpy(gate_buf, pri->gate_addr);
 157
 158                err = slip_tramp(argv, sfd);
 159
 160                if (err < 0) {
 161                        printk(UM_KERN_ERR "slip_tramp failed - err = %d\n",
 162                               -err);
 163                        goto out_close2;
 164                }
 165                err = os_get_ifname(pri->slave, pri->name);
 166                if (err < 0) {
 167                        printk(UM_KERN_ERR "get_ifname failed, err = %d\n",
 168                               -err);
 169                        goto out_close2;
 170                }
 171                iter_addresses(pri->dev, open_addr, pri->name);
 172        }
 173        else {
 174                err = os_set_slip(sfd);
 175                if (err < 0) {
 176                        printk(UM_KERN_ERR "Failed to set slip discipline "
 177                               "encapsulation - err = %d\n", -err);
 178                        goto out_close2;
 179                }
 180        }
 181        return mfd;
 182out_close2:
 183        close(sfd);
 184out_close:
 185        close(mfd);
 186out:
 187        return err;
 188}
 189
 190static void slip_close(int fd, void *data)
 191{
 192        struct slip_data *pri = data;
 193        char version_buf[sizeof("nnnnn\0")];
 194        char *argv[] = { "uml_net", version_buf, "slip", "down", pri->name,
 195                         NULL };
 196        int err;
 197
 198        if (pri->gate_addr != NULL)
 199                iter_addresses(pri->dev, close_addr, pri->name);
 200
 201        sprintf(version_buf, "%d", UML_NET_VERSION);
 202
 203        err = slip_tramp(argv, pri->slave);
 204
 205        if (err != 0)
 206                printk(UM_KERN_ERR "slip_tramp failed - errno = %d\n", -err);
 207        close(fd);
 208        close(pri->slave);
 209        pri->slave = -1;
 210}
 211
 212int slip_user_read(int fd, void *buf, int len, struct slip_data *pri)
 213{
 214        return slip_proto_read(fd, buf, len, &pri->slip);
 215}
 216
 217int slip_user_write(int fd, void *buf, int len, struct slip_data *pri)
 218{
 219        return slip_proto_write(fd, buf, len, &pri->slip);
 220}
 221
 222static void slip_add_addr(unsigned char *addr, unsigned char *netmask,
 223                          void *data)
 224{
 225        struct slip_data *pri = data;
 226
 227        if (pri->slave < 0)
 228                return;
 229        open_addr(addr, netmask, pri->name);
 230}
 231
 232static void slip_del_addr(unsigned char *addr, unsigned char *netmask,
 233                            void *data)
 234{
 235        struct slip_data *pri = data;
 236
 237        if (pri->slave < 0)
 238                return;
 239        close_addr(addr, netmask, pri->name);
 240}
 241
 242const struct net_user_info slip_user_info = {
 243        .init           = slip_user_init,
 244        .open           = slip_open,
 245        .close          = slip_close,
 246        .remove         = NULL,
 247        .add_address    = slip_add_addr,
 248        .delete_address = slip_del_addr,
 249        .mtu            = BUF_SIZE,
 250        .max_packet     = BUF_SIZE,
 251};
 252