Path: blob/master/arch/um/os-Linux/drivers/ethertap_user.c
10819 views
/*1* Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)2* Copyright (C) 2001 Lennert Buytenhek ([email protected]) and3* James Leu ([email protected]).4* Copyright (C) 2001 by various other people who didn't put their name here.5* Licensed under the GPL.6*/78#include <stdio.h>9#include <unistd.h>10#include <errno.h>11#include <string.h>12#include <sys/socket.h>13#include <sys/wait.h>14#include "etap.h"15#include "kern_constants.h"16#include "os.h"17#include "net_user.h"18#include "um_malloc.h"19#include "user.h"2021#define MAX_PACKET ETH_MAX_PACKET2223static int etap_user_init(void *data, void *dev)24{25struct ethertap_data *pri = data;2627pri->dev = dev;28return 0;29}3031struct addr_change {32enum { ADD_ADDR, DEL_ADDR } what;33unsigned char addr[4];34unsigned char netmask[4];35};3637static void etap_change(int op, unsigned char *addr, unsigned char *netmask,38int fd)39{40struct addr_change change;41char *output;42int n;4344change.what = op;45memcpy(change.addr, addr, sizeof(change.addr));46memcpy(change.netmask, netmask, sizeof(change.netmask));47CATCH_EINTR(n = write(fd, &change, sizeof(change)));48if (n != sizeof(change)) {49printk(UM_KERN_ERR "etap_change - request failed, err = %d\n",50errno);51return;52}5354output = uml_kmalloc(UM_KERN_PAGE_SIZE, UM_GFP_KERNEL);55if (output == NULL)56printk(UM_KERN_ERR "etap_change : Failed to allocate output "57"buffer\n");58read_output(fd, output, UM_KERN_PAGE_SIZE);59if (output != NULL) {60printk("%s", output);61kfree(output);62}63}6465static void etap_open_addr(unsigned char *addr, unsigned char *netmask,66void *arg)67{68etap_change(ADD_ADDR, addr, netmask, *((int *) arg));69}7071static void etap_close_addr(unsigned char *addr, unsigned char *netmask,72void *arg)73{74etap_change(DEL_ADDR, addr, netmask, *((int *) arg));75}7677struct etap_pre_exec_data {78int control_remote;79int control_me;80int data_me;81};8283static void etap_pre_exec(void *arg)84{85struct etap_pre_exec_data *data = arg;8687dup2(data->control_remote, 1);88close(data->data_me);89close(data->control_me);90}9192static int etap_tramp(char *dev, char *gate, int control_me,93int control_remote, int data_me, int data_remote)94{95struct etap_pre_exec_data pe_data;96int pid, err, n;97char version_buf[sizeof("nnnnn\0")];98char data_fd_buf[sizeof("nnnnnn\0")];99char gate_buf[sizeof("nnn.nnn.nnn.nnn\0")];100char *setup_args[] = { "uml_net", version_buf, "ethertap", dev,101data_fd_buf, gate_buf, NULL };102char *nosetup_args[] = { "uml_net", version_buf, "ethertap",103dev, data_fd_buf, NULL };104char **args, c;105106sprintf(data_fd_buf, "%d", data_remote);107sprintf(version_buf, "%d", UML_NET_VERSION);108if (gate != NULL) {109strcpy(gate_buf, gate);110args = setup_args;111}112else args = nosetup_args;113114err = 0;115pe_data.control_remote = control_remote;116pe_data.control_me = control_me;117pe_data.data_me = data_me;118pid = run_helper(etap_pre_exec, &pe_data, args);119120if (pid < 0)121err = pid;122close(data_remote);123close(control_remote);124CATCH_EINTR(n = read(control_me, &c, sizeof(c)));125if (n != sizeof(c)) {126err = -errno;127printk(UM_KERN_ERR "etap_tramp : read of status failed, "128"err = %d\n", -err);129return err;130}131if (c != 1) {132printk(UM_KERN_ERR "etap_tramp : uml_net failed\n");133err = helper_wait(pid);134}135return err;136}137138static int etap_open(void *data)139{140struct ethertap_data *pri = data;141char *output;142int data_fds[2], control_fds[2], err, output_len;143144err = tap_open_common(pri->dev, pri->gate_addr);145if (err)146return err;147148err = socketpair(AF_UNIX, SOCK_DGRAM, 0, data_fds);149if (err) {150err = -errno;151printk(UM_KERN_ERR "etap_open - data socketpair failed - "152"err = %d\n", errno);153return err;154}155156err = socketpair(AF_UNIX, SOCK_STREAM, 0, control_fds);157if (err) {158err = -errno;159printk(UM_KERN_ERR "etap_open - control socketpair failed - "160"err = %d\n", errno);161goto out_close_data;162}163164err = etap_tramp(pri->dev_name, pri->gate_addr, control_fds[0],165control_fds[1], data_fds[0], data_fds[1]);166output_len = UM_KERN_PAGE_SIZE;167output = uml_kmalloc(output_len, UM_GFP_KERNEL);168read_output(control_fds[0], output, output_len);169170if (output == NULL)171printk(UM_KERN_ERR "etap_open : failed to allocate output "172"buffer\n");173else {174printk("%s", output);175kfree(output);176}177178if (err < 0) {179printk(UM_KERN_ERR "etap_tramp failed - err = %d\n", -err);180goto out_close_control;181}182183pri->data_fd = data_fds[0];184pri->control_fd = control_fds[0];185iter_addresses(pri->dev, etap_open_addr, &pri->control_fd);186return data_fds[0];187188out_close_control:189close(control_fds[0]);190close(control_fds[1]);191out_close_data:192close(data_fds[0]);193close(data_fds[1]);194return err;195}196197static void etap_close(int fd, void *data)198{199struct ethertap_data *pri = data;200201iter_addresses(pri->dev, etap_close_addr, &pri->control_fd);202close(fd);203204if (shutdown(pri->data_fd, SHUT_RDWR) < 0)205printk(UM_KERN_ERR "etap_close - shutdown data socket failed, "206"errno = %d\n", errno);207208if (shutdown(pri->control_fd, SHUT_RDWR) < 0)209printk(UM_KERN_ERR "etap_close - shutdown control socket "210"failed, errno = %d\n", errno);211212close(pri->data_fd);213pri->data_fd = -1;214close(pri->control_fd);215pri->control_fd = -1;216}217218static void etap_add_addr(unsigned char *addr, unsigned char *netmask,219void *data)220{221struct ethertap_data *pri = data;222223tap_check_ips(pri->gate_addr, addr);224if (pri->control_fd == -1)225return;226etap_open_addr(addr, netmask, &pri->control_fd);227}228229static void etap_del_addr(unsigned char *addr, unsigned char *netmask,230void *data)231{232struct ethertap_data *pri = data;233234if (pri->control_fd == -1)235return;236237etap_close_addr(addr, netmask, &pri->control_fd);238}239240const struct net_user_info ethertap_user_info = {241.init = etap_user_init,242.open = etap_open,243.close = etap_close,244.remove = NULL,245.add_address = etap_add_addr,246.delete_address = etap_del_addr,247.mtu = ETH_MAX_PACKET,248.max_packet = ETH_MAX_PACKET + ETH_HEADER_ETHERTAP,249};250251252