VirtualBox

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

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

slirp:codding style

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

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