Linux-2.6.12-rc2
[pandora-kernel.git] / arch / um / drivers / slirp_user.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <unistd.h>
4 #include <stddef.h>
5 #include <sched.h>
6 #include <string.h>
7 #include <errno.h>
8 #include <sys/wait.h>
9 #include <sys/signal.h>
10 #include "user_util.h"
11 #include "kern_util.h"
12 #include "user.h"
13 #include "net_user.h"
14 #include "slirp.h"
15 #include "slip_proto.h"
16 #include "helper.h"
17 #include "os.h"
18
19 void slirp_user_init(void *data, void *dev)
20 {
21         struct slirp_data *pri = data;
22
23         pri->dev = dev;
24 }
25
26 struct slirp_pre_exec_data {
27         int stdin;
28         int stdout;
29 };
30
31 static void slirp_pre_exec(void *arg)
32 {
33         struct slirp_pre_exec_data *data = arg;
34
35         if(data->stdin != -1) dup2(data->stdin, 0);
36         if(data->stdout != -1) dup2(data->stdout, 1);
37 }
38
39 static int slirp_tramp(char **argv, int fd)
40 {
41         struct slirp_pre_exec_data pe_data;
42         int pid;
43
44         pe_data.stdin = fd;
45         pe_data.stdout = fd;
46         pid = run_helper(slirp_pre_exec, &pe_data, argv, NULL);
47
48         return(pid);
49 }
50
51 /* XXX This is just a trivial wrapper around os_pipe */
52 static int slirp_datachan(int *mfd, int *sfd)
53 {
54         int fds[2], err;
55
56         err = os_pipe(fds, 1, 1);
57         if(err < 0){
58                 printk("slirp_datachan: Failed to open pipe, err = %d\n", -err);
59                 return(err);
60         }
61
62         *mfd = fds[0];
63         *sfd = fds[1];
64         return(0);
65 }
66
67 static int slirp_open(void *data)
68 {
69         struct slirp_data *pri = data;
70         int sfd, mfd, pid, err;
71
72         err = slirp_datachan(&mfd, &sfd);
73         if(err)
74                 return(err);
75
76         pid = slirp_tramp(pri->argw.argv, sfd);
77
78         if(pid < 0){
79                 printk("slirp_tramp failed - errno = %d\n", -pid);
80                 os_close_file(sfd);     
81                 os_close_file(mfd);     
82                 return(pid);
83         }
84
85         pri->slave = sfd;
86         pri->pos = 0;
87         pri->esc = 0;
88
89         pri->pid = pid;
90
91         return(mfd);
92 }
93
94 static void slirp_close(int fd, void *data)
95 {
96         struct slirp_data *pri = data;
97         int status,err;
98
99         os_close_file(fd);
100         os_close_file(pri->slave);
101
102         pri->slave = -1;
103
104         if(pri->pid<1) {
105                 printk("slirp_close: no child process to shut down\n");
106                 return;
107         }
108
109 #if 0
110         if(kill(pri->pid, SIGHUP)<0) {
111                 printk("slirp_close: sending hangup to %d failed (%d)\n",
112                         pri->pid, errno);
113         }
114 #endif
115
116         CATCH_EINTR(err = waitpid(pri->pid, &status, WNOHANG));
117         if(err < 0) {
118                 printk("slirp_close: waitpid returned %d\n", errno);
119                 return;
120         }
121
122         if(err == 0) {
123                 printk("slirp_close: process %d has not exited\n");
124                 return;
125         }
126
127         pri->pid = -1;
128 }
129
130 int slirp_user_read(int fd, void *buf, int len, struct slirp_data *pri)
131 {
132         int i, n, size, start;
133
134         if(pri->more>0) {
135                 i = 0;
136                 while(i < pri->more) {
137                         size = slip_unesc(pri->ibuf[i++],
138                                         pri->ibuf,&pri->pos,&pri->esc);
139                         if(size){
140                                 memcpy(buf, pri->ibuf, size);
141                                 memmove(pri->ibuf, &pri->ibuf[i], pri->more-i);
142                                 pri->more=pri->more-i; 
143                                 return(size);
144                         }
145                 }
146                 pri->more=0;
147         }
148
149         n = net_read(fd, &pri->ibuf[pri->pos], sizeof(pri->ibuf) - pri->pos);
150         if(n <= 0) return(n);
151
152         start = pri->pos;
153         for(i = 0; i < n; i++){
154                 size = slip_unesc(pri->ibuf[start + i],
155                                 pri->ibuf,&pri->pos,&pri->esc);
156                 if(size){
157                         memcpy(buf, pri->ibuf, size);
158                         memmove(pri->ibuf, &pri->ibuf[start+i+1], n-(i+1));
159                         pri->more=n-(i+1); 
160                         return(size);
161                 }
162         }
163         return(0);
164 }
165
166 int slirp_user_write(int fd, void *buf, int len, struct slirp_data *pri)
167 {
168         int actual, n;
169
170         actual = slip_esc(buf, pri->obuf, len);
171         n = net_write(fd, pri->obuf, actual);
172         if(n < 0) return(n);
173         else return(len);
174 }
175
176 static int slirp_set_mtu(int mtu, void *data)
177 {
178         return(mtu);
179 }
180
181 struct net_user_info slirp_user_info = {
182         .init           = slirp_user_init,
183         .open           = slirp_open,
184         .close          = slirp_close,
185         .remove         = NULL,
186         .set_mtu        = slirp_set_mtu,
187         .add_address    = NULL,
188         .delete_address = NULL,
189         .max_packet     = BUF_SIZE
190 };
191
192 /*
193  * Overrides for Emacs so that we follow Linus's tabbing style.
194  * Emacs will notice this stuff at the end of the file and automatically
195  * adjust the settings for this buffer only.  This must remain at the end
196  * of the file.
197  * ---------------------------------------------------------------------------
198  * Local variables:
199  * c-file-style: "linux"
200  * End:
201  */