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