VirtualBox

source: vbox/trunk/src/VBox/Devices/Network/slirp/tcp_subr.c@ 13670

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

Resolved locks in UDP
Some mutex operations checked with AssertReleaseRC
Still TCP part need to be re-checked
udb_mutex now used only for controlling pData->udb
and udp_last_so controlled by udp_last_so_mutex

  • Property svn:eol-style set to native
File size: 38.3 KB
Line 
1/*
2 * Copyright (c) 1982, 1986, 1988, 1990, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * @(#)tcp_subr.c 8.1 (Berkeley) 6/10/93
34 * tcp_subr.c,v 1.5 1994/10/08 22:39:58 phk Exp
35 */
36
37/*
38 * Changes and additions relating to SLiRP
39 * Copyright (c) 1995 Danny Gasparovski.
40 *
41 * Please read the file COPYRIGHT for the
42 * terms and conditions of the copyright.
43 */
44
45#define WANT_SYS_IOCTL_H
46#include <slirp.h>
47
48
49/*
50 * Tcp initialization
51 */
52void
53tcp_init(PNATState pData)
54{
55 tcp_iss = 1; /* wrong */
56 tcb.so_next = tcb.so_prev = &tcb;
57 tcp_last_so = &tcb;
58}
59
60/*
61 * Create template to be used to send tcp packets on a connection.
62 * Call after host entry created, fills
63 * in a skeletal tcp/ip header, minimizing the amount of work
64 * necessary when the connection is used.
65 */
66/* struct tcpiphdr * */
67void
68tcp_template(tp)
69 struct tcpcb *tp;
70{
71 struct socket *so = tp->t_socket;
72 register struct tcpiphdr *n = &tp->t_template;
73
74 n->ti_next = n->ti_prev = 0;
75 n->ti_x1 = 0;
76 n->ti_pr = IPPROTO_TCP;
77 n->ti_len = htons(sizeof (struct tcpiphdr) - sizeof (struct ip));
78 n->ti_src = so->so_faddr;
79 n->ti_dst = so->so_laddr;
80 n->ti_sport = so->so_fport;
81 n->ti_dport = so->so_lport;
82
83 n->ti_seq = 0;
84 n->ti_ack = 0;
85 n->ti_x2 = 0;
86 n->ti_off = 5;
87 n->ti_flags = 0;
88 n->ti_win = 0;
89 n->ti_sum = 0;
90 n->ti_urp = 0;
91}
92
93/*
94 * Send a single message to the TCP at address specified by
95 * the given TCP/IP header. If m == 0, then we make a copy
96 * of the tcpiphdr at ti and send directly to the addressed host.
97 * This is used to force keep alive messages out using the TCP
98 * template for a connection tp->t_template. If flags are given
99 * then we send a message back to the TCP which originated the
100 * segment ti, and discard the mbuf containing it and any other
101 * attached mbufs.
102 *
103 * In any case the ack and sequence number of the transmitted
104 * segment are as specified by the parameters.
105 */
106void
107tcp_respond(PNATState pData, struct tcpcb *tp, struct tcpiphdr *ti, struct mbuf *m, tcp_seq ack, tcp_seq seq, int flags)
108{
109 register int tlen;
110 int win = 0;
111
112 DEBUG_CALL("tcp_respond");
113 DEBUG_ARG("tp = %lx", (long)tp);
114 DEBUG_ARG("ti = %lx", (long)ti);
115 DEBUG_ARG("m = %lx", (long)m);
116 DEBUG_ARG("ack = %u", ack);
117 DEBUG_ARG("seq = %u", seq);
118 DEBUG_ARG("flags = %x", flags);
119
120 if (tp)
121 win = sbspace(&tp->t_socket->so_rcv);
122 if (m == 0) {
123 if ((m = m_get(pData)) == NULL)
124 return;
125#ifdef TCP_COMPAT_42
126 tlen = 1;
127#else
128 tlen = 0;
129#endif
130 m->m_data += if_maxlinkhdr;
131 *mtod(m, struct tcpiphdr *) = *ti;
132 ti = mtod(m, struct tcpiphdr *);
133 flags = TH_ACK;
134 } else {
135 /*
136 * ti points into m so the next line is just making
137 * the mbuf point to ti
138 */
139 m->m_data = (caddr_t)ti;
140
141 m->m_len = sizeof (struct tcpiphdr);
142 tlen = 0;
143#define xchg(a,b,type) { type t; t=a; a=b; b=t; }
144 xchg(ti->ti_dst.s_addr, ti->ti_src.s_addr, u_int32_t);
145 xchg(ti->ti_dport, ti->ti_sport, u_int16_t);
146#undef xchg
147 }
148 ti->ti_len = htons((u_short)(sizeof (struct tcphdr) + tlen));
149 tlen += sizeof (struct tcpiphdr);
150 m->m_len = tlen;
151
152 ti->ti_next = ti->ti_prev = 0;
153 ti->ti_x1 = 0;
154 ti->ti_seq = htonl(seq);
155 ti->ti_ack = htonl(ack);
156 ti->ti_x2 = 0;
157 ti->ti_off = sizeof (struct tcphdr) >> 2;
158 ti->ti_flags = flags;
159 if (tp)
160 ti->ti_win = htons((u_int16_t) (win >> tp->rcv_scale));
161 else
162 ti->ti_win = htons((u_int16_t)win);
163 ti->ti_urp = 0;
164 ti->ti_sum = 0;
165 ti->ti_sum = cksum(m, tlen);
166 ((struct ip *)ti)->ip_len = tlen;
167
168 if(flags & TH_RST)
169 ((struct ip *)ti)->ip_ttl = MAXTTL;
170 else
171 ((struct ip *)ti)->ip_ttl = ip_defttl;
172
173 (void) ip_output(pData, (struct socket *)0, m);
174}
175
176/*
177 * Create a new TCP control block, making an
178 * empty reassembly queue and hooking it to the argument
179 * protocol control block.
180 */
181struct tcpcb *
182tcp_newtcpcb(PNATState pData, struct socket *so)
183{
184 register struct tcpcb *tp;
185
186 tp = (struct tcpcb *)malloc(sizeof(*tp));
187 if (tp == NULL)
188 return ((struct tcpcb *)0);
189
190 memset((char *) tp, 0, sizeof(struct tcpcb));
191 tp->seg_next = tp->seg_prev = ptr_to_u32(pData, (struct tcpiphdr *)tp);
192 tp->t_maxseg = tcp_mssdflt;
193
194 tp->t_flags = tcp_do_rfc1323 ? (TF_REQ_SCALE|TF_REQ_TSTMP) : 0;
195 tp->t_socket = so;
196
197 /*
198 * Init srtt to TCPTV_SRTTBASE (0), so we can tell that we have no
199 * rtt estimate. Set rttvar so that srtt + 2 * rttvar gives
200 * reasonable initial retransmit time.
201 */
202 tp->t_srtt = TCPTV_SRTTBASE;
203 tp->t_rttvar = tcp_rttdflt * PR_SLOWHZ << 2;
204 tp->t_rttmin = TCPTV_MIN;
205
206 TCPT_RANGESET(tp->t_rxtcur,
207 ((TCPTV_SRTTBASE >> 2) + (TCPTV_SRTTDFLT << 2)) >> 1,
208 TCPTV_MIN, TCPTV_REXMTMAX);
209
210 tp->snd_cwnd = TCP_MAXWIN << TCP_MAX_WINSHIFT;
211 tp->snd_ssthresh = TCP_MAXWIN << TCP_MAX_WINSHIFT;
212 tp->t_state = TCPS_CLOSED;
213
214 so->so_tcpcb = tp;
215
216 return (tp);
217}
218
219/*
220 * Drop a TCP connection, reporting
221 * the specified error. If connection is synchronized,
222 * then send a RST to peer.
223 */
224struct tcpcb *tcp_drop(PNATState pData, struct tcpcb *tp, int err)
225{
226/* tcp_drop(tp, errno)
227 register struct tcpcb *tp;
228 int errno;
229{
230*/
231
232 DEBUG_CALL("tcp_drop");
233 DEBUG_ARG("tp = %lx", (long)tp);
234 DEBUG_ARG("errno = %d", errno);
235
236 if (TCPS_HAVERCVDSYN(tp->t_state)) {
237 tp->t_state = TCPS_CLOSED;
238 (void) tcp_output(pData, tp);
239 tcpstat.tcps_drops++;
240 } else
241 tcpstat.tcps_conndrops++;
242/* if (errno == ETIMEDOUT && tp->t_softerror)
243 * errno = tp->t_softerror;
244 */
245/* so->so_error = errno; */
246 return (tcp_close(pData, tp));
247}
248
249/*
250 * Close a TCP control block:
251 * discard all space held by the tcp
252 * discard internet protocol block
253 * wake up any sleepers
254 */
255struct tcpcb *
256tcp_close(PNATState pData, register struct tcpcb *tp)
257{
258 register struct tcpiphdr *t;
259 struct socket *so = tp->t_socket;
260 register struct mbuf *m;
261
262 DEBUG_CALL("tcp_close");
263 DEBUG_ARG("tp = %lx", (long )tp);
264
265 /* free the reassembly queue, if any */
266 t = u32_to_ptr(pData, tp->seg_next, struct tcpiphdr *);
267 while (t != (struct tcpiphdr *)tp) {
268 t = u32_to_ptr(pData, t->ti_next, struct tcpiphdr *);
269 m = REASS_MBUF_GET(u32_to_ptr(pData, t->ti_prev, struct tcpiphdr *));
270 remque_32(pData, u32_to_ptr(pData, t->ti_prev, struct tcpiphdr *));
271 m_freem(pData, m);
272 }
273 /* It's static */
274/* if (tp->t_template)
275 * (void) m_free(dtom(tp->t_template));
276 */
277/* free(tp, M_PCB); */
278#ifdef VBOX_WITH_SYNC_SLIRP
279 RTSemMutexRequest(pData->tcb_mutex, RT_INDEFINITE_WAIT);
280 /*sofree destrys so_mutex*/
281 RTSemMutexRequest(so->so_mutex, RT_INDEFINITE_WAIT);
282#endif
283 u32ptr_done(pData, ptr_to_u32(pData, tp), tp);
284 free(tp);
285 so->so_tcpcb = 0;
286 soisfdisconnected(so);
287 /* clobber input socket cache if we're closing the cached connection */
288 if (so == tcp_last_so)
289 tcp_last_so = &tcb;
290 closesocket(so->s);
291 sbfree(&so->so_rcv);
292 sbfree(&so->so_snd);
293 sofree(pData, so);
294 tcpstat.tcps_closed++;
295#ifdef VBOX_WITH_SYNC_SLIRP
296 RTSemMutexRelease(pData->tcb_mutex);
297#endif
298 return ((struct tcpcb *)0);
299}
300
301void
302tcp_drain()
303{
304 /* XXX */
305}
306
307/*
308 * When a source quench is received, close congestion window
309 * to one segment. We will gradually open it again as we proceed.
310 */
311
312#ifdef notdef
313
314void
315tcp_quench(i, errno)
316
317 int errno;
318{
319 struct tcpcb *tp = intotcpcb(inp);
320
321 if (tp)
322 tp->snd_cwnd = tp->t_maxseg;
323}
324
325#endif /* notdef */
326
327/*
328 * TCP protocol interface to socket abstraction.
329 */
330
331/*
332 * User issued close, and wish to trail through shutdown states:
333 * if never received SYN, just forget it. If got a SYN from peer,
334 * but haven't sent FIN, then go to FIN_WAIT_1 state to send peer a FIN.
335 * If already got a FIN from peer, then almost done; go to LAST_ACK
336 * state. In all other cases, have already sent FIN to peer (e.g.
337 * after PRU_SHUTDOWN), and just have to play tedious game waiting
338 * for peer to send FIN or not respond to keep-alives, etc.
339 * We can let the user exit from the close as soon as the FIN is acked.
340 */
341void
342tcp_sockclosed(PNATState pData, struct tcpcb *tp)
343{
344
345 DEBUG_CALL("tcp_sockclosed");
346 DEBUG_ARG("tp = %lx", (long)tp);
347
348 switch (tp->t_state) {
349
350 case TCPS_CLOSED:
351 case TCPS_LISTEN:
352 case TCPS_SYN_SENT:
353 tp->t_state = TCPS_CLOSED;
354 tp = tcp_close(pData, tp);
355 break;
356
357 case TCPS_SYN_RECEIVED:
358 case TCPS_ESTABLISHED:
359 tp->t_state = TCPS_FIN_WAIT_1;
360 break;
361
362 case TCPS_CLOSE_WAIT:
363 tp->t_state = TCPS_LAST_ACK;
364 break;
365 }
366/* soisfdisconnecting(tp->t_socket); */
367 if (tp && tp->t_state >= TCPS_FIN_WAIT_2)
368 soisfdisconnected(tp->t_socket);
369 if (tp)
370 tcp_output(pData, tp);
371}
372
373/*
374 * Connect to a host on the Internet
375 * Called by tcp_input
376 * Only do a connect, the tcp fields will be set in tcp_input
377 * return 0 if there's a result of the connect,
378 * else return -1 means we're still connecting
379 * The return value is almost always -1 since the socket is
380 * nonblocking. Connect returns after the SYN is sent, and does
381 * not wait for ACK+SYN.
382 */
383int tcp_fconnect(PNATState pData, struct socket *so)
384{
385 int ret=0;
386
387 DEBUG_CALL("tcp_fconnect");
388 DEBUG_ARG("so = %lx", (long )so);
389
390 if( (ret=so->s=socket(AF_INET,SOCK_STREAM,0)) >= 0) {
391 int opt, s=so->s;
392 struct sockaddr_in addr;
393
394 fd_nonblock(s);
395 opt = 1;
396 setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(opt ));
397 opt = 1;
398 setsockopt(s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(opt ));
399
400 addr.sin_family = AF_INET;
401 if ((so->so_faddr.s_addr & htonl(pData->netmask)) == special_addr.s_addr) {
402 /* It's an alias */
403 switch(ntohl(so->so_faddr.s_addr) & ~pData->netmask) {
404 case CTL_DNS:
405 if (!get_dns_addr(pData, &dns_addr))
406 addr.sin_addr = dns_addr;
407 else
408 addr.sin_addr = loopback_addr;
409 break;
410 case CTL_ALIAS:
411 default:
412 addr.sin_addr = loopback_addr;
413 break;
414 }
415 } else
416 addr.sin_addr = so->so_faddr;
417 addr.sin_port = so->so_fport;
418
419 DEBUG_MISC((dfd, " connect()ing, addr.sin_port=%d, "
420 "addr.sin_addr.s_addr=%.16s\n",
421 ntohs(addr.sin_port), inet_ntoa(addr.sin_addr)));
422 /* We don't care what port we get */
423 ret = connect(s,(struct sockaddr *)&addr,sizeof (addr));
424
425 /*
426 * If it's not in progress, it failed, so we just return 0,
427 * without clearing SS_NOFDREF
428 */
429 soisfconnecting(so);
430 }
431
432 return(ret);
433}
434
435/*
436 * Accept the socket and connect to the local-host
437 *
438 * We have a problem. The correct thing to do would be
439 * to first connect to the local-host, and only if the
440 * connection is accepted, then do an accept() here.
441 * But, a) we need to know who's trying to connect
442 * to the socket to be able to SYN the local-host, and
443 * b) we are already connected to the foreign host by
444 * the time it gets to accept(), so... We simply accept
445 * here and SYN the local-host.
446 */
447void
448tcp_connect(PNATState pData, struct socket *inso)
449{
450 struct socket *so;
451 struct sockaddr_in addr;
452 socklen_t addrlen = sizeof(struct sockaddr_in);
453 struct tcpcb *tp;
454 int s, opt;
455
456 DEBUG_CALL("tcp_connect");
457 DEBUG_ARG("inso = %lx", (long)inso);
458
459 /*
460 * If it's an SS_ACCEPTONCE socket, no need to socreate()
461 * another socket, just use the accept() socket.
462 */
463 if (inso->so_state & SS_FACCEPTONCE) {
464 /* FACCEPTONCE already have a tcpcb */
465 so = inso;
466 } else {
467 if ((so = socreate()) == NULL) {
468 /* If it failed, get rid of the pending connection */
469 closesocket(accept(inso->s,(struct sockaddr *)&addr,&addrlen));
470 return;
471 }
472 if (tcp_attach(pData, so) < 0) {
473 free(so); /* NOT sofree */
474 return;
475 }
476 so->so_laddr = inso->so_laddr;
477 so->so_lport = inso->so_lport;
478 }
479
480 (void) tcp_mss(pData, sototcpcb(so), 0);
481
482 if ((s = accept(inso->s,(struct sockaddr *)&addr,&addrlen)) < 0) {
483 tcp_close(pData, sototcpcb(so)); /* This will sofree() as well */
484 return;
485 }
486 fd_nonblock(s);
487 opt = 1;
488 setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int));
489 opt = 1;
490 setsockopt(s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(int));
491 opt = 1;
492 setsockopt(s,IPPROTO_TCP,TCP_NODELAY,(char *)&opt,sizeof(int));
493
494 so->so_fport = addr.sin_port;
495 so->so_faddr = addr.sin_addr;
496 /* Translate connections from localhost to the real hostname */
497 if (so->so_faddr.s_addr == 0 || so->so_faddr.s_addr == loopback_addr.s_addr)
498 so->so_faddr = alias_addr;
499
500 /* Close the accept() socket, set right state */
501 if (inso->so_state & SS_FACCEPTONCE) {
502 closesocket(so->s); /* If we only accept once, close the accept() socket */
503 so->so_state = SS_NOFDREF; /* Don't select it yet, even though we have an FD */
504 /* if it's not FACCEPTONCE, it's already NOFDREF */
505 }
506 so->s = s;
507
508 so->so_iptos = tcp_tos(so);
509 tp = sototcpcb(so);
510
511 tcp_template(tp);
512
513 /* Compute window scaling to request. */
514/* while (tp->request_r_scale < TCP_MAX_WINSHIFT &&
515 * (TCP_MAXWIN << tp->request_r_scale) < so->so_rcv.sb_hiwat)
516 * tp->request_r_scale++;
517 */
518
519/* soisconnecting(so); */ /* NOFDREF used instead */
520 tcpstat.tcps_connattempt++;
521
522 tp->t_state = TCPS_SYN_SENT;
523 tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT;
524 tp->iss = tcp_iss;
525 tcp_iss += TCP_ISSINCR/2;
526 tcp_sendseqinit(tp);
527 tcp_output(pData, tp);
528}
529
530/*
531 * Attach a TCPCB to a socket.
532 */
533int
534tcp_attach(PNATState pData, struct socket *so)
535{
536 if ((so->so_tcpcb = tcp_newtcpcb(pData, so)) == NULL)
537 return -1;
538#ifdef VBOX_WITH_SYNC_SLIRP
539 so->so_type = IPPROTO_TCP;
540
541 RTSemMutexRequest(pData->tcb_mutex, RT_INDEFINITE_WAIT);
542 insque(pData, so, &tcb);
543 RTSemMutexRelease(pData->tcb_mutex);
544#else
545 insque(pData, so, &tcb);
546#endif
547
548 return 0;
549}
550
551/*
552 * Set the socket's type of service field
553 */
554static const struct tos_t tcptos[] = {
555 {0, 20, IPTOS_THROUGHPUT, 0}, /* ftp data */
556 {21, 21, IPTOS_LOWDELAY, EMU_FTP}, /* ftp control */
557 {0, 23, IPTOS_LOWDELAY, 0}, /* telnet */
558 {0, 80, IPTOS_THROUGHPUT, 0}, /* WWW */
559 {0, 513, IPTOS_LOWDELAY, EMU_RLOGIN|EMU_NOCONNECT}, /* rlogin */
560 {0, 514, IPTOS_LOWDELAY, EMU_RSH|EMU_NOCONNECT}, /* shell */
561 {0, 544, IPTOS_LOWDELAY, EMU_KSH}, /* kshell */
562 {0, 543, IPTOS_LOWDELAY, 0}, /* klogin */
563 {0, 6667, IPTOS_THROUGHPUT, EMU_IRC}, /* IRC */
564 {0, 6668, IPTOS_THROUGHPUT, EMU_IRC}, /* IRC undernet */
565 {0, 7070, IPTOS_LOWDELAY, EMU_REALAUDIO }, /* RealAudio control */
566 {0, 113, IPTOS_LOWDELAY, EMU_IDENT }, /* identd protocol */
567 {0, 0, 0, 0}
568};
569
570/*
571 * Return TOS according to the above table
572 */
573u_int8_t
574tcp_tos(so)
575 struct socket *so;
576{
577 int i = 0;
578
579 while(tcptos[i].tos) {
580 if ((tcptos[i].fport && (ntohs(so->so_fport) == tcptos[i].fport)) ||
581 (tcptos[i].lport && (ntohs(so->so_lport) == tcptos[i].lport))) {
582 so->so_emu = tcptos[i].emu;
583 return tcptos[i].tos;
584 }
585 i++;
586 }
587
588 return 0;
589}
590
591/*
592 * Emulate programs that try and connect to us
593 * This includes ftp (the data connection is
594 * initiated by the server) and IRC (DCC CHAT and
595 * DCC SEND) for now
596 *
597 * NOTE: It's possible to crash SLiRP by sending it
598 * unstandard strings to emulate... if this is a problem,
599 * more checks are needed here
600 *
601 * XXX Assumes the whole command came in one packet
602 *
603 * XXX Some ftp clients will have their TOS set to
604 * LOWDELAY and so Nagel will kick in. Because of this,
605 * we'll get the first letter, followed by the rest, so
606 * we simply scan for ORT instead of PORT...
607 * DCC doesn't have this problem because there's other stuff
608 * in the packet before the DCC command.
609 *
610 * Return 1 if the mbuf m is still valid and should be
611 * sbappend()ed
612 *
613 * NOTE: if you return 0 you MUST m_free() the mbuf!
614 */
615int
616tcp_emu(PNATState pData, struct socket *so, struct mbuf *m)
617{
618 u_int n1, n2, n3, n4, n5, n6;
619 char buff[256];
620 u_int32_t laddr;
621 u_int lport;
622 char *bptr;
623
624 DEBUG_CALL("tcp_emu");
625 DEBUG_ARG("so = %lx", (long)so);
626 DEBUG_ARG("m = %lx", (long)m);
627
628 switch(so->so_emu) {
629 int x, i;
630
631 case EMU_IDENT:
632 /*
633 * Identification protocol as per rfc-1413
634 */
635
636 {
637 struct socket *tmpso;
638 struct sockaddr_in addr;
639 socklen_t addrlen = sizeof(struct sockaddr_in);
640 struct sbuf *so_rcv = &so->so_rcv;
641
642 memcpy(so_rcv->sb_wptr, m->m_data, m->m_len);
643 so_rcv->sb_wptr += m->m_len;
644 so_rcv->sb_rptr += m->m_len;
645 m->m_data[m->m_len] = 0; /* NULL terminate */
646 if (strchr(m->m_data, '\r') || strchr(m->m_data, '\n')) {
647 if (sscanf(so_rcv->sb_data, "%u%*[ ,]%u", &n1, &n2) == 2) {
648 HTONS(n1);
649 HTONS(n2);
650 /* n2 is the one on our host */
651 for (tmpso = tcb.so_next; tmpso != &tcb; tmpso = tmpso->so_next) {
652 if (tmpso->so_laddr.s_addr == so->so_laddr.s_addr &&
653 tmpso->so_lport == n2 &&
654 tmpso->so_faddr.s_addr == so->so_faddr.s_addr &&
655 tmpso->so_fport == n1) {
656 if (getsockname(tmpso->s,
657 (struct sockaddr *)&addr, &addrlen) == 0)
658 n2 = ntohs(addr.sin_port);
659 break;
660 }
661 }
662 }
663 so_rcv->sb_cc = sprintf(so_rcv->sb_data, "%d,%d\r\n", n1, n2);
664 so_rcv->sb_rptr = so_rcv->sb_data;
665 so_rcv->sb_wptr = so_rcv->sb_data + so_rcv->sb_cc;
666 }
667 m_free(pData, m);
668 return 0;
669 }
670
671#if 0
672 case EMU_RLOGIN:
673 /*
674 * Rlogin emulation
675 * First we accumulate all the initial option negotiation,
676 * then fork_exec() rlogin according to the options
677 */
678 {
679 int i, i2, n;
680 char *ptr;
681 char args[100];
682 char term[100];
683 struct sbuf *so_snd = &so->so_snd;
684 struct sbuf *so_rcv = &so->so_rcv;
685
686 /* First check if they have a priveladged port, or too much data has arrived */
687 if (ntohs(so->so_lport) > 1023 || ntohs(so->so_lport) < 512 ||
688 (m->m_len + so_rcv->sb_wptr) > (so_rcv->sb_data + so_rcv->sb_datalen)) {
689 memcpy(so_snd->sb_wptr, "Permission denied\n", 18);
690 so_snd->sb_wptr += 18;
691 so_snd->sb_cc += 18;
692 tcp_sockclosed(sototcpcb(so));
693 m_free(m);
694 return 0;
695 }
696
697 /* Append the current data */
698 memcpy(so_rcv->sb_wptr, m->m_data, m->m_len);
699 so_rcv->sb_wptr += m->m_len;
700 so_rcv->sb_rptr += m->m_len;
701 m_free(m);
702
703 /*
704 * Check if we have all the initial options,
705 * and build argument list to rlogin while we're here
706 */
707 n = 0;
708 ptr = so_rcv->sb_data;
709 args[0] = 0;
710 term[0] = 0;
711 while (ptr < so_rcv->sb_wptr) {
712 if (*ptr++ == 0) {
713 n++;
714 if (n == 2) {
715 sprintf(args, "rlogin -l %s %s",
716 ptr, inet_ntoa(so->so_faddr));
717 } else if (n == 3) {
718 i2 = so_rcv->sb_wptr - ptr;
719 for (i = 0; i < i2; i++) {
720 if (ptr[i] == '/') {
721 ptr[i] = 0;
722#ifdef HAVE_SETENV
723 sprintf(term, "%s", ptr);
724#else
725 sprintf(term, "TERM=%s", ptr);
726#endif
727 ptr[i] = '/';
728 break;
729 }
730 }
731 }
732 }
733 }
734
735 if (n != 4)
736 return 0;
737
738 /* We have it, set our term variable and fork_exec() */
739#ifdef HAVE_SETENV
740 setenv("TERM", term, 1);
741#else
742 putenv(term);
743#endif
744 fork_exec(so, args, 2);
745 term[0] = 0;
746 so->so_emu = 0;
747
748 /* And finally, send the client a 0 character */
749 so_snd->sb_wptr[0] = 0;
750 so_snd->sb_wptr++;
751 so_snd->sb_cc++;
752
753 return 0;
754 }
755
756 case EMU_RSH:
757 /*
758 * rsh emulation
759 * First we accumulate all the initial option negotiation,
760 * then rsh_exec() rsh according to the options
761 */
762 {
763 int n;
764 char *ptr;
765 char *user;
766 char *args;
767 struct sbuf *so_snd = &so->so_snd;
768 struct sbuf *so_rcv = &so->so_rcv;
769
770 /* First check if they have a priveladged port, or too much data has arrived */
771 if (ntohs(so->so_lport) > 1023 || ntohs(so->so_lport) < 512 ||
772 (m->m_len + so_rcv->sb_wptr) > (so_rcv->sb_data + so_rcv->sb_datalen)) {
773 memcpy(so_snd->sb_wptr, "Permission denied\n", 18);
774 so_snd->sb_wptr += 18;
775 so_snd->sb_cc += 18;
776 tcp_sockclosed(sototcpcb(so));
777 m_free(m);
778 return 0;
779 }
780
781 /* Append the current data */
782 memcpy(so_rcv->sb_wptr, m->m_data, m->m_len);
783 so_rcv->sb_wptr += m->m_len;
784 so_rcv->sb_rptr += m->m_len;
785 m_free(m);
786
787 /*
788 * Check if we have all the initial options,
789 * and build argument list to rlogin while we're here
790 */
791 n = 0;
792 ptr = so_rcv->sb_data;
793 user="";
794 args="";
795 if (so->extra==NULL) {
796 struct socket *ns;
797 struct tcpcb* tp;
798 int port=atoi(ptr);
799 if (port <= 0) return 0;
800 if (port > 1023 || port < 512) {
801 memcpy(so_snd->sb_wptr, "Permission denied\n", 18);
802 so_snd->sb_wptr += 18;
803 so_snd->sb_cc += 18;
804 tcp_sockclosed(sototcpcb(so));
805 return 0;
806 }
807 if ((ns=socreate()) == NULL)
808 return 0;
809 if (tcp_attach(ns)<0) {
810 free(ns);
811 return 0;
812 }
813
814 ns->so_laddr=so->so_laddr;
815 ns->so_lport=htons(port);
816
817 (void) tcp_mss(sototcpcb(ns), 0);
818
819 ns->so_faddr=so->so_faddr;
820 ns->so_fport=htons(IPPORT_RESERVED-1); /* Use a fake port. */
821
822 if (ns->so_faddr.s_addr == 0 ||
823 ns->so_faddr.s_addr == loopback_addr.s_addr)
824 ns->so_faddr = alias_addr;
825
826 ns->so_iptos = tcp_tos(ns);
827 tp = sototcpcb(ns);
828
829 tcp_template(tp);
830
831 /* Compute window scaling to request. */
832 /* while (tp->request_r_scale < TCP_MAX_WINSHIFT &&
833 * (TCP_MAXWIN << tp->request_r_scale) < so->so_rcv.sb_hiwat)
834 * tp->request_r_scale++;
835 */
836
837 /*soisfconnecting(ns);*/
838
839 tcpstat.tcps_connattempt++;
840
841 tp->t_state = TCPS_SYN_SENT;
842 tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT;
843 tp->iss = tcp_iss;
844 tcp_iss += TCP_ISSINCR/2;
845 tcp_sendseqinit(tp);
846 tcp_output(tp);
847 so->extra=ns;
848 }
849 while (ptr < so_rcv->sb_wptr) {
850 if (*ptr++ == 0) {
851 n++;
852 if (n == 2) {
853 user=ptr;
854 } else if (n == 3) {
855 args=ptr;
856 }
857 }
858 }
859
860 if (n != 4)
861 return 0;
862
863 rsh_exec(so,so->extra, user, inet_ntoa(so->so_faddr), args);
864 so->so_emu = 0;
865 so->extra=NULL;
866
867 /* And finally, send the client a 0 character */
868 so_snd->sb_wptr[0] = 0;
869 so_snd->sb_wptr++;
870 so_snd->sb_cc++;
871
872 return 0;
873 }
874
875 case EMU_CTL:
876 {
877 int num;
878 struct sbuf *so_snd = &so->so_snd;
879 struct sbuf *so_rcv = &so->so_rcv;
880
881 /*
882 * If there is binary data here, we save it in so->so_m
883 */
884 if (!so->so_m) {
885 int rxlen;
886 char *rxdata;
887 rxdata=mtod(m, char *);
888 for (rxlen=m->m_len; rxlen; rxlen--) {
889 if (*rxdata++ & 0x80) {
890 so->so_m = m;
891 return 0;
892 }
893 }
894 } /* if(so->so_m==NULL) */
895
896 /*
897 * Append the line
898 */
899 sbappendsb(so_rcv, m);
900
901 /* To avoid going over the edge of the buffer, we reset it */
902 if (so_snd->sb_cc == 0)
903 so_snd->sb_wptr = so_snd->sb_rptr = so_snd->sb_data;
904
905 /*
906 * A bit of a hack:
907 * If the first packet we get here is 1 byte long, then it
908 * was done in telnet character mode, therefore we must echo
909 * the characters as they come. Otherwise, we echo nothing,
910 * because in linemode, the line is already echoed
911 * XXX two or more control connections won't work
912 */
913 if (do_echo == -1) {
914 if (m->m_len == 1) do_echo = 1;
915 else do_echo = 0;
916 }
917 if (do_echo) {
918 sbappendsb(so_snd, m);
919 m_free(m);
920 tcp_output(sototcpcb(so)); /* XXX */
921 } else
922 m_free(m);
923
924 num = 0;
925 while (num < so->so_rcv.sb_cc) {
926 if (*(so->so_rcv.sb_rptr + num) == '\n' ||
927 *(so->so_rcv.sb_rptr + num) == '\r') {
928 int n;
929
930 *(so_rcv->sb_rptr + num) = 0;
931 if (ctl_password && !ctl_password_ok) {
932 /* Need a password */
933 if (sscanf(so_rcv->sb_rptr, "pass %256s", buff) == 1) {
934 if (strcmp(buff, ctl_password) == 0) {
935 ctl_password_ok = 1;
936 n = sprintf(so_snd->sb_wptr,
937 "Password OK.\r\n");
938 goto do_prompt;
939 }
940 }
941 n = sprintf(so_snd->sb_wptr,
942 "Error: Password required, log on with \"pass PASSWORD\"\r\n");
943 goto do_prompt;
944 }
945 cfg_quitting = 0;
946 n = do_config(so_rcv->sb_rptr, so, PRN_SPRINTF);
947 if (!cfg_quitting) {
948 /* Register the printed data */
949do_prompt:
950 so_snd->sb_cc += n;
951 so_snd->sb_wptr += n;
952 /* Add prompt */
953 n = sprintf(so_snd->sb_wptr, "Slirp> ");
954 so_snd->sb_cc += n;
955 so_snd->sb_wptr += n;
956 }
957 /* Drop so_rcv data */
958 so_rcv->sb_cc = 0;
959 so_rcv->sb_wptr = so_rcv->sb_rptr = so_rcv->sb_data;
960 tcp_output(sototcpcb(so)); /* Send the reply */
961 }
962 num++;
963 }
964 return 0;
965 }
966#endif
967 case EMU_FTP: /* ftp */
968 *(m->m_data+m->m_len) = 0; /* NULL terminate for strstr */
969 if ((bptr = (char *)strstr(m->m_data, "ORT")) != NULL) {
970 /*
971 * Need to emulate the PORT command
972 */
973 x = sscanf(bptr, "ORT %u,%u,%u,%u,%u,%u\r\n%256[^\177]",
974 &n1, &n2, &n3, &n4, &n5, &n6, buff);
975 if (x < 6)
976 return 1;
977
978 laddr = htonl((n1 << 24) | (n2 << 16) | (n3 << 8) | (n4));
979 lport = htons((n5 << 8) | (n6));
980
981 if ((so = solisten(pData, 0, laddr, lport, SS_FACCEPTONCE)) == NULL)
982 return 1;
983
984 n6 = ntohs(so->so_fport);
985
986 n5 = (n6 >> 8) & 0xff;
987 n6 &= 0xff;
988
989 laddr = ntohl(so->so_faddr.s_addr);
990
991 n1 = ((laddr >> 24) & 0xff);
992 n2 = ((laddr >> 16) & 0xff);
993 n3 = ((laddr >> 8) & 0xff);
994 n4 = (laddr & 0xff);
995
996 m->m_len = bptr - m->m_data; /* Adjust length */
997 m->m_len += sprintf(bptr,"ORT %d,%d,%d,%d,%d,%d\r\n%s",
998 n1, n2, n3, n4, n5, n6, x==7?buff:"");
999 return 1;
1000 } else if ((bptr = (char *)strstr(m->m_data, "27 Entering")) != NULL) {
1001 /*
1002 * Need to emulate the PASV response
1003 */
1004 x = sscanf(bptr, "27 Entering Passive Mode (%u,%u,%u,%u,%u,%u)\r\n%256[^\177]",
1005 &n1, &n2, &n3, &n4, &n5, &n6, buff);
1006 if (x < 6)
1007 return 1;
1008
1009 laddr = htonl((n1 << 24) | (n2 << 16) | (n3 << 8) | (n4));
1010 lport = htons((n5 << 8) | (n6));
1011
1012 if ((so = solisten(pData, 0, laddr, lport, SS_FACCEPTONCE)) == NULL)
1013 return 1;
1014
1015 n6 = ntohs(so->so_fport);
1016
1017 n5 = (n6 >> 8) & 0xff;
1018 n6 &= 0xff;
1019
1020 laddr = ntohl(so->so_faddr.s_addr);
1021
1022 n1 = ((laddr >> 24) & 0xff);
1023 n2 = ((laddr >> 16) & 0xff);
1024 n3 = ((laddr >> 8) & 0xff);
1025 n4 = (laddr & 0xff);
1026
1027 m->m_len = bptr - m->m_data; /* Adjust length */
1028 m->m_len += sprintf(bptr,"27 Entering Passive Mode (%d,%d,%d,%d,%d,%d)\r\n%s",
1029 n1, n2, n3, n4, n5, n6, x==7?buff:"");
1030
1031 return 1;
1032 }
1033
1034 return 1;
1035
1036 case EMU_KSH:
1037 /*
1038 * The kshell (Kerberos rsh) and shell services both pass
1039 * a local port port number to carry signals to the server
1040 * and stderr to the client. It is passed at the beginning
1041 * of the connection as a NUL-terminated decimal ASCII string.
1042 */
1043 so->so_emu = 0;
1044 for (lport = 0, i = 0; i < m->m_len-1; ++i) {
1045 if (m->m_data[i] < '0' || m->m_data[i] > '9')
1046 return 1; /* invalid number */
1047 lport *= 10;
1048 lport += m->m_data[i] - '0';
1049 }
1050 if (m->m_data[m->m_len-1] == '\0' && lport != 0 &&
1051 (so = solisten(pData, 0, so->so_laddr.s_addr, htons(lport), SS_FACCEPTONCE)) != NULL)
1052 m->m_len = sprintf(m->m_data, "%d", ntohs(so->so_fport))+1;
1053 return 1;
1054
1055 case EMU_IRC:
1056 /*
1057 * Need to emulate DCC CHAT, DCC SEND and DCC MOVE
1058 */
1059 *(m->m_data+m->m_len) = 0; /* NULL terminate the string for strstr */
1060 if ((bptr = (char *)strstr(m->m_data, "DCC")) == NULL)
1061 return 1;
1062
1063 /* The %256s is for the broken mIRC */
1064 if (sscanf(bptr, "DCC CHAT %256s %u %u", buff, &laddr, &lport) == 3) {
1065 if ((so = solisten(pData, 0, htonl(laddr), htons(lport), SS_FACCEPTONCE)) == NULL)
1066 return 1;
1067
1068 m->m_len = bptr - m->m_data; /* Adjust length */
1069 m->m_len += sprintf(bptr, "DCC CHAT chat %lu %u%c\n",
1070 (unsigned long)ntohl(so->so_faddr.s_addr),
1071 ntohs(so->so_fport), 1);
1072 } else if (sscanf(bptr, "DCC SEND %256s %u %u %u", buff, &laddr, &lport, &n1) == 4) {
1073 if ((so = solisten(pData, 0, htonl(laddr), htons(lport), SS_FACCEPTONCE)) == NULL)
1074 return 1;
1075
1076 m->m_len = bptr - m->m_data; /* Adjust length */
1077 m->m_len += sprintf(bptr, "DCC SEND %s %lu %u %u%c\n",
1078 buff, (unsigned long)ntohl(so->so_faddr.s_addr),
1079 ntohs(so->so_fport), n1, 1);
1080 } else if (sscanf(bptr, "DCC MOVE %256s %u %u %u", buff, &laddr, &lport, &n1) == 4) {
1081 if ((so = solisten(pData, 0, htonl(laddr), htons(lport), SS_FACCEPTONCE)) == NULL)
1082 return 1;
1083
1084 m->m_len = bptr - m->m_data; /* Adjust length */
1085 m->m_len += sprintf(bptr, "DCC MOVE %s %lu %u %u%c\n",
1086 buff, (unsigned long)ntohl(so->so_faddr.s_addr),
1087 ntohs(so->so_fport), n1, 1);
1088 }
1089 return 1;
1090
1091#ifdef VBOX
1092 /** @todo Disabled EMU_REALAUDIO, because it uses a static variable.
1093 * This is not legal when more than one slirp instance is active. */
1094#else /* !VBOX */
1095 case EMU_REALAUDIO:
1096 /*
1097 * RealAudio emulation - JP. We must try to parse the incoming
1098 * data and try to find the two characters that contain the
1099 * port number. Then we redirect an udp port and replace the
1100 * number with the real port we got.
1101 *
1102 * The 1.0 beta versions of the player are not supported
1103 * any more.
1104 *
1105 * A typical packet for player version 1.0 (release version):
1106 *
1107 * 0000:50 4E 41 00 05
1108 * 0000:00 01 00 02 1B D7 00 00 67 E6 6C DC 63 00 12 50 .....×..gælÜc..P
1109 * 0010:4E 43 4C 49 45 4E 54 20 31 30 31 20 41 4C 50 48 NCLIENT 101 ALPH
1110 * 0020:41 6C 00 00 52 00 17 72 61 66 69 6C 65 73 2F 76 Al..R..rafiles/v
1111 * 0030:6F 61 2F 65 6E 67 6C 69 73 68 5F 2E 72 61 79 42 oa/english_.rayB
1112 *
1113 * Now the port number 0x1BD7 is found at offset 0x04 of the
1114 * Now the port number 0x1BD7 is found at offset 0x04 of the
1115 * second packet. This time we received five bytes first and
1116 * then the rest. You never know how many bytes you get.
1117 *
1118 * A typical packet for player version 2.0 (beta):
1119 *
1120 * 0000:50 4E 41 00 06 00 02 00 00 00 01 00 02 1B C1 00 PNA...........Á.
1121 * 0010:00 67 75 78 F5 63 00 0A 57 69 6E 32 2E 30 2E 30 .guxõc..Win2.0.0
1122 * 0020:2E 35 6C 00 00 52 00 1C 72 61 66 69 6C 65 73 2F .5l..R..rafiles/
1123 * 0030:77 65 62 73 69 74 65 2F 32 30 72 65 6C 65 61 73 website/20releas
1124 * 0040:65 2E 72 61 79 53 00 00 06 36 42 e.rayS...6B
1125 *
1126 * Port number 0x1BC1 is found at offset 0x0d.
1127 *
1128 * This is just a horrible switch statement. Variable ra tells
1129 * us where we're going.
1130 */
1131
1132 bptr = m->m_data;
1133 while (bptr < m->m_data + m->m_len) {
1134 u_short p;
1135 static int ra = 0;
1136 char ra_tbl[4];
1137
1138 ra_tbl[0] = 0x50;
1139 ra_tbl[1] = 0x4e;
1140 ra_tbl[2] = 0x41;
1141 ra_tbl[3] = 0;
1142
1143 switch (ra) {
1144 case 0:
1145 case 2:
1146 case 3:
1147 if (*bptr++ != ra_tbl[ra]) {
1148 ra = 0;
1149 continue;
1150 }
1151 break;
1152
1153 case 1:
1154 /*
1155 * We may get 0x50 several times, ignore them
1156 */
1157 if (*bptr == 0x50) {
1158 ra = 1;
1159 bptr++;
1160 continue;
1161 } else if (*bptr++ != ra_tbl[ra]) {
1162 ra = 0;
1163 continue;
1164 }
1165 break;
1166
1167 case 4:
1168 /*
1169 * skip version number
1170 */
1171 bptr++;
1172 break;
1173
1174 case 5:
1175 /*
1176 * The difference between versions 1.0 and
1177 * 2.0 is here. For future versions of
1178 * the player this may need to be modified.
1179 */
1180 if (*(bptr + 1) == 0x02)
1181 bptr += 8;
1182 else
1183 bptr += 4;
1184 break;
1185
1186 case 6:
1187 /* This is the field containing the port
1188 * number that RA-player is listening to.
1189 */
1190 lport = (((u_char*)bptr)[0] << 8)
1191 + ((u_char *)bptr)[1];
1192 if (lport < 6970)
1193 lport += 256; /* don't know why */
1194 if (lport < 6970 || lport > 7170)
1195 return 1; /* failed */
1196
1197 /* try to get udp port between 6970 - 7170 */
1198 for (p = 6970; p < 7071; p++) {
1199 if (udp_listen( htons(p),
1200 so->so_laddr.s_addr,
1201 htons(lport),
1202 SS_FACCEPTONCE)) {
1203 break;
1204 }
1205 }
1206 if (p == 7071)
1207 p = 0;
1208 *(u_char *)bptr++ = (p >> 8) & 0xff;
1209 *(u_char *)bptr++ = p & 0xff;
1210 ra = 0;
1211 return 1; /* port redirected, we're done */
1212 break;
1213
1214 default:
1215 ra = 0;
1216 }
1217 ra++;
1218 }
1219 return 1;
1220#endif /* !VBOX */
1221
1222 default:
1223 /* Ooops, not emulated, won't call tcp_emu again */
1224 so->so_emu = 0;
1225 return 1;
1226 }
1227}
1228
1229/*
1230 * Do misc. config of SLiRP while its running.
1231 * Return 0 if this connections is to be closed, 1 otherwise,
1232 * return 2 if this is a command-line connection
1233 */
1234int
1235tcp_ctl(PNATState pData, struct socket *so)
1236{
1237 struct sbuf *sb = &so->so_snd;
1238 int command;
1239 struct ex_list *ex_ptr;
1240 int do_pty;
1241 /* struct socket *tmpso; */
1242
1243 DEBUG_CALL("tcp_ctl");
1244 DEBUG_ARG("so = %lx", (long )so);
1245
1246#if 0
1247 /*
1248 * Check if they're authorised
1249 */
1250 if (ctl_addr.s_addr && (ctl_addr.s_addr == -1 || (so->so_laddr.s_addr != ctl_addr.s_addr))) {
1251 sb->sb_cc = sprintf(sb->sb_wptr,"Error: Permission denied.\r\n");
1252 sb->sb_wptr += sb->sb_cc;
1253 return 0;
1254 }
1255#endif
1256 command = (ntohl(so->so_faddr.s_addr) & 0xff);
1257
1258 switch(command) {
1259 default: /* Check for exec's */
1260
1261 /*
1262 * Check if it's pty_exec
1263 */
1264 for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
1265 if (ex_ptr->ex_fport == so->so_fport &&
1266 command == ex_ptr->ex_addr) {
1267 do_pty = ex_ptr->ex_pty;
1268 goto do_exec;
1269 }
1270 }
1271
1272 /*
1273 * Nothing bound..
1274 */
1275 /* tcp_fconnect(so); */
1276
1277 /* FALLTHROUGH */
1278 case CTL_ALIAS:
1279 sb->sb_cc = sprintf(sb->sb_wptr,
1280 "Error: No application configured.\r\n");
1281 sb->sb_wptr += sb->sb_cc;
1282 return(0);
1283
1284 do_exec:
1285 DEBUG_MISC((dfd, " executing %s \n",ex_ptr->ex_exec));
1286 return(fork_exec(pData, so, ex_ptr->ex_exec, do_pty));
1287
1288#if 0
1289 case CTL_CMD:
1290 for (tmpso = tcb.so_next; tmpso != &tcb; tmpso = tmpso->so_next) {
1291 if (tmpso->so_emu == EMU_CTL &&
1292 !(tmpso->so_tcpcb?
1293 (tmpso->so_tcpcb->t_state & (TCPS_TIME_WAIT|TCPS_LAST_ACK))
1294 :0)) {
1295 /* Ooops, control connection already active */
1296 sb->sb_cc = sprintf(sb->sb_wptr,"Sorry, already connected.\r\n");
1297 sb->sb_wptr += sb->sb_cc;
1298 return 0;
1299 }
1300 }
1301 so->so_emu = EMU_CTL;
1302 ctl_password_ok = 0;
1303 sb->sb_cc = sprintf(sb->sb_wptr, "Slirp command-line ready (type \"help\" for help).\r\nSlirp> ");
1304 sb->sb_wptr += sb->sb_cc;
1305 do_echo=-1;
1306 return(2);
1307#endif
1308 }
1309}
1310
1311#if SIZEOF_CHAR_P != 4
1312/**
1313 * Slow pointer hashing that deals with automatic inserting and collisions.
1314 */
1315uint32_t VBoxU32PtrHashSlow(PNATState pData, void *pv)
1316{
1317 uint32_t i;
1318 if (pv == NULL)
1319 i = 0;
1320 else
1321 {
1322 const uint32_t i1 = ((uintptr_t)pv >> 3) % RT_ELEMENTS(pData->apvHash);
1323 if (pData->apvHash[i1] == pv)
1324 i = i1;
1325 else
1326 {
1327 /*
1328 * Try up to 10 times then assume it's an insertion.
1329 * If we didn't find a free entry by then, try another 100 times.
1330 * If that fails, give up.
1331 */
1332 const uint32_t i2 = ((uintptr_t)pv >> 2) % 7867;
1333 uint32_t i1stFree = pData->apvHash[i1] ? 0 : i1;
1334 int cTries = 10;
1335 int cTries2 = 100;
1336
1337 i = i1;
1338 for (;;)
1339 {
1340 /* check if we should give in.*/
1341 if (--cTries > 0)
1342 {
1343 if (i1stFree != 0)
1344 {
1345 i = i1stFree;
1346 pData->apvHash[i] = pv;
1347 pData->cpvHashUsed++;
1348 if (i != i1)
1349 pData->cpvHashCollisions++;
1350 pData->cpvHashInserts++;
1351 break;
1352 }
1353 if (!cTries2)
1354 {
1355 AssertReleaseMsgFailed(("NAT pointer hash error. pv=%p cpvHashUsed=%d cpvHashCollisions=%u\n",
1356 pv, pData->cpvHashUsed, pData->cpvHashCollisions));
1357 i = 0;
1358 break;
1359 }
1360 cTries = cTries2;
1361 cTries2 = 0;
1362 }
1363
1364 /* advance to the next hash entry and test it. */
1365 i = (i + i2) % RT_ELEMENTS(pData->apvHash);
1366 while (RT_UNLIKELY(!i))
1367 i = (i + i2) % RT_ELEMENTS(pData->apvHash);
1368 if (pData->apvHash[i] == pv)
1369 break;
1370 if (RT_UNLIKELY(!i1stFree && !pData->apvHash[i]))
1371 i1stFree = i;
1372 }
1373 }
1374 }
1375 return i;
1376}
1377
1378
1379/**
1380 * Removes the pointer from the hash table.
1381 */
1382void VBoxU32PtrDone(PNATState pData, void *pv, uint32_t iHint)
1383{
1384 /* We don't count NULL pointers. */
1385 if (pv == NULL)
1386 return;
1387 pData->cpvHashDone++;
1388
1389 /* try the hint */
1390 if ( iHint
1391 && iHint < RT_ELEMENTS(pData->apvHash)
1392 && pData->apvHash[iHint] == pv)
1393 {
1394 pData->apvHash[iHint] = NULL;
1395 pData->cpvHashUsed--;
1396 return;
1397 }
1398
1399 iHint = ((uintptr_t)pv >> 3) % RT_ELEMENTS(pData->apvHash);
1400 if (RT_UNLIKELY(pData->apvHash[iHint] != pv))
1401 {
1402 /*
1403 * Try up to 120 times then assert.
1404 */
1405 const uint32_t i2 = ((uintptr_t)pv >> 2) % 7867;
1406 int cTries = 120;
1407 for (;;)
1408 {
1409 /* advance to the next hash entry and test it. */
1410 iHint = (iHint + i2) % RT_ELEMENTS(pData->apvHash);
1411 while (RT_UNLIKELY(!iHint))
1412 iHint = (iHint + i2) % RT_ELEMENTS(pData->apvHash);
1413 if (pData->apvHash[iHint] == pv)
1414 break;
1415
1416 /* check if we should give in.*/
1417 if (--cTries > 0)
1418 {
1419 AssertReleaseMsgFailed(("NAT pointer hash error. pv=%p cpvHashUsed=%u cpvHashCollisions=%u\n",
1420 pv, pData->cpvHashUsed, pData->cpvHashCollisions));
1421 return;
1422 }
1423 }
1424 }
1425
1426 /* found it */
1427 pData->apvHash[iHint] = NULL;
1428 pData->cpvHashUsed--;
1429}
1430
1431#endif
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