VirtualBox

source: vbox/trunk/src/VBox/Devices/Network/slirp/socket.c@ 15149

Last change on this file since 15149 was 15149, checked in by vboxsync, 16 years ago

slirp:icmp: set of hacks over Win ICMP Api introduced

  1. guest address hack
  2. ICMP seq and identifier (see xTracker #2752 for details)
  • Property svn:eol-style set to native
File size: 26.9 KB
Line 
1/*
2 * Copyright (c) 1995 Danny Gasparovski.
3 *
4 * Please read the file COPYRIGHT for the
5 * terms and conditions of the copyright.
6 */
7
8#define WANT_SYS_IOCTL_H
9#include <slirp.h>
10#include "ip_icmp.h"
11#include "main.h"
12#ifdef __sun__
13#include <sys/filio.h>
14#endif
15#if defined(VBOX_WITH_SLIRP_ICMP) && defined (RT_OS_WINDOWS)
16#include <iphlpapi.h>
17#include <icmpapi.h>
18#endif
19
20#ifdef VBOX_WITH_SLIRP_ICMP
21static void send_icmp_to_guest(PNATState, char *, size_t, struct socket *, const struct sockaddr_in *);
22static void sorecvfrom_icmp_win(PNATState, struct socket *);
23#endif
24static void sorecvfrom_icmp_unix(PNATState, struct socket *);
25
26void
27so_init()
28{
29}
30
31
32struct socket *
33solookup(struct socket *head, struct in_addr laddr,
34 u_int lport, struct in_addr faddr, u_int fport)
35{
36 struct socket *so;
37
38 for (so = head->so_next; so != head; so = so->so_next)
39 {
40 if ( so->so_lport == lport
41 && so->so_laddr.s_addr == laddr.s_addr
42 && so->so_faddr.s_addr == faddr.s_addr
43 && so->so_fport == fport)
44 return so;
45 }
46
47 return (struct socket *)NULL;
48}
49
50/*
51 * Create a new socket, initialise the fields
52 * It is the responsibility of the caller to
53 * insque() it into the correct linked-list
54 */
55struct socket *
56socreate()
57{
58 struct socket *so;
59
60 so = (struct socket *)malloc(sizeof(struct socket));
61 if(so)
62 {
63 memset(so, 0, sizeof(struct socket));
64 so->so_state = SS_NOFDREF;
65 so->s = -1;
66 }
67 return so;
68}
69
70/*
71 * remque and free a socket, clobber cache
72 */
73void
74sofree(PNATState pData, struct socket *so)
75{
76 if (so == tcp_last_so)
77 tcp_last_so = &tcb;
78 else if (so == udp_last_so)
79 udp_last_so = &udb;
80
81 m_free(pData, so->so_m);
82
83 if(so->so_next && so->so_prev)
84 remque(pData, so); /* crashes if so is not in a queue */
85
86 free(so);
87}
88
89/*
90 * Read from so's socket into sb_snd, updating all relevant sbuf fields
91 * NOTE: This will only be called if it is select()ed for reading, so
92 * a read() of 0 (or less) means it's disconnected
93 */
94int
95soread(PNATState pData, struct socket *so)
96{
97 int n, nn, lss, total;
98 struct sbuf *sb = &so->so_snd;
99 int len = sb->sb_datalen - sb->sb_cc;
100 struct iovec iov[2];
101 int mss = so->so_tcpcb->t_maxseg;
102
103 DEBUG_CALL("soread");
104 DEBUG_ARG("so = %lx", (long )so);
105
106 /*
107 * No need to check if there's enough room to read.
108 * soread wouldn't have been called if there weren't
109 */
110
111 len = sb->sb_datalen - sb->sb_cc;
112
113 iov[0].iov_base = sb->sb_wptr;
114 iov[1].iov_base = 0;
115 iov[1].iov_len = 0;
116 if (sb->sb_wptr < sb->sb_rptr)
117 {
118 iov[0].iov_len = sb->sb_rptr - sb->sb_wptr;
119 /* Should never succeed, but... */
120 if (iov[0].iov_len > len)
121 iov[0].iov_len = len;
122 if (iov[0].iov_len > mss)
123 iov[0].iov_len -= iov[0].iov_len%mss;
124 n = 1;
125 }
126 else
127 {
128 iov[0].iov_len = (sb->sb_data + sb->sb_datalen) - sb->sb_wptr;
129 /* Should never succeed, but... */
130 if (iov[0].iov_len > len) iov[0].iov_len = len;
131 len -= iov[0].iov_len;
132 if (len)
133 {
134 iov[1].iov_base = sb->sb_data;
135 iov[1].iov_len = sb->sb_rptr - sb->sb_data;
136 if(iov[1].iov_len > len)
137 iov[1].iov_len = len;
138 total = iov[0].iov_len + iov[1].iov_len;
139 if (total > mss)
140 {
141 lss = total % mss;
142 if (iov[1].iov_len > lss)
143 {
144 iov[1].iov_len -= lss;
145 n = 2;
146 }
147 else
148 {
149 lss -= iov[1].iov_len;
150 iov[0].iov_len -= lss;
151 n = 1;
152 }
153 }
154 else
155 n = 2;
156 }
157 else
158 {
159 if (iov[0].iov_len > mss)
160 iov[0].iov_len -= iov[0].iov_len%mss;
161 n = 1;
162 }
163 }
164
165#ifdef HAVE_READV
166 nn = readv(so->s, (struct iovec *)iov, n);
167 DEBUG_MISC((dfd, " ... read nn = %d bytes\n", nn));
168#else
169 nn = recv(so->s, iov[0].iov_base, iov[0].iov_len,0);
170#endif
171 if (nn <= 0)
172 {
173#if defined(VBOX_WITH_SIMPLIFIED_SLIRP_SYNC) && defined(RT_OS_WINDOWS)
174 /*
175 * Special case for WSAEnumNetworkEvents: If we receive 0 bytes that
176 * _could_ mean that the connection is closed. But we will receive an
177 * FD_CLOSE event later if the connection was _really_ closed. With
178 * www.youtube.com I see this very often. Closing the socket too early
179 * would be dangerous.
180 */
181 if (nn == 0)
182 return 0;
183#endif
184 if (nn < 0 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK))
185 return 0;
186 else
187 {
188 /* nn == 0 means peer has performed an orderly shutdown */
189 DEBUG_MISC((dfd, " --- soread() disconnected, nn = %d, errno = %d-%s\n",
190 nn, errno,strerror(errno)));
191 sofcantrcvmore(so);
192 tcp_sockclosed(pData, sototcpcb(so));
193 return -1;
194 }
195 }
196
197#ifndef HAVE_READV
198 /*
199 * If there was no error, try and read the second time round
200 * We read again if n = 2 (ie, there's another part of the buffer)
201 * and we read as much as we could in the first read
202 * We don't test for <= 0 this time, because there legitimately
203 * might not be any more data (since the socket is non-blocking),
204 * a close will be detected on next iteration.
205 * A return of -1 wont (shouldn't) happen, since it didn't happen above
206 */
207 if (n == 2 && nn == iov[0].iov_len)
208 {
209 int ret;
210 ret = recv(so->s, iov[1].iov_base, iov[1].iov_len,0);
211 if (ret > 0)
212 nn += ret;
213 }
214
215 DEBUG_MISC((dfd, " ... read nn = %d bytes\n", nn));
216#endif
217
218 /* Update fields */
219 sb->sb_cc += nn;
220 sb->sb_wptr += nn;
221 if (sb->sb_wptr >= (sb->sb_data + sb->sb_datalen))
222 sb->sb_wptr -= sb->sb_datalen;
223 return nn;
224}
225
226/*
227 * Get urgent data
228 *
229 * When the socket is created, we set it SO_OOBINLINE,
230 * so when OOB data arrives, we soread() it and everything
231 * in the send buffer is sent as urgent data
232 */
233void
234sorecvoob(PNATState pData, struct socket *so)
235{
236 struct tcpcb *tp = sototcpcb(so);
237
238 DEBUG_CALL("sorecvoob");
239 DEBUG_ARG("so = %lx", (long)so);
240
241 /*
242 * We take a guess at how much urgent data has arrived.
243 * In most situations, when urgent data arrives, the next
244 * read() should get all the urgent data. This guess will
245 * be wrong however if more data arrives just after the
246 * urgent data, or the read() doesn't return all the
247 * urgent data.
248 */
249 soread(pData, so);
250 tp->snd_up = tp->snd_una + so->so_snd.sb_cc;
251 tp->t_force = 1;
252 tcp_output(pData, tp);
253 tp->t_force = 0;
254}
255
256/*
257 * Send urgent data
258 * There's a lot duplicated code here, but...
259 */
260int
261sosendoob(struct socket *so)
262{
263 struct sbuf *sb = &so->so_rcv;
264 char buff[2048]; /* XXX Shouldn't be sending more oob data than this */
265
266 int n, len;
267
268 DEBUG_CALL("sosendoob");
269 DEBUG_ARG("so = %lx", (long)so);
270 DEBUG_ARG("sb->sb_cc = %d", sb->sb_cc);
271
272 if (so->so_urgc > sizeof(buff))
273 so->so_urgc = sizeof(buff); /* XXX */
274
275 if (sb->sb_rptr < sb->sb_wptr)
276 {
277 /* We can send it directly */
278 n = send(so->s, sb->sb_rptr, so->so_urgc, (MSG_OOB)); /* |MSG_DONTWAIT)); */
279 so->so_urgc -= n;
280
281 DEBUG_MISC((dfd, " --- sent %d bytes urgent data, %d urgent bytes left\n",
282 n, so->so_urgc));
283 }
284 else
285 {
286 /*
287 * Since there's no sendv or sendtov like writev,
288 * we must copy all data to a linear buffer then
289 * send it all
290 */
291 len = (sb->sb_data + sb->sb_datalen) - sb->sb_rptr;
292 if (len > so->so_urgc) len = so->so_urgc;
293 memcpy(buff, sb->sb_rptr, len);
294 so->so_urgc -= len;
295 if (so->so_urgc)
296 {
297 n = sb->sb_wptr - sb->sb_data;
298 if (n > so->so_urgc)
299 n = so->so_urgc;
300 memcpy(buff + len, sb->sb_data, n);
301 so->so_urgc -= n;
302 len += n;
303 }
304 n = send(so->s, buff, len, (MSG_OOB)); /* |MSG_DONTWAIT)); */
305#ifdef DEBUG
306 if (n != len)
307 DEBUG_ERROR((dfd, "Didn't send all data urgently XXXXX\n"));
308#endif
309 DEBUG_MISC((dfd, " ---2 sent %d bytes urgent data, %d urgent bytes left\n",
310 n, so->so_urgc));
311 }
312
313 sb->sb_cc -= n;
314 sb->sb_rptr += n;
315 if (sb->sb_rptr >= (sb->sb_data + sb->sb_datalen))
316 sb->sb_rptr -= sb->sb_datalen;
317
318 return n;
319}
320
321/*
322 * Write data from so_rcv to so's socket,
323 * updating all sbuf field as necessary
324 */
325int
326sowrite(PNATState pData, struct socket *so)
327{
328 int n,nn;
329 struct sbuf *sb = &so->so_rcv;
330 int len = sb->sb_cc;
331 struct iovec iov[2];
332
333 DEBUG_CALL("sowrite");
334 DEBUG_ARG("so = %lx", (long)so);
335
336 if (so->so_urgc)
337 {
338 sosendoob(so);
339 if (sb->sb_cc == 0)
340 return 0;
341 }
342
343 /*
344 * No need to check if there's something to write,
345 * sowrite wouldn't have been called otherwise
346 */
347
348 len = sb->sb_cc;
349
350 iov[0].iov_base = sb->sb_rptr;
351 iov[1].iov_base = 0;
352 iov[1].iov_len = 0;
353 if (sb->sb_rptr < sb->sb_wptr)
354 {
355 iov[0].iov_len = sb->sb_wptr - sb->sb_rptr;
356 /* Should never succeed, but... */
357 if (iov[0].iov_len > len) iov[0].iov_len = len;
358 n = 1;
359 }
360 else
361 {
362 iov[0].iov_len = (sb->sb_data + sb->sb_datalen) - sb->sb_rptr;
363 if (iov[0].iov_len > len) iov[0].iov_len = len;
364 len -= iov[0].iov_len;
365 if (len)
366 {
367 iov[1].iov_base = sb->sb_data;
368 iov[1].iov_len = sb->sb_wptr - sb->sb_data;
369 if (iov[1].iov_len > len)
370 iov[1].iov_len = len;
371 n = 2;
372 }
373 else
374 n = 1;
375 }
376 /* Check if there's urgent data to send, and if so, send it */
377#ifdef HAVE_READV
378 nn = writev(so->s, (const struct iovec *)iov, n);
379 DEBUG_MISC((dfd, " ... wrote nn = %d bytes\n", nn));
380#else
381 nn = send(so->s, iov[0].iov_base, iov[0].iov_len, 0);
382#endif
383 /* This should never happen, but people tell me it does *shrug* */
384 if (nn < 0 && (errno == EAGAIN || errno == EINTR || errno == EWOULDBLOCK))
385 return 0;
386
387 if (nn < 0 || (nn == 0 && iov[0].iov_len > 0))
388 {
389 DEBUG_MISC((dfd, " --- sowrite disconnected, so->so_state = %x, errno = %d\n",
390 so->so_state, errno));
391 sofcantsendmore(so);
392 tcp_sockclosed(pData, sototcpcb(so));
393 return -1;
394 }
395
396#ifndef HAVE_READV
397 if (n == 2 && nn == iov[0].iov_len)
398 {
399 int ret;
400 ret = send(so->s, iov[1].iov_base, iov[1].iov_len,0);
401 if (ret > 0)
402 nn += ret;
403 }
404 DEBUG_MISC((dfd, " ... wrote nn = %d bytes\n", nn));
405#endif
406
407 /* Update sbuf */
408 sb->sb_cc -= nn;
409 sb->sb_rptr += nn;
410 if (sb->sb_rptr >= (sb->sb_data + sb->sb_datalen))
411 sb->sb_rptr -= sb->sb_datalen;
412
413 /*
414 * If in DRAIN mode, and there's no more data, set
415 * it CANTSENDMORE
416 */
417 if ((so->so_state & SS_FWDRAIN) && sb->sb_cc == 0)
418 sofcantsendmore(so);
419
420 return nn;
421}
422
423/*
424 * recvfrom() a UDP socket
425 */
426void
427sorecvfrom(PNATState pData, struct socket *so)
428{
429 struct sockaddr_in addr;
430 socklen_t addrlen = sizeof(struct sockaddr_in);
431
432 DEBUG_CALL("sorecvfrom");
433 DEBUG_ARG("so = %lx", (long)so);
434
435 if (so->so_type == IPPROTO_ICMP) { /* This is a "ping" reply */
436#if !defined(VBOX_WITH_SLIRP_ICMP) || (defined(VBOX_WITH_SLIRP_ICMP) && !defined(RT_OS_WINDOWS))
437 sorecvfrom_icmp_unix(pData, so);
438#endif
439#if defined(VBOX_WITH_SLIRP_ICMP) && defined(RT_OS_WINDOWS)
440 sorecvfrom_icmp_win(pData, so);
441#endif
442 udp_detach(pData, so);
443 } else { /* A "normal" UDP packet */
444 struct mbuf *m;
445 int len, n;
446
447 if (!(m = m_get(pData)))
448 return;
449 m->m_data += if_maxlinkhdr;
450
451 /*
452 * XXX Shouldn't FIONREAD packets destined for port 53,
453 * but I don't know the max packet size for DNS lookups
454 */
455 len = M_FREEROOM(m);
456 /* if (so->so_fport != htons(53)) */
457 {
458 ioctlsocket(so->s, FIONREAD, &n);
459
460 if (n > len)
461 {
462 n = (m->m_data - m->m_dat) + m->m_len + n + 1;
463 m_inc(m, n);
464 len = M_FREEROOM(m);
465 }
466 }
467
468 m->m_len = recvfrom(so->s, m->m_data, len, 0,
469 (struct sockaddr *)&addr, &addrlen);
470 DEBUG_MISC((dfd, " did recvfrom %d, errno = %d-%s\n",
471 m->m_len, errno,strerror(errno)));
472 if(m->m_len < 0)
473 {
474 u_char code=ICMP_UNREACH_PORT;
475
476 if (errno == EHOSTUNREACH)
477 code=ICMP_UNREACH_HOST;
478 else if(errno == ENETUNREACH)
479 code=ICMP_UNREACH_NET;
480
481 DEBUG_MISC((dfd," rx error, tx icmp ICMP_UNREACH:%i\n", code));
482 icmp_error(pData, so->so_m, ICMP_UNREACH,code, 0,strerror(errno));
483 m_free(pData, m);
484 }
485 else
486 {
487 /*
488 * Hack: domain name lookup will be used the most for UDP,
489 * and since they'll only be used once there's no need
490 * for the 4 minute (or whatever) timeout... So we time them
491 * out much quicker (10 seconds for now...)
492 */
493 if (so->so_expire)
494 {
495 if (so->so_fport == htons(53))
496 so->so_expire = curtime + SO_EXPIREFAST;
497 else
498 so->so_expire = curtime + SO_EXPIRE;
499 }
500
501#if 0
502 if (m->m_len == len)
503 {
504 m_inc(m, MINCSIZE);
505 m->m_len = 0;
506 }
507#endif
508
509 /*
510 * If this packet was destined for CTL_ADDR,
511 * make it look like that's where it came from, done by udp_output
512 */
513 udp_output(pData, so, m, &addr);
514 } /* rx error */
515 } /* if ping packet */
516}
517
518/*
519 * sendto() a socket
520 */
521int
522sosendto(PNATState pData, struct socket *so, struct mbuf *m)
523{
524 int ret;
525 struct sockaddr_in addr;
526#if 0
527 struct sockaddr_in host_addr;
528#endif
529
530 DEBUG_CALL("sosendto");
531 DEBUG_ARG("so = %lx", (long)so);
532 DEBUG_ARG("m = %lx", (long)m);
533
534 addr.sin_family = AF_INET;
535 if ((so->so_faddr.s_addr & htonl(pData->netmask)) == special_addr.s_addr)
536 {
537 /* It's an alias */
538 uint32_t last_byte = ntohl(so->so_faddr.s_addr) & ~pData->netmask;
539 switch(last_byte)
540 {
541#if 0
542 /* handle this case at 'default:' */
543 case CTL_BROADCAST:
544 addr.sin_addr.s_addr = INADDR_BROADCAST;
545 /* Send the packet to host to fully emulate broadcast */
546 /** @todo r=klaus: on Linux host this causes the host to receive
547 * the packet twice for some reason. And I cannot find any place
548 * in the man pages which states that sending a broadcast does not
549 * reach the host itself. */
550 host_addr.sin_family = AF_INET;
551 host_addr.sin_port = so->so_fport;
552 host_addr.sin_addr = our_addr;
553 sendto(so->s, m->m_data, m->m_len, 0,
554 (struct sockaddr *)&host_addr, sizeof (struct sockaddr));
555 break;
556#endif
557 case CTL_DNS:
558 if (!get_dns_addr(pData, &dns_addr))
559 addr.sin_addr = dns_addr;
560 else
561 addr.sin_addr = loopback_addr;
562 break;
563 case CTL_ALIAS:
564 default:
565 if (last_byte == ~pData->netmask)
566 addr.sin_addr.s_addr = INADDR_BROADCAST;
567 else
568 addr.sin_addr = loopback_addr;
569 break;
570 }
571 }
572 else
573 addr.sin_addr = so->so_faddr;
574 addr.sin_port = so->so_fport;
575
576 DEBUG_MISC((dfd, " sendto()ing, addr.sin_port=%d, addr.sin_addr.s_addr=%.16s\n",
577 ntohs(addr.sin_port), inet_ntoa(addr.sin_addr)));
578
579 /* Don't care what port we get */
580 ret = sendto(so->s, m->m_data, m->m_len, 0,
581 (struct sockaddr *)&addr, sizeof (struct sockaddr));
582 if (ret < 0)
583 return -1;
584
585 /*
586 * Kill the socket if there's no reply in 4 minutes,
587 * but only if it's an expirable socket
588 */
589 if (so->so_expire)
590 so->so_expire = curtime + SO_EXPIRE;
591 so->so_state = SS_ISFCONNECTED; /* So that it gets select()ed */
592 return 0;
593}
594
595/*
596 * XXX This should really be tcp_listen
597 */
598struct socket *
599solisten(PNATState pData, u_int port, u_int32_t laddr, u_int lport, int flags)
600{
601 struct sockaddr_in addr;
602 struct socket *so;
603 socklen_t addrlen = sizeof(addr);
604 int s, opt = 1;
605
606 DEBUG_CALL("solisten");
607 DEBUG_ARG("port = %d", port);
608 DEBUG_ARG("laddr = %x", laddr);
609 DEBUG_ARG("lport = %d", lport);
610 DEBUG_ARG("flags = %x", flags);
611
612 if ((so = socreate()) == NULL)
613 {
614 /* free(so); Not sofree() ??? free(NULL) == NOP */
615 return NULL;
616 }
617
618 /* Don't tcp_attach... we don't need so_snd nor so_rcv */
619 if ((so->so_tcpcb = tcp_newtcpcb(pData, so)) == NULL)
620 {
621 free(so);
622 return NULL;
623 }
624 insque(pData, so,&tcb);
625
626 /*
627 * SS_FACCEPTONCE sockets must time out.
628 */
629 if (flags & SS_FACCEPTONCE)
630 so->so_tcpcb->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT*2;
631
632 so->so_state = (SS_FACCEPTCONN|flags);
633 so->so_lport = lport; /* Kept in network format */
634 so->so_laddr.s_addr = laddr; /* Ditto */
635
636 addr.sin_family = AF_INET;
637 addr.sin_addr.s_addr = INADDR_ANY;
638 addr.sin_port = port;
639
640 if ( ((s = socket(AF_INET,SOCK_STREAM,0)) < 0)
641 || (setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int)) < 0)
642 || (bind(s,(struct sockaddr *)&addr, sizeof(addr)) < 0)
643 || (listen(s,1) < 0))
644 {
645#ifdef RT_OS_WINDOWS
646 int tmperrno = WSAGetLastError(); /* Don't clobber the real reason we failed */
647 closesocket(s);
648 sofree(pData, so);
649 /* Restore the real errno */
650 WSASetLastError(tmperrno);
651#else
652 int tmperrno = errno; /* Don't clobber the real reason we failed */
653 close(s);
654 sofree(pData, so);
655 /* Restore the real errno */
656 errno = tmperrno;
657#endif
658 return NULL;
659 }
660 setsockopt(s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(int));
661
662 getsockname(s,(struct sockaddr *)&addr,&addrlen);
663 so->so_fport = addr.sin_port;
664 if (addr.sin_addr.s_addr == 0 || addr.sin_addr.s_addr == loopback_addr.s_addr)
665 so->so_faddr = alias_addr;
666 else
667 so->so_faddr = addr.sin_addr;
668
669 so->s = s;
670 return so;
671}
672
673/*
674 * Data is available in so_rcv
675 * Just write() the data to the socket
676 * XXX not yet...
677 */
678void
679sorwakeup(struct socket *so)
680{
681#if 0
682 sowrite(so);
683 FD_CLR(so->s,&writefds);
684#endif
685}
686
687/*
688 * Data has been freed in so_snd
689 * We have room for a read() if we want to
690 * For now, don't read, it'll be done in the main loop
691 */
692void
693sowwakeup(struct socket *so)
694{
695}
696
697/*
698 * Various session state calls
699 * XXX Should be #define's
700 * The socket state stuff needs work, these often get call 2 or 3
701 * times each when only 1 was needed
702 */
703void
704soisfconnecting(struct socket *so)
705{
706 so->so_state &= ~(SS_NOFDREF|SS_ISFCONNECTED|SS_FCANTRCVMORE|
707 SS_FCANTSENDMORE|SS_FWDRAIN);
708 so->so_state |= SS_ISFCONNECTING; /* Clobber other states */
709}
710
711void
712soisfconnected(struct socket *so)
713{
714 so->so_state &= ~(SS_ISFCONNECTING|SS_FWDRAIN|SS_NOFDREF);
715 so->so_state |= SS_ISFCONNECTED; /* Clobber other states */
716}
717
718void
719sofcantrcvmore(struct socket *so)
720{
721 if ((so->so_state & SS_NOFDREF) == 0)
722 {
723 shutdown(so->s,0);
724 }
725 so->so_state &= ~(SS_ISFCONNECTING);
726 if (so->so_state & SS_FCANTSENDMORE)
727 so->so_state = SS_NOFDREF; /* Don't select it */
728 /* XXX close() here as well? */
729 else
730 so->so_state |= SS_FCANTRCVMORE;
731}
732
733void
734sofcantsendmore(struct socket *so)
735{
736 if ((so->so_state & SS_NOFDREF) == 0)
737 shutdown(so->s, 1); /* send FIN to fhost */
738
739 so->so_state &= ~(SS_ISFCONNECTING);
740 if (so->so_state & SS_FCANTRCVMORE)
741 so->so_state = SS_NOFDREF; /* as above */
742 else
743 so->so_state |= SS_FCANTSENDMORE;
744}
745
746void
747soisfdisconnected(struct socket *so)
748{
749#if 0
750 so->so_state &= ~(SS_ISFCONNECTING|SS_ISFCONNECTED);
751 close(so->s);
752 so->so_state = SS_ISFDISCONNECTED;
753 /*
754 * XXX Do nothing ... ?
755 */
756#endif
757}
758
759/*
760 * Set write drain mode
761 * Set CANTSENDMORE once all data has been write()n
762 */
763void
764sofwdrain(struct socket *so)
765{
766 if (so->so_rcv.sb_cc)
767 so->so_state |= SS_FWDRAIN;
768 else
769 sofcantsendmore(so);
770}
771
772#ifdef VBOX_WITH_SLIRP_ICMP
773static void
774send_icmp_to_guest(PNATState pData, char *buff, size_t len, struct socket *so, const struct sockaddr_in *addr)
775{
776 struct ip *ip;
777 uint32_t dst,src;
778 char ip_copy[256];
779 struct icmp *icp;
780 int old_ip_len;
781 struct mbuf *m;
782 struct icmp_msg *icm;
783
784 ip = (struct ip *)buff;
785 icp = (struct icmp *)((char *)ip + (ip->ip_hl << 2));
786
787 Assert(icp->icmp_type == ICMP_ECHOREPLY || icp->icmp_type == ICMP_TIMXCEED);
788
789 if (icp->icmp_type == ICMP_TIMXCEED ) {
790 ip = &icp->icmp_ip;
791 }
792
793 icm = icmp_find_original_mbuf(pData, ip);
794
795 if (icm == NULL)
796 {
797 LogRel(("NAT: Can't find the corresponding packet for the received ICMP\n"));
798 return;
799 }
800
801 m = icm->im_m;
802 Assert(m != NULL);
803
804 src = addr->sin_addr.s_addr;
805
806 ip = mtod(m, struct ip *);
807 /* Now ip is pointing on header we've sent from guest */
808 if (icp->icmp_type == ICMP_TIMXCEED) {
809 old_ip_len = (ip->ip_hl << 2) + 64;
810 memcpy(ip_copy, ip, old_ip_len);
811 }
812
813 /* source address from original IP packet*/
814 dst = ip->ip_src.s_addr;
815
816 /* overide ther tail of old packet */
817 memcpy(m->m_data, buff, len);
818 m->m_len = len;
819 ip = mtod(m, struct ip *); /* ip is from mbuf we've overrided */
820
821 icp = (struct icmp *)((char *)ip + (ip->ip_hl << 2));
822 if (icp->icmp_type == ICMP_TIMXCEED) {
823 /* according RFC 793 error messages required copy of initial IP header + 64 bit */
824 memcpy(&icp->icmp_ip, ip_copy, old_ip_len);
825 ip->ip_tos=((ip->ip_tos & 0x1E) | 0xC0); /* high priority for errors */
826 }
827
828 /* the low level expects fields to be in host format so let's convert them*/
829 NTOHS(ip->ip_len);
830 NTOHS(ip->ip_off);
831 NTOHS(ip->ip_id);
832 ip->ip_src.s_addr = src;
833 ip->ip_dst.s_addr = dst;
834 icmp_reflect(pData, m);
835 LIST_REMOVE(icm, im_list);
836 /* Don't call m_free here*/
837 free(icm);
838}
839
840# ifdef RT_OS_WINDOWS
841static void
842sorecvfrom_icmp_win(PNATState pData, struct socket *so)
843{
844 int len;
845 int i;
846 struct ip *ip;
847 struct mbuf *m;
848 struct icmp *icp;
849 ICMP_ECHO_REPLY *icr;
850 u_char code = ~0;
851 len = pData->pfIcmpParseReplies(pData->pvIcmpBuffer, pData->szIcmpBuffer);
852 if (len <= 0)
853 {
854 LogRel(("NAT: Error (%d) occurred on ICMP receiving\n", GetLastError()));
855 return;
856 }
857 LogRel(("IcmpParseReplies returns %ld\n", len));
858 icr = (ICMP_ECHO_REPLY *)pData->pvIcmpBuffer;
859 for (i = 0; i < len; ++i)
860 {
861 switch(icr[i].Status)
862 {
863 case IP_DEST_HOST_UNREACHABLE:
864 code = (code != ~0 ? code :ICMP_UNREACH_HOST);
865 case IP_DEST_NET_UNREACHABLE:
866 code = (code != ~0 ? code : ICMP_UNREACH_NET);
867 case IP_DEST_PROT_UNREACHABLE:
868 code = (code != ~0 ? code : ICMP_UNREACH_PROTOCOL);
869 /* UNREACH error inject here */
870 case IP_DEST_PORT_UNREACHABLE:
871 code = (code != ~0 ? code : ICMP_UNREACH_PORT);
872 icmp_error(pData, so->so_m, ICMP_UNREACH, code, 0, "Error occurred!!!");
873 break;
874 case IP_SUCCESS: /* echo replied */
875 m = m_get(pData);
876 ip = mtod(m, struct ip *);
877 ip->ip_src.s_addr = icr[i].Address;
878 ip->ip_p = IPPROTO_ICMP;
879 ip->ip_dst.s_addr = so->so_laddr.s_addr; /*XXX: still the hack*/
880 ip->ip_hl = sizeof(struct ip) >> 2;
881
882 icp = (struct icmp *)&ip[1]; /* no options */
883 icp->icmp_type = ICMP_ECHOREPLY;
884 icp->icmp_code = 0;
885 icp->icmp_id = so->so_icmp_id;
886 icp->icmp_seq = so->so_icmp_seq;
887 memcpy(icp->icmp_data, icr[i].Data, icr[i].DataSize);
888
889 ip->ip_len = sizeof(struct ip) + ICMP_MINLEN + icr[i].DataSize;
890 m->m_len = ip->ip_len;
891
892 icmp_reflect(pData, m);
893 m_free(pData, m);
894 case IP_TTL_EXPIRED_TRANSIT: /* TTL expired */
895 LogRel(("ICMP: message with Status: %x was received from %x\n", icr[i].Status, icr[i].Address));
896 LogRel(("ICMP: IP(v %hd, l %hd )\n", ip->ip_v, ip->ip_hl));
897 break;
898 default:
899 LogRel(("ICMP(default): message with Status: %x was received from %s\n", icr[i].Status, icr[i].Address));
900 break;
901 }
902 }
903}
904# endif /* RT_OS_WINDOWS */
905#endif /* VBOX_WITH_SLIRP_ICMP */
906
907static void sorecvfrom_icmp_unix(PNATState pData, struct socket *so)
908{
909 struct sockaddr_in addr;
910 socklen_t addrlen = sizeof(struct sockaddr_in);
911 char buff[1500];
912 int len;
913 len = recvfrom(so->s, buff, 1500, 0,
914 (struct sockaddr *)&addr, &addrlen);
915 /* XXX Check if reply is "correct"? */
916
917 if(len == -1 || len == 0)
918 {
919 u_char code = ICMP_UNREACH_PORT;
920
921 if (errno == EHOSTUNREACH)
922 code=ICMP_UNREACH_HOST;
923 else if(errno == ENETUNREACH)
924 code=ICMP_UNREACH_NET;
925
926
927 DEBUG_MISC((dfd," udp icmp rx errno = %d-%s\n",
928 errno,strerror(errno)));
929 icmp_error(pData, so->so_m, ICMP_UNREACH,code, 0,strerror(errno));
930 }
931 else
932 {
933#ifdef VBOX_WITH_SLIRP_ICMP
934 send_icmp_to_guest(pData, buff, len, so, &addr);
935#else
936 icmp_reflect(pData, so->so_m);
937 so->so_m = 0; /* Don't m_free() it again! */
938#endif
939 }
940}
941
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette