Commit e1c5a2b33409b9795fa58bf389eac855981330a5

Authored by aliguori
1 parent 4dda4063

Redirect slirp traffic to/from qemu character device (Gleb Natapov)

Signed-off-by: Gleb Natapov <gleb@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>



git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6240 c046a42c-6fe2-441c-8c8c-71466251a162
slirp/libslirp.h
... ... @@ -20,13 +20,16 @@ void slirp_output(const uint8_t *pkt, int pkt_len);
20 20  
21 21 int slirp_redir(int is_udp, int host_port,
22 22 struct in_addr guest_addr, int guest_port);
23   -int slirp_add_exec(int do_pty, const char *args, int addr_low_byte,
  23 +int slirp_add_exec(int do_pty, const void *args, int addr_low_byte,
24 24 int guest_port);
25 25  
26 26 extern const char *tftp_prefix;
27 27 extern char slirp_hostname[33];
28 28  
29 29 void slirp_stats(void);
  30 +void slirp_socket_recv(int addr_low_byte, int guest_port, const uint8_t *buf,
  31 + int size);
  32 +size_t slirp_socket_can_recv(int addr_low_byte, int guest_port);
30 33  
31 34 #ifdef __cplusplus
32 35 }
... ...
slirp/main.h
... ... @@ -51,3 +51,4 @@ extern uint8_t client_ethaddr[6];
51 51 #endif
52 52  
53 53 void if_encap(const uint8_t *ip_data, int ip_data_len);
  54 +ssize_t slirp_send(struct socket *so, const void *buf, size_t len, int flags);
... ...
slirp/misc.c
... ... @@ -169,7 +169,7 @@ add_exec(ex_ptr, do_pty, exec, addr, port)
169 169 (*ex_ptr)->ex_fport = port;
170 170 (*ex_ptr)->ex_addr = addr;
171 171 (*ex_ptr)->ex_pty = do_pty;
172   - (*ex_ptr)->ex_exec = strdup(exec);
  172 + (*ex_ptr)->ex_exec = (do_pty == 3) ? exec : strdup(exec);
173 173 (*ex_ptr)->ex_next = tmp_ptr;
174 174 return 0;
175 175 }
... ...
slirp/sbuf.c
... ... @@ -108,7 +108,7 @@ sbappend(so, m)
108 108 * ottherwise it'll arrive out of order, and hence corrupt
109 109 */
110 110 if (!so->so_rcv.sb_cc)
111   - ret = send(so->s, m->m_data, m->m_len, 0);
  111 + ret = slirp_send(so, m->m_data, m->m_len, 0);
112 112  
113 113 if (ret <= 0) {
114 114 /*
... ...
slirp/slirp.c
... ... @@ -21,6 +21,7 @@
21 21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 22 * THE SOFTWARE.
23 23 */
  24 +#include "qemu-common.h"
24 25 #include "slirp.h"
25 26  
26 27 /* host address */
... ... @@ -736,9 +737,69 @@ int slirp_redir(int is_udp, int host_port,
736 737 return 0;
737 738 }
738 739  
739   -int slirp_add_exec(int do_pty, const char *args, int addr_low_byte,
  740 +int slirp_add_exec(int do_pty, const void *args, int addr_low_byte,
740 741 int guest_port)
741 742 {
742 743 return add_exec(&exec_list, do_pty, (char *)args,
743 744 addr_low_byte, htons(guest_port));
744 745 }
  746 +
  747 +ssize_t slirp_send(struct socket *so, const void *buf, size_t len, int flags)
  748 +{
  749 + if (so->s == -1 && so->extra) {
  750 + qemu_chr_write(so->extra, buf, len);
  751 + return len;
  752 + }
  753 +
  754 + return send(so->s, buf, len, flags);
  755 +}
  756 +
  757 +static struct socket *slirp_find_ctl_socket(int addr_low_byte, int guest_port)
  758 +{
  759 + struct socket *so;
  760 +
  761 + for (so = tcb.so_next; so != &tcb; so = so->so_next) {
  762 + if ((so->so_faddr.s_addr & htonl(0xffffff00)) ==
  763 + special_addr.s_addr
  764 + && (ntohl(so->so_faddr.s_addr) & 0xff) ==
  765 + addr_low_byte
  766 + && htons(so->so_fport) == guest_port)
  767 + return so;
  768 + }
  769 +
  770 + return NULL;
  771 +}
  772 +
  773 +size_t slirp_socket_can_recv(int addr_low_byte, int guest_port)
  774 +{
  775 + struct iovec iov[2];
  776 + struct socket *so;
  777 +
  778 + if (!link_up)
  779 + return 0;
  780 +
  781 + so = slirp_find_ctl_socket(addr_low_byte, guest_port);
  782 +
  783 + if (!so || so->so_state & SS_NOFDREF)
  784 + return 0;
  785 +
  786 + if (!CONN_CANFRCV(so) || so->so_snd.sb_cc >= (so->so_snd.sb_datalen/2))
  787 + return 0;
  788 +
  789 + return sopreprbuf(so, iov, NULL);
  790 +}
  791 +
  792 +void slirp_socket_recv(int addr_low_byte, int guest_port, const uint8_t *buf,
  793 + int size)
  794 +{
  795 + int ret;
  796 + struct socket *so = slirp_find_ctl_socket(addr_low_byte, guest_port);
  797 +
  798 + if (!so)
  799 + return;
  800 +
  801 + ret = soreadbuf(so, buf, size);
  802 +
  803 + if (ret > 0)
  804 + tcp_output(sototcpcb(so));
  805 +}
... ...
slirp/socket.c
... ... @@ -5,13 +5,13 @@
5 5 * terms and conditions of the copyright.
6 6 */
7 7  
  8 +#include "qemu-common.h"
8 9 #define WANT_SYS_IOCTL_H
9 10 #include <slirp.h>
10 11 #include "ip_icmp.h"
11 12 #ifdef __sun__
12 13 #include <sys/filio.h>
13 14 #endif
14   -#include "qemu-common.h"
15 15  
16 16 static void sofcantrcvmore(struct socket *so);
17 17 static void sofcantsendmore(struct socket *so);
... ... @@ -91,31 +91,21 @@ sofree(so)
91 91 free(so);
92 92 }
93 93  
94   -/*
95   - * Read from so's socket into sb_snd, updating all relevant sbuf fields
96   - * NOTE: This will only be called if it is select()ed for reading, so
97   - * a read() of 0 (or less) means it's disconnected
98   - */
99   -int
100   -soread(so)
101   - struct socket *so;
  94 +size_t sopreprbuf(struct socket *so, struct iovec *iov, int *np)
102 95 {
103   - int n, nn, lss, total;
  96 + int n, lss, total;
104 97 struct sbuf *sb = &so->so_snd;
105 98 int len = sb->sb_datalen - sb->sb_cc;
106   - struct iovec iov[2];
107 99 int mss = so->so_tcpcb->t_maxseg;
108 100  
109   - DEBUG_CALL("soread");
  101 + DEBUG_CALL("sopreprbuf");
110 102 DEBUG_ARG("so = %lx", (long )so);
111 103  
112   - /*
113   - * No need to check if there's enough room to read.
114   - * soread wouldn't have been called if there weren't
115   - */
116   -
117 104 len = sb->sb_datalen - sb->sb_cc;
118 105  
  106 + if (len <= 0)
  107 + return 0;
  108 +
119 109 iov[0].iov_base = sb->sb_wptr;
120 110 iov[1].iov_base = NULL;
121 111 iov[1].iov_len = 0;
... ... @@ -156,6 +146,33 @@ soread(so)
156 146 n = 1;
157 147 }
158 148 }
  149 + if (np)
  150 + *np = n;
  151 +
  152 + return iov[0].iov_len + (n - 1) * iov[1].iov_len;
  153 +}
  154 +
  155 +/*
  156 + * Read from so's socket into sb_snd, updating all relevant sbuf fields
  157 + * NOTE: This will only be called if it is select()ed for reading, so
  158 + * a read() of 0 (or less) means it's disconnected
  159 + */
  160 +int
  161 +soread(so)
  162 + struct socket *so;
  163 +{
  164 + int n, nn;
  165 + struct sbuf *sb = &so->so_snd;
  166 + struct iovec iov[2];
  167 +
  168 + DEBUG_CALL("soread");
  169 + DEBUG_ARG("so = %lx", (long )so);
  170 +
  171 + /*
  172 + * No need to check if there's enough room to read.
  173 + * soread wouldn't have been called if there weren't
  174 + */
  175 + sopreprbuf(so, iov, &n);
159 176  
160 177 #ifdef HAVE_READV
161 178 nn = readv(so->s, (struct iovec *)iov, n);
... ... @@ -202,6 +219,48 @@ soread(so)
202 219 return nn;
203 220 }
204 221  
  222 +int soreadbuf(struct socket *so, const char *buf, int size)
  223 +{
  224 + int n, nn, copy = size;
  225 + struct sbuf *sb = &so->so_snd;
  226 + struct iovec iov[2];
  227 +
  228 + DEBUG_CALL("soreadbuf");
  229 + DEBUG_ARG("so = %lx", (long )so);
  230 +
  231 + /*
  232 + * No need to check if there's enough room to read.
  233 + * soread wouldn't have been called if there weren't
  234 + */
  235 + if (sopreprbuf(so, iov, &n) < size)
  236 + goto err;
  237 +
  238 + nn = MIN(iov[0].iov_len, copy);
  239 + memcpy(iov[0].iov_base, buf, nn);
  240 +
  241 + copy -= nn;
  242 + buf += nn;
  243 +
  244 + if (copy == 0)
  245 + goto done;
  246 +
  247 + memcpy(iov[1].iov_base, buf, copy);
  248 +
  249 +done:
  250 + /* Update fields */
  251 + sb->sb_cc += size;
  252 + sb->sb_wptr += size;
  253 + if (sb->sb_wptr >= (sb->sb_data + sb->sb_datalen))
  254 + sb->sb_wptr -= sb->sb_datalen;
  255 + return size;
  256 +err:
  257 +
  258 + sofcantrcvmore(so);
  259 + tcp_sockclosed(sototcpcb(so));
  260 + fprintf(stderr, "soreadbuf buffer to small");
  261 + return -1;
  262 +}
  263 +
205 264 /*
206 265 * Get urgent data
207 266 *
... ... @@ -255,7 +314,7 @@ sosendoob(so)
255 314  
256 315 if (sb->sb_rptr < sb->sb_wptr) {
257 316 /* We can send it directly */
258   - n = send(so->s, sb->sb_rptr, so->so_urgc, (MSG_OOB)); /* |MSG_DONTWAIT)); */
  317 + n = slirp_send(so, sb->sb_rptr, so->so_urgc, (MSG_OOB)); /* |MSG_DONTWAIT)); */
259 318 so->so_urgc -= n;
260 319  
261 320 DEBUG_MISC((dfd, " --- sent %d bytes urgent data, %d urgent bytes left\n", n, so->so_urgc));
... ... @@ -276,7 +335,7 @@ sosendoob(so)
276 335 so->so_urgc -= n;
277 336 len += n;
278 337 }
279   - n = send(so->s, buff, len, (MSG_OOB)); /* |MSG_DONTWAIT)); */
  338 + n = slirp_send(so, buff, len, (MSG_OOB)); /* |MSG_DONTWAIT)); */
280 339 #ifdef DEBUG
281 340 if (n != len)
282 341 DEBUG_ERROR((dfd, "Didn't send all data urgently XXXXX\n"));
... ... @@ -348,7 +407,7 @@ sowrite(so)
348 407  
349 408 DEBUG_MISC((dfd, " ... wrote nn = %d bytes\n", nn));
350 409 #else
351   - nn = send(so->s, iov[0].iov_base, iov[0].iov_len,0);
  410 + nn = slirp_send(so, iov[0].iov_base, iov[0].iov_len,0);
352 411 #endif
353 412 /* This should never happen, but people tell me it does *shrug* */
354 413 if (nn < 0 && (errno == EAGAIN || errno == EINTR))
... ... @@ -365,7 +424,7 @@ sowrite(so)
365 424 #ifndef HAVE_READV
366 425 if (n == 2 && nn == iov[0].iov_len) {
367 426 int ret;
368   - ret = send(so->s, iov[1].iov_base, iov[1].iov_len,0);
  427 + ret = slirp_send(so, iov[1].iov_base, iov[1].iov_len,0);
369 428 if (ret > 0)
370 429 nn += ret;
371 430 }
... ...
slirp/socket.h
... ... @@ -87,5 +87,7 @@ void soisfconnecting _P((register struct socket *));
87 87 void soisfconnected _P((register struct socket *));
88 88 void soisfdisconnected _P((struct socket *));
89 89 void sofwdrain _P((struct socket *));
  90 +size_t sopreprbuf(struct socket *so, struct iovec *iov, int *np);
  91 +int soreadbuf(struct socket *so, const char *buf, int size);
90 92  
91 93 #endif /* _SOCKET_H_ */
... ...
slirp/tcp_subr.c
... ... @@ -1281,6 +1281,11 @@ tcp_ctl(so)
1281 1281 for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
1282 1282 if (ex_ptr->ex_fport == so->so_fport &&
1283 1283 command == ex_ptr->ex_addr) {
  1284 + if (ex_ptr->ex_pty == 3) {
  1285 + so->s = -1;
  1286 + so->extra = ex_ptr->ex_exec;
  1287 + return 1;
  1288 + }
1284 1289 do_pty = ex_ptr->ex_pty;
1285 1290 goto do_exec;
1286 1291 }
... ...