VirtualBox

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

Last change on this file since 59350 was 58631, checked in by vboxsync, 9 years ago

NAT: tcp_fconnect - when DNS proxy is enabled and the target is
port 53 of CTL_DNS, connect to the first resolver in the list in a
kind of reverse port-forwarding. This makes fallback to TCP work with
DNS proxy when reply doesn't fit into UDP 512 bytes payload.

Currently when we have more than one resolver we only forward to the
first one and don't try others.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 19.3 KB
Line 
1/* $Id: tcp_subr.c 58631 2015-11-10 12:10:28Z vboxsync $ */
2/** @file
3 * NAT - TCP support.
4 */
5
6/*
7 * Copyright (C) 2006-2015 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18/*
19 * This code is based on:
20 *
21 * Copyright (c) 1982, 1986, 1988, 1990, 1993
22 * The Regents of the University of California. All rights reserved.
23 *
24 * Redistribution and use in source and binary forms, with or without
25 * modification, are permitted provided that the following conditions
26 * are met:
27 * 1. Redistributions of source code must retain the above copyright
28 * notice, this list of conditions and the following disclaimer.
29 * 2. Redistributions in binary form must reproduce the above copyright
30 * notice, this list of conditions and the following disclaimer in the
31 * documentation and/or other materials provided with the distribution.
32 * 3. All advertising materials mentioning features or use of this software
33 * must display the following acknowledgement:
34 * This product includes software developed by the University of
35 * California, Berkeley and its contributors.
36 * 4. Neither the name of the University nor the names of its contributors
37 * may be used to endorse or promote products derived from this software
38 * without specific prior written permission.
39 *
40 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
41 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
43 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
44 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
45 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
46 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
48 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
49 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
50 * SUCH DAMAGE.
51 *
52 * @(#)tcp_subr.c 8.1 (Berkeley) 6/10/93
53 * tcp_subr.c,v 1.5 1994/10/08 22:39:58 phk Exp
54 */
55
56/*
57 * Changes and additions relating to SLiRP
58 * Copyright (c) 1995 Danny Gasparovski.
59 *
60 * Please read the file COPYRIGHT for the
61 * terms and conditions of the copyright.
62 */
63
64#include <slirp.h>
65
66
67/*
68 * Tcp initialization
69 */
70void
71tcp_init(PNATState pData)
72{
73 tcp_iss = 1; /* wrong */
74 tcb.so_next = tcb.so_prev = &tcb;
75 tcp_last_so = &tcb;
76 tcp_reass_maxqlen = 48;
77 tcp_reass_maxseg = 256;
78}
79
80/*
81 * Create template to be used to send tcp packets on a connection.
82 * Call after host entry created, fills
83 * in a skeletal tcp/ip header, minimizing the amount of work
84 * necessary when the connection is used.
85 */
86/* struct tcpiphdr * */
87void
88tcp_template(struct tcpcb *tp)
89{
90 struct socket *so = tp->t_socket;
91 register struct tcpiphdr *n = &tp->t_template;
92
93 memset(n->ti_x1, 0, 9);
94 n->ti_pr = IPPROTO_TCP;
95 n->ti_len = RT_H2N_U16(sizeof (struct tcpiphdr) - sizeof (struct ip));
96 n->ti_src = so->so_faddr;
97 n->ti_dst = so->so_laddr;
98 n->ti_sport = so->so_fport;
99 n->ti_dport = so->so_lport;
100
101 n->ti_seq = 0;
102 n->ti_ack = 0;
103 n->ti_x2 = 0;
104 n->ti_off = 5;
105 n->ti_flags = 0;
106 n->ti_win = 0;
107 n->ti_sum = 0;
108 n->ti_urp = 0;
109}
110
111/*
112 * Send a single message to the TCP at address specified by
113 * the given TCP/IP header. If m == 0, then we make a copy
114 * of the tcpiphdr at ti and send directly to the addressed host.
115 * This is used to force keep alive messages out using the TCP
116 * template for a connection tp->t_template. If flags are given
117 * then we send a message back to the TCP which originated the
118 * segment ti, and discard the mbuf containing it and any other
119 * attached mbufs.
120 *
121 * In any case the ack and sequence number of the transmitted
122 * segment are as specified by the parameters.
123 */
124void
125tcp_respond(PNATState pData, struct tcpcb *tp, struct tcpiphdr *ti, struct mbuf *m, tcp_seq ack, tcp_seq seq, int flags)
126{
127 register int tlen;
128
129 LogFlowFunc(("ENTER: tp = %R[tcpcb793], ti = %lx, m = %lx, ack = %u, seq = %u, flags = %x\n",
130 tp, (long)ti, (long)m, ack, seq, flags));
131
132 if (m == 0)
133 {
134 if ((m = m_gethdr(pData, M_DONTWAIT, MT_HEADER)) == NULL)
135 return;
136#ifdef TCP_COMPAT_42
137 tlen = 1;
138#else
139 tlen = 0;
140#endif
141 m->m_data += if_maxlinkhdr;
142 m->m_pkthdr.header = mtod(m, void *);
143 *mtod(m, struct tcpiphdr *) = *ti;
144 ti = mtod(m, struct tcpiphdr *);
145 flags = TH_ACK;
146 }
147 else
148 {
149 /*
150 * ti points into m so the next line is just making
151 * the mbuf point to ti
152 */
153 m->m_data = (caddr_t)ti;
154
155 m->m_len = sizeof (struct tcpiphdr);
156 tlen = 0;
157#define xchg(a,b,type) { type t; t = a; a = b; b = t; }
158 xchg(ti->ti_dst.s_addr, ti->ti_src.s_addr, u_int32_t);
159 xchg(ti->ti_dport, ti->ti_sport, u_int16_t);
160#undef xchg
161 }
162 ti->ti_len = RT_H2N_U16((u_short)(sizeof (struct tcphdr) + tlen));
163 tlen += sizeof (struct tcpiphdr);
164 m->m_len = tlen;
165
166 memset(ti->ti_x1, 0, 9);
167 ti->ti_seq = RT_H2N_U32(seq);
168 ti->ti_ack = RT_H2N_U32(ack);
169 ti->ti_x2 = 0;
170 ti->ti_off = sizeof (struct tcphdr) >> 2;
171 ti->ti_flags = flags;
172 if (tp)
173 {
174 int win = sbspace(&tp->t_socket->so_rcv);
175 ti->ti_win = RT_H2N_U16((u_int16_t) (win >> tp->rcv_scale));
176 }
177 else
178 ti->ti_win = 0;
179 ti->ti_urp = 0;
180 ti->ti_sum = 0;
181 ti->ti_sum = cksum(m, tlen);
182 ((struct ip *)ti)->ip_len = tlen;
183
184 if(flags & TH_RST)
185 ((struct ip *)ti)->ip_ttl = MAXTTL;
186 else
187 ((struct ip *)ti)->ip_ttl = ip_defttl;
188
189 (void) ip_output(pData, (struct socket *)0, m);
190}
191
192/*
193 * Create a new TCP control block, making an
194 * empty reassembly queue and hooking it to the argument
195 * protocol control block.
196 */
197struct tcpcb *
198tcp_newtcpcb(PNATState pData, struct socket *so)
199{
200 register struct tcpcb *tp;
201
202 tp = (struct tcpcb *)RTMemAllocZ(sizeof(*tp));
203 if (tp == NULL)
204 return ((struct tcpcb *)0);
205
206 tp->t_maxseg = tcp_mssdflt;
207
208 tp->t_flags = tcp_do_rfc1323 ? (TF_REQ_SCALE|TF_REQ_TSTMP) : 0;
209 tp->t_socket = so;
210
211 /*
212 * Init srtt to TCPTV_SRTTBASE (0), so we can tell that we have no
213 * rtt estimate. Set rttvar so that srtt + 2 * rttvar gives
214 * reasonable initial retransmit time.
215 */
216 tp->t_srtt = TCPTV_SRTTBASE;
217 tp->t_rttvar = tcp_rttdflt * PR_SLOWHZ << 2;
218 tp->t_rttmin = TCPTV_MIN;
219
220 TCPT_RANGESET(tp->t_rxtcur,
221 ((TCPTV_SRTTBASE >> 2) + (TCPTV_SRTTDFLT << 2)) >> 1,
222 TCPTV_MIN, TCPTV_REXMTMAX);
223
224 tp->snd_cwnd = TCP_MAXWIN << TCP_MAX_WINSHIFT;
225 tp->snd_ssthresh = TCP_MAXWIN << TCP_MAX_WINSHIFT;
226 TCP_STATE_SWITCH_TO(tp, TCPS_CLOSED);
227
228 so->so_tcpcb = tp;
229 so->so_type = IPPROTO_TCP;
230
231 return (tp);
232}
233
234/*
235 * Drop a TCP connection, reporting
236 * the specified error. If connection is synchronized,
237 * then send a RST to peer.
238 */
239struct tcpcb *tcp_drop(PNATState pData, struct tcpcb *tp, int err)
240{
241/* tcp_drop(tp, errno)
242 register struct tcpcb *tp;
243 int errno;
244{
245*/
246 int fUninitiolizedTemplate = 0;
247#ifndef LOG_ENABLED
248 NOREF(err);
249#endif
250 LogFlowFunc(("ENTER: tp = %R[tcpcb793], errno = %d\n", tp, err));
251 fUninitiolizedTemplate = RT_BOOL(( tp
252 && ( tp->t_template.ti_src.s_addr == INADDR_ANY
253 || tp->t_template.ti_dst.s_addr == INADDR_ANY)));
254
255 if ( TCPS_HAVERCVDSYN(tp->t_state)
256 && !fUninitiolizedTemplate)
257 {
258 TCP_STATE_SWITCH_TO(tp, TCPS_CLOSED);
259 (void) tcp_output(pData, tp);
260 tcpstat.tcps_drops++;
261 }
262 else
263 tcpstat.tcps_conndrops++;
264#if 0
265 if (errno == ETIMEDOUT && tp->t_softerror)
266 errno = tp->t_softerror;
267
268 so->so_error = errno;
269#endif
270 return (tcp_close(pData, tp));
271}
272
273/*
274 * Close a TCP control block:
275 * discard all space held by the tcp
276 * discard internet protocol block
277 * wake up any sleepers
278 */
279struct tcpcb *
280tcp_close(PNATState pData, register struct tcpcb *tp)
281{
282 struct socket *so = tp->t_socket;
283
284 struct tseg_qent *te = NULL;
285 LogFlowFunc(("ENTER: tp = %R[tcpcb793]\n", tp));
286 /*XXX: freeing the reassembly queue */
287 while (!LIST_EMPTY(&tp->t_segq))
288 {
289 te = LIST_FIRST(&tp->t_segq);
290 LIST_REMOVE(te, tqe_q);
291 m_freem(pData, te->tqe_m);
292 RTMemFree(te);
293 tcp_reass_qsize--;
294 }
295 RTMemFree(tp);
296 so->so_tcpcb = 0;
297 soisfdisconnected(so);
298 /* clobber input socket cache if we're closing the cached connection */
299 if (so == tcp_last_so)
300 tcp_last_so = &tcb;
301 if (so->s != -1)
302 closesocket(so->s);
303 /* Avoid double free if the socket is listening and therefore doesn't have
304 * any sbufs reserved. */
305 if (!(so->so_state & SS_FACCEPTCONN))
306 {
307 sbfree(&so->so_rcv);
308 sbfree(&so->so_snd);
309 }
310 sofree(pData, so);
311 SOCKET_UNLOCK(so);
312 tcpstat.tcps_closed++;
313 return ((struct tcpcb *)0);
314}
315
316void
317tcp_drain()
318{
319 /* XXX */
320}
321
322/*
323 * When a source quench is received, close congestion window
324 * to one segment. We will gradually open it again as we proceed.
325 */
326
327#if 0
328
329void
330tcp_quench(i, int errno)
331{
332 struct tcpcb *tp = intotcpcb(inp);
333
334 if (tp)
335 tp->snd_cwnd = tp->t_maxseg;
336}
337
338#endif
339
340/*
341 * TCP protocol interface to socket abstraction.
342 */
343
344/*
345 * User issued close, and wish to trail through shutdown states:
346 * if never received SYN, just forget it. If got a SYN from peer,
347 * but haven't sent FIN, then go to FIN_WAIT_1 state to send peer a FIN.
348 * If already got a FIN from peer, then almost done; go to LAST_ACK
349 * state. In all other cases, have already sent FIN to peer (e.g.
350 * after PRU_SHUTDOWN), and just have to play tedious game waiting
351 * for peer to send FIN or not respond to keep-alives, etc.
352 * We can let the user exit from the close as soon as the FIN is acked.
353 */
354void
355tcp_sockclosed(PNATState pData, struct tcpcb *tp)
356{
357 LogFlowFunc(("ENTER: tp = %R[tcpcb793]\n", tp));
358 LogFunc(("tp->t_socket:%R[natsock]\n",tp->t_socket));
359
360 switch (tp->t_state)
361 {
362 case TCPS_CLOSED:
363 case TCPS_LISTEN:
364 case TCPS_SYN_SENT:
365 TCP_STATE_SWITCH_TO(tp, TCPS_CLOSED);
366 tp = tcp_close(pData, tp);
367 break;
368
369 case TCPS_SYN_RECEIVED:
370 case TCPS_ESTABLISHED:
371 TCP_STATE_SWITCH_TO(tp, TCPS_FIN_WAIT_1);
372 break;
373
374 case TCPS_CLOSE_WAIT:
375 TCP_STATE_SWITCH_TO(tp, TCPS_LAST_ACK);
376 break;
377 }
378/* soisfdisconnecting(tp->t_socket); */
379 if ( tp
380 && tp->t_state >= TCPS_FIN_WAIT_2)
381 soisfdisconnected(tp->t_socket);
382 /*
383 * (vasily) there're situations when the FIN or FIN,ACK are lost (Windows host)
384 * and retransmitting keeps VBox busy on sending closing sequences *very* frequent,
385 * easting a lot of CPU. To avoid this we don't sent on sockets marked as closed
386 * (see slirp.c for details about setting so_close member).
387 */
388 if ( tp
389 && tp->t_socket
390 && !tp->t_socket->so_close)
391 tcp_output(pData, tp);
392}
393
394/*
395 * Connect to a host on the Internet
396 * Called by tcp_input
397 * Only do a connect, the tcp fields will be set in tcp_input
398 * return 0 if there's a result of the connect,
399 * else return -1 means we're still connecting
400 * The return value is almost always -1 since the socket is
401 * nonblocking. Connect returns after the SYN is sent, and does
402 * not wait for ACK+SYN.
403 */
404int tcp_fconnect(PNATState pData, struct socket *so)
405{
406 int ret = 0;
407
408 LogFlowFunc(("ENTER: so = %R[natsock]\n", so));
409
410 if ((ret = so->s = socket(AF_INET, SOCK_STREAM, 0)) >= 0)
411 {
412 int opt, s = so->s;
413 struct sockaddr_in addr;
414
415 fd_nonblock(s);
416 opt = 1;
417 setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt));
418 opt = 1;
419 setsockopt(s, SOL_SOCKET, SO_OOBINLINE, (char *)&opt, sizeof(opt));
420
421 addr.sin_family = AF_INET;
422 if ((so->so_faddr.s_addr & RT_H2N_U32(pData->netmask)) == pData->special_addr.s_addr)
423 {
424 /* It's an alias */
425 switch(RT_N2H_U32(so->so_faddr.s_addr) & ~pData->netmask)
426 {
427 case CTL_DNS:
428 /*
429 * TCP DNS proxy. We only support "forwarding" to
430 * single server. We don't have infrastructure in
431 * place to re-try connections to other servers.
432 */
433 if ( pData->fUseDnsProxy
434 && so->so_fport == RT_H2N_U16_C(53))
435 {
436 struct dns_entry *ns = TAILQ_LAST(&pData->pDnsList, dns_list_head);
437 if (ns != NULL)
438 {
439 addr.sin_addr = ns->de_addr;
440 break;
441 }
442 }
443 /* FALLTHROUGH */
444 case CTL_ALIAS:
445 default:
446 addr.sin_addr = loopback_addr;
447 break;
448 }
449 }
450 else
451 addr.sin_addr = so->so_faddr;
452 addr.sin_port = so->so_fport;
453
454 Log2((" connect()ing, addr.sin_port=%d, addr.sin_addr.s_addr=%.16s\n",
455 RT_N2H_U16(addr.sin_port), inet_ntoa(addr.sin_addr)));
456 /* We don't care what port we get */
457 ret = connect(s,(struct sockaddr *)&addr,sizeof (addr));
458
459 /*
460 * If it's not in progress, it failed, so we just return 0,
461 * without clearing SS_NOFDREF
462 */
463 soisfconnecting(so);
464 }
465
466 return(ret);
467}
468
469/*
470 * Accept the socket and connect to the local-host
471 *
472 * We have a problem. The correct thing to do would be
473 * to first connect to the local-host, and only if the
474 * connection is accepted, then do an accept() here.
475 * But, a) we need to know who's trying to connect
476 * to the socket to be able to SYN the local-host, and
477 * b) we are already connected to the foreign host by
478 * the time it gets to accept(), so... We simply accept
479 * here and SYN the local-host.
480 */
481void
482tcp_connect(PNATState pData, struct socket *inso)
483{
484 struct socket *so;
485 struct sockaddr_in addr;
486 socklen_t addrlen = sizeof(struct sockaddr_in);
487 struct tcpcb *tp;
488 int s, opt;
489 int status;
490 socklen_t optlen;
491 static int cVerbose = 1;
492
493 LogFlowFunc(("ENTER: inso = %R[natsock]\n", inso));
494
495 if ( inso->so_laddr.s_addr == INADDR_ANY /* delayed port-forwarding? */
496 && pData->guest_addr_guess.s_addr == INADDR_ANY)
497 {
498 LogRel2(("NAT: Port-forward: guest address unknown for %R[natsock]\n", inso));
499 closesocket(accept(inso->s, NULL, NULL));
500 if (inso->so_state & SS_FACCEPTONCE)
501 tcp_close(pData, sototcpcb(inso));
502 return;
503 }
504
505 /*
506 * If it's an SS_ACCEPTONCE socket, no need to socreate()
507 * another socket, just use the accept() socket.
508 */
509 if (inso->so_state & SS_FACCEPTONCE)
510 {
511 /* FACCEPTONCE already have a tcpcb */
512 so = inso;
513 }
514 else
515 {
516 if ((so = socreate()) == NULL)
517 {
518 /* If it failed, get rid of the pending connection */
519 closesocket(accept(inso->s,(struct sockaddr *)&addr,&addrlen));
520 return;
521 }
522 if (tcp_attach(pData, so) < 0)
523 {
524 RTMemFree(so); /* NOT sofree */
525 return;
526 }
527 so->so_laddr = inso->so_laddr;
528 so->so_lport = inso->so_lport;
529 }
530
531 if (so->so_laddr.s_addr == INADDR_ANY)
532 {
533 LogRel2(("NAT: Port-forward: using %RTnaipv4 for %R[natsock]\n",
534 pData->guest_addr_guess.s_addr, inso));
535 so->so_laddr = pData->guest_addr_guess;
536 }
537
538 (void) tcp_mss(pData, sototcpcb(so), 0);
539
540 fd_nonblock(inso->s);
541 if ((s = accept(inso->s,(struct sockaddr *)&addr,&addrlen)) < 0)
542 {
543 tcp_close(pData, sototcpcb(so)); /* This will sofree() as well */
544 return;
545 }
546 fd_nonblock(s);
547 opt = 1;
548 setsockopt(s, SOL_SOCKET, SO_REUSEADDR,(char *)&opt, sizeof(int));
549 opt = 1;
550 setsockopt(s, SOL_SOCKET, SO_OOBINLINE,(char *)&opt, sizeof(int));
551#if 0
552 opt = 1;
553 setsockopt(s, IPPROTO_TCP, TCP_NODELAY,(char *)&opt, sizeof(int));
554#endif
555
556 optlen = sizeof(int);
557 status = getsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *)&opt, &optlen);
558 if (status < 0)
559 {
560 LogRel(("NAT: Error(%d) while getting RCV capacity\n", errno));
561 goto no_sockopt;
562 }
563 if (cVerbose > 0)
564 LogRel(("NAT: Old socket recv size: %dKB\n", opt / 1024));
565 /* @todo (r-vvl) make it configurable (via extra data) */
566 opt = pData->socket_rcv;
567 status = setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *)&opt, sizeof(int));
568 if (status < 0)
569 {
570 LogRel(("NAT: Error(%d) while setting RCV capacity to (%d)\n", errno, opt));
571 goto no_sockopt;
572 }
573 optlen = sizeof(int);
574 status = getsockopt(s, SOL_SOCKET, SO_SNDBUF, (char *)&opt, &optlen);
575 if (status < 0)
576 {
577 LogRel(("NAT: Error(%d) while getting SND capacity\n", errno));
578 goto no_sockopt;
579 }
580 if (cVerbose > 0)
581 LogRel(("NAT: Old socket send size: %dKB\n", opt / 1024));
582 opt = pData->socket_rcv;
583 status = setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char *)&opt, sizeof(int));
584 if (status < 0)
585 {
586 LogRel(("NAT: Error(%d) while setting SND capacity to (%d)\n", errno, opt));
587 goto no_sockopt;
588 }
589 if (cVerbose > 0)
590 cVerbose--;
591
592 no_sockopt:
593 so->so_fport = addr.sin_port;
594 so->so_faddr = addr.sin_addr;
595 /* Translate connections from localhost to the real hostname */
596 if (so->so_faddr.s_addr == 0 || so->so_faddr.s_addr == loopback_addr.s_addr)
597 so->so_faddr = alias_addr;
598
599 /* Close the accept() socket, set right state */
600 if (inso->so_state & SS_FACCEPTONCE)
601 {
602 closesocket(so->s); /* If we only accept once, close the accept() socket */
603 so->so_state = SS_NOFDREF; /* Don't select it yet, even though we have an FD */
604 /* if it's not FACCEPTONCE, it's already NOFDREF */
605 }
606 so->s = s;
607
608 tp = sototcpcb(so);
609
610 tcp_template(tp);
611
612 /* Compute window scaling to request. */
613/* while (tp->request_r_scale < TCP_MAX_WINSHIFT
614 * && (TCP_MAXWIN << tp->request_r_scale) < so->so_rcv.sb_hiwat)
615 * tp->request_r_scale++;
616 */
617
618/* soisconnecting(so); */ /* NOFDREF used instead */
619 tcpstat.tcps_connattempt++;
620
621 TCP_STATE_SWITCH_TO(tp, TCPS_SYN_SENT);
622 tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT;
623 tp->iss = tcp_iss;
624 tcp_iss += TCP_ISSINCR/2;
625 tcp_sendseqinit(tp);
626 tcp_output(pData, tp);
627}
628
629/*
630 * Attach a TCPCB to a socket.
631 */
632int
633tcp_attach(PNATState pData, struct socket *so)
634{
635 /* We're attaching already attached socket??? */
636 Assert(so->so_type == 0);
637 if ((so->so_tcpcb = tcp_newtcpcb(pData, so)) == NULL)
638 return -1;
639
640 SOCKET_LOCK_CREATE(so);
641 QSOCKET_LOCK(tcb);
642 insque(pData, so, &tcb);
643 NSOCK_INC();
644 QSOCKET_UNLOCK(tcb);
645 return 0;
646}
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