2 * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and
3 * James Leu (jleu@mindspring.net).
4 * Copyright (C) 2001 by various other people who didn't put their name here.
5 * Licensed under the GPL.
12 #include <sys/errno.h>
13 #include <sys/socket.h>
18 #include "kern_util.h"
22 #include "um_malloc.h"
23 #include "kern_constants.h"
25 #define MAX_PACKET ETH_MAX_PACKET
27 static int etap_user_init(void *data
, void *dev
)
29 struct ethertap_data
*pri
= data
;
36 enum { ADD_ADDR
, DEL_ADDR
} what
;
37 unsigned char addr
[4];
38 unsigned char netmask
[4];
41 static void etap_change(int op
, unsigned char *addr
, unsigned char *netmask
,
44 struct addr_change change
;
49 memcpy(change
.addr
, addr
, sizeof(change
.addr
));
50 memcpy(change
.netmask
, netmask
, sizeof(change
.netmask
));
51 CATCH_EINTR(n
= write(fd
, &change
, sizeof(change
)));
52 if(n
!= sizeof(change
)){
53 printk("etap_change - request failed, err = %d\n", errno
);
57 output
= um_kmalloc(UM_KERN_PAGE_SIZE
);
59 printk("etap_change : Failed to allocate output buffer\n");
60 read_output(fd
, output
, UM_KERN_PAGE_SIZE
);
67 static void etap_open_addr(unsigned char *addr
, unsigned char *netmask
,
70 etap_change(ADD_ADDR
, addr
, netmask
, *((int *) arg
));
73 static void etap_close_addr(unsigned char *addr
, unsigned char *netmask
,
76 etap_change(DEL_ADDR
, addr
, netmask
, *((int *) arg
));
79 struct etap_pre_exec_data
{
85 static void etap_pre_exec(void *arg
)
87 struct etap_pre_exec_data
*data
= arg
;
89 dup2(data
->control_remote
, 1);
90 os_close_file(data
->data_me
);
91 os_close_file(data
->control_me
);
94 static int etap_tramp(char *dev
, char *gate
, int control_me
,
95 int control_remote
, int data_me
, int data_remote
)
97 struct etap_pre_exec_data pe_data
;
98 int pid
, status
, err
, n
;
99 char version_buf
[sizeof("nnnnn\0")];
100 char data_fd_buf
[sizeof("nnnnnn\0")];
101 char gate_buf
[sizeof("nnn.nnn.nnn.nnn\0")];
102 char *setup_args
[] = { "uml_net", version_buf
, "ethertap", dev
,
103 data_fd_buf
, gate_buf
, NULL
};
104 char *nosetup_args
[] = { "uml_net", version_buf
, "ethertap",
105 dev
, data_fd_buf
, NULL
};
108 sprintf(data_fd_buf
, "%d", data_remote
);
109 sprintf(version_buf
, "%d", UML_NET_VERSION
);
111 strcpy(gate_buf
, gate
);
114 else args
= nosetup_args
;
117 pe_data
.control_remote
= control_remote
;
118 pe_data
.control_me
= control_me
;
119 pe_data
.data_me
= data_me
;
120 pid
= run_helper(etap_pre_exec
, &pe_data
, args
, NULL
);
124 os_close_file(data_remote
);
125 os_close_file(control_remote
);
126 CATCH_EINTR(n
= read(control_me
, &c
, sizeof(c
)));
129 printk("etap_tramp : read of status failed, err = %d\n", -err
);
133 printk("etap_tramp : uml_net failed\n");
135 CATCH_EINTR(n
= waitpid(pid
, &status
, 0));
138 else if(!WIFEXITED(status
) || (WEXITSTATUS(status
) != 1))
139 printk("uml_net didn't exit with status 1\n");
144 static int etap_open(void *data
)
146 struct ethertap_data
*pri
= data
;
148 int data_fds
[2], control_fds
[2], err
, output_len
;
150 err
= tap_open_common(pri
->dev
, pri
->gate_addr
);
154 err
= os_pipe(data_fds
, 0, 0);
156 printk("data os_pipe failed - err = %d\n", -err
);
160 err
= os_pipe(control_fds
, 1, 0);
162 printk("control os_pipe failed - err = %d\n", -err
);
166 err
= etap_tramp(pri
->dev_name
, pri
->gate_addr
, control_fds
[0],
167 control_fds
[1], data_fds
[0], data_fds
[1]);
168 output_len
= UM_KERN_PAGE_SIZE
;
169 output
= um_kmalloc(output_len
);
170 read_output(control_fds
[0], output
, output_len
);
173 printk("etap_open : failed to allocate output buffer\n");
175 printk("%s", output
);
180 printk("etap_tramp failed - err = %d\n", -err
);
184 pri
->data_fd
= data_fds
[0];
185 pri
->control_fd
= control_fds
[0];
186 iter_addresses(pri
->dev
, etap_open_addr
, &pri
->control_fd
);
190 static void etap_close(int fd
, void *data
)
192 struct ethertap_data
*pri
= data
;
194 iter_addresses(pri
->dev
, etap_close_addr
, &pri
->control_fd
);
196 os_shutdown_socket(pri
->data_fd
, 1, 1);
197 os_close_file(pri
->data_fd
);
199 os_close_file(pri
->control_fd
);
200 pri
->control_fd
= -1;
203 static int etap_set_mtu(int mtu
, void *data
)
208 static void etap_add_addr(unsigned char *addr
, unsigned char *netmask
,
211 struct ethertap_data
*pri
= data
;
213 tap_check_ips(pri
->gate_addr
, addr
);
214 if(pri
->control_fd
== -1)
216 etap_open_addr(addr
, netmask
, &pri
->control_fd
);
219 static void etap_del_addr(unsigned char *addr
, unsigned char *netmask
,
222 struct ethertap_data
*pri
= data
;
224 if(pri
->control_fd
== -1)
226 etap_close_addr(addr
, netmask
, &pri
->control_fd
);
229 const struct net_user_info ethertap_user_info
= {
230 .init
= etap_user_init
,
234 .set_mtu
= etap_set_mtu
,
235 .add_address
= etap_add_addr
,
236 .delete_address
= etap_del_addr
,
237 .max_packet
= MAX_PACKET
- ETH_HEADER_ETHERTAP