tcp_usrreq.c
上传用户:nvosite88
上传日期:2007-01-17
资源大小:4983k
文件大小:18k
源码类别:

VxWorks

开发平台:

C/C++

  1. /* tcp_usrreq.c - TCP interface routines */
  2. /* Copyright 1984 - 2002 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5.  * Copyright (c) 1982, 1986, 1988, 1993, 1995
  6.  * The Regents of the University of California.  All rights reserved.
  7.  *
  8.  * Redistribution and use in source and binary forms, with or without
  9.  * modification, are permitted provided that the following conditions
  10.  * are met:
  11.  * 1. Redistributions of source code must retain the above copyright
  12.  *    notice, this list of conditions and the following disclaimer.
  13.  * 2. Redistributions in binary form must reproduce the above copyright
  14.  *    notice, this list of conditions and the following disclaimer in the
  15.  *    documentation and/or other materials provided with the distribution.
  16.  * 3. All advertising materials mentioning features or use of this software
  17.  *    must display the following acknowledgement:
  18.  * This product includes software developed by the University of
  19.  * California, Berkeley and its contributors.
  20.  * 4. Neither the name of the University nor the names of its contributors
  21.  *    may be used to endorse or promote products derived from this software
  22.  *    without specific prior written permission.
  23.  *
  24.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  25.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  26.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  27.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  28.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  29.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  30.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  31.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  32.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  33.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  34.  * SUCH DAMAGE.
  35.  *
  36.  * @(#)tcp_usrreq.c 8.5 (Berkeley) 6/21/95
  37.  */
  38. /*
  39. modification history
  40. --------------------
  41. 03i,05jun02,vvv  fixed Nagle for large writes (SPR #72213)
  42. 03h,21mar02,wap  avoid making local port of TCP connection the same as
  43.                  the foreign port (SPR #73104)
  44. 03g,12oct01,rae  merge from truestack ver 03j, base 03e
  45. 03f,14nov00,ham  remoeved tcpstates declaration(SPR 62272).
  46. 03e,26aug98,n_s  added return val check for mBufClGet in tcp_ctloutput. 
  47.                  spr #22238.
  48. 03d,07jul97,vin  in tcp_usrreq case PRU_DETACH simplified.
  49. 03c,08mar97,vin  added changes to accomodate changes in pcb structure for
  50.  hash look ups.
  51. 03b,22nov96,vin  modified for cluster support, replace m_get(..) with 
  52.  mBufClGet(..).
  53. 03a,03mar96,vin  created from BSD4.4 stuff,integrated with 02o of tcp_usrreq.c.
  54. */
  55. /*
  56. DESCRIPTION
  57. */
  58. #include "vxWorks.h"
  59. #include "net/mbuf.h"
  60. #include "sys/socket.h"
  61. #include "net/socketvar.h"
  62. #include "net/protosw.h"
  63. #include "errno.h"
  64. #include "sys/stat.h"
  65. #include "net/if.h"
  66. #include "net/route.h"
  67. #include "netinet/in.h"
  68. #include "netinet/in_pcb.h"
  69. #include "netinet/in_systm.h"
  70. #include "netinet/in_var.h"
  71. #include "netinet/ip.h"
  72. #include "netinet/ip_var.h"
  73. #include "netinet/tcp.h"
  74. #include "netinet/tcp_fsm.h"
  75. #include "netinet/tcp_seq.h"
  76. #include "netinet/tcp_timer.h"
  77. #include "netinet/tcp_var.h"
  78. #include "netinet/tcpip.h"
  79. #include "netinet/tcp_debug.h"
  80. #include "net/systm.h"
  81. #ifdef WV_INSTRUMENTATION
  82. #ifdef INCLUDE_WVNET
  83. #include "wvNetLib.h"
  84. #endif
  85. #endif
  86. #ifdef VIRTUAL_STACK
  87. #include "netinet/vsLib.h"
  88. #else
  89. IMPORT int tcp_keepinit;
  90. #endif /* VIRTUAL_STACK */
  91. IMPORT unsigned long (*pTcpRandHook)(void);
  92. LOCAL void tcpTraceStub ();
  93. LOCAL void tcpReportStub ();
  94. VOIDFUNCPTR tcpTraceRtn = tcpTraceStub; /* exported */
  95. VOIDFUNCPTR tcpReportRtn = tcpReportStub; /* exported */
  96. /*
  97.  * TCP protocol interface to socket abstraction.
  98.  */
  99. #ifdef WV_INSTRUMENTATION
  100. #ifdef INCLUDE_WVNET
  101.     /* Set common fields of event identifiers for this module. */
  102. LOCAL UCHAR wvNetModuleId = WV_NET_TCPREQ_MODULE; /* Value for tcp_usrreq.c */
  103. LOCAL UCHAR wvNetLocalFilter = WV_NET_NONE;     /* Available event filter */
  104. LOCAL ULONG wvNetEventId;       /* Event identifier: see wvNetLib.h */
  105. #endif    /* INCLUDE_WVNET */
  106. #endif
  107. /*
  108.  * Process a TCP user request for TCP tb.  If this is a send request
  109.  * then m is the mbuf chain of send data.  If this is a timer expiration
  110.  * (called from the software clock routine), then timertype tells which timer.
  111.  */
  112. /*ARGSUSED*/
  113. int
  114. tcp_usrreq(so, req, m, nam, control)
  115. struct socket *so;
  116. int req;
  117. struct mbuf *m, *nam, *control;
  118. {
  119. register struct inpcb *inp;
  120. register struct tcpcb *tp = NULL;
  121. int s;
  122. int error = 0;
  123. int ostate;
  124. #ifdef WV_INSTRUMENTATION
  125. #ifdef INCLUDE_WVNET    /* WV_NET_INFO event */
  126.     WV_NET_MARKER_2 (NET_AUX_EVENT, WV_NET_INFO, 47, 8,
  127.                      WV_NETEVENT_TCPREQ_START, so->so_fd, req)
  128. #endif  /* INCLUDE_WVNET */
  129. #endif
  130. if (req == PRU_CONTROL)
  131. return (in_control(so, (u_long)m, (caddr_t)nam,
  132. (struct ifnet *)control));
  133. if (control && control->m_len) {
  134. m_freem(control);
  135. if (m)
  136. m_freem(m);
  137. #ifdef WV_INSTRUMENTATION
  138. #ifdef INCLUDE_WVNET    /* WV_NET_ERROR event */
  139.         WV_NET_MARKER_2 (NET_AUX_EVENT, WV_NET_ERROR, 38, 4,
  140.                          WV_NETEVENT_TCPREQ_BADMEM, so->so_fd, req)
  141. #endif  /* INCLUDE_WVNET */
  142. #endif
  143. return (EINVAL);
  144. }
  145. s = splnet();
  146. inp = sotoinpcb(so);
  147. /*
  148.  * When a TCP is attached to a socket, then there will be
  149.  * a (struct inpcb) pointed at by the socket, and this
  150.  * structure will point at a subsidary (struct tcpcb).
  151.  */
  152. if (inp == 0 && req != PRU_ATTACH) {
  153. splx(s);
  154. #if 0
  155. /*
  156.  * The following corrects an mbuf leak under rare
  157.  * circumstances, but has not been fully tested.
  158.  */
  159. if (m && req != PRU_SENSE)
  160. m_freem(m);
  161. #else
  162. /* safer version of fix for mbuf leak */
  163. if (m && (req == PRU_SEND || req == PRU_SENDOOB))
  164. m_freem(m);
  165. #endif
  166. #ifdef WV_INSTRUMENTATION
  167. #ifdef INCLUDE_WVNET    /* WV_NET_ERROR event */
  168.         WV_NET_MARKER_2 (NET_AUX_EVENT, WV_NET_ERROR, 39, 5,
  169.                          WV_NETEVENT_TCPREQ_NOPCB, so->so_fd, req)
  170. #endif  /* INCLUDE_WVNET */
  171. #endif
  172. return (EINVAL); /* XXX */
  173. }
  174. if (inp) {
  175. tp = intotcpcb(inp);
  176. /* WHAT IF TP IS 0? */
  177. #ifdef KPROF
  178. tcp_acounts[tp->t_state][req]++;
  179. #endif
  180. ostate = tp->t_state;
  181. } else
  182. ostate = 0;
  183. switch (req) {
  184. /*
  185.  * TCP attaches to socket via PRU_ATTACH, reserving space,
  186.  * and an internet control block.
  187.  */
  188. case PRU_ATTACH:
  189. if (inp) {
  190. error = EISCONN;
  191. break;
  192. }
  193. error = tcp_attach(so);
  194. if (error)
  195. break;
  196.                 /* TCP sockets use path MTU discovery by default. */
  197.                 so->so_options |= SO_USEPATHMTU;
  198. if ((so->so_options & SO_LINGER) && so->so_linger == 0)
  199. so->so_linger = TCP_LINGERTIME;
  200. tp = sototcpcb(so);
  201. break;
  202. /*
  203.  * PRU_DETACH detaches the TCP protocol from the socket.
  204.  * If the protocol state is non-embryonic, then can't
  205.  * do this directly: have to initiate a PRU_DISCONNECT,
  206.  * which may finish later; embryonic TCB's can just
  207.  * be discarded here.
  208.  */
  209. case PRU_DETACH:
  210.             tp = tcp_disconnect(tp);
  211.             break;
  212. /*
  213.  * Give the socket an address.
  214.  */
  215. case PRU_BIND:
  216. error = in_pcbbind(inp, nam);
  217. if (error)
  218. break;
  219. break;
  220. /*
  221.  * Prepare to accept connections.
  222.  */
  223. case PRU_LISTEN:
  224. if (inp->inp_lport == 0)
  225. error = in_pcbbind(inp, (struct mbuf *)0);
  226. if (error == 0)
  227. tp->t_state = TCPS_LISTEN;
  228. break;
  229. /*
  230.  * Initiate connection to peer.
  231.  * Create a template for use in transmissions on this connection.
  232.  * Enter SYN_SENT state, and mark socket as connecting.
  233.  * Start keep-alive timer, and seed output sequence space.
  234.  * Send initial segment on connection.
  235.  */
  236. case PRU_CONNECT:
  237. if (inp->inp_lport == 0) {
  238. error = in_pcbbind(inp, (struct mbuf *)0);
  239. if (error)
  240. break;
  241. /*
  242.  * Avoid case where ephemeral port for local
  243.  * side of connection is the same as destination
  244.  * port for foreign side.
  245.  */
  246. if (inp->inp_lport ==
  247.     (mtod (nam, struct sockaddr_in *))->sin_port)
  248.     {
  249. inp->inp_lport = 0;
  250. error = in_pcbbind (inp, (struct mbuf *)0);
  251. if (error)
  252. break;
  253.     }
  254. }
  255. error = in_pcbconnect(inp, nam);
  256. if (error)
  257. break;
  258. tp->t_template = tcp_template(tp);
  259. if (tp->t_template == 0) {
  260. in_pcbdisconnect(inp);
  261. error = ENOBUFS;
  262. break;
  263. }
  264. /* Compute window scaling to request.  */
  265. while (tp->request_r_scale < TCP_MAX_WINSHIFT &&
  266.     (TCP_MAXWIN << tp->request_r_scale) < so->so_rcv.sb_hiwat)
  267. tp->request_r_scale++;
  268. soisconnecting(so);
  269. tcpstat.tcps_connattempt++;
  270. tp->t_state = TCPS_SYN_SENT;
  271.                 tp->t_timer[TCPT_KEEP] = tcp_keepinit;
  272.       tp->iss = tcp_iss;
  273. tcp_iss += TCP_ISSINCR/4 + ((0x0000ffff) & (pTcpRandHook() >> 16));
  274. tcp_sendseqinit(tp);
  275. error = tcp_output(tp);
  276. break;
  277. /*
  278.  * Create a TCP connection between two sockets.
  279.  */
  280. case PRU_CONNECT2:
  281. error = EOPNOTSUPP;
  282. break;
  283. /*
  284.  * Initiate disconnect from peer.
  285.  * If connection never passed embryonic stage, just drop;
  286.  * else if don't need to let data drain, then can just drop anyways,
  287.  * else have to begin TCP shutdown process: mark socket disconnecting,
  288.  * drain unread data, state switch to reflect user close, and
  289.  * send segment (e.g. FIN) to peer.  Socket will be really disconnected
  290.  * when peer sends FIN and acks ours.
  291.  *
  292.  * SHOULD IMPLEMENT LATER PRU_CONNECT VIA REALLOC TCPCB.
  293.  */
  294. case PRU_DISCONNECT:
  295. tp = tcp_disconnect(tp);
  296. break;
  297. /*
  298.  * Accept a connection.  Essentially all the work is
  299.  * done at higher levels; just return the address
  300.  * of the peer, storing through addr.
  301.  */
  302. case PRU_ACCEPT:
  303. in_setpeeraddr(inp, nam);
  304. break;
  305. /*
  306.  * Mark the connection as being incapable of further output.
  307.  */
  308. case PRU_SHUTDOWN:
  309. socantsendmore(so);
  310. tp = tcp_usrclosed(tp);
  311. if (tp)
  312. error = tcp_output(tp);
  313. break;
  314. /*
  315.  * After a receive, possibly send window update to peer.
  316.  */
  317. case PRU_RCVD:
  318. (void) tcp_output(tp);
  319. break;
  320. /*
  321.  * Do a send by putting data in output queue and updating urgent
  322.  * marker if URG set.  Possibly send more data.
  323.  */
  324. case PRU_SEND:
  325. if (m->m_flags & M_EOB)
  326.     {
  327.     m->m_flags &= ~M_EOB;
  328.     tp->t_flags |= TF_EOB;
  329.     }
  330. sbappend(&so->so_snd, m);
  331. error = tcp_output(tp);
  332. tp->t_flags &= ~TF_EOB;
  333. break;
  334. /*
  335.  * Abort the TCP.
  336.  */
  337. case PRU_ABORT:
  338. tp = tcp_drop(tp, ECONNABORTED);
  339. break;
  340. case PRU_SENSE:
  341. ((struct stat *) m)->st_blksize = so->so_snd.sb_hiwat;
  342. (void) splx(s);
  343. return (0);
  344. case PRU_RCVOOB:
  345. if ((so->so_oobmark == 0 &&
  346.     (so->so_state & SS_RCVATMARK) == 0) ||
  347.     so->so_options & SO_OOBINLINE ||
  348.     tp->t_oobflags & TCPOOB_HADDATA) {
  349. error = EINVAL;
  350. break;
  351. }
  352. if ((tp->t_oobflags & TCPOOB_HAVEDATA) == 0) {
  353. error = EWOULDBLOCK;
  354. break;
  355. }
  356. m->m_len = 1;
  357. *mtod(m, caddr_t) = tp->t_iobc;
  358. if (((int)nam & MSG_PEEK) == 0)
  359. tp->t_oobflags ^= (TCPOOB_HAVEDATA | TCPOOB_HADDATA);
  360. break;
  361. case PRU_SENDOOB:
  362. if (sbspace(&so->so_snd) < -512) {
  363. m_freem(m);
  364. error = ENOBUFS;
  365. break;
  366. }
  367. /*
  368.  * According to RFC961 (Assigned Protocols),
  369.  * the urgent pointer points to the last octet
  370.  * of urgent data.  We continue, however,
  371.  * to consider it to indicate the first octet
  372.  * of data past the urgent section.
  373.  * Otherwise, snd_up should be one lower.
  374.  */
  375. sbappend(&so->so_snd, m);
  376. tp->snd_up = tp->snd_una + so->so_snd.sb_cc;
  377. tp->t_force = 1;
  378. error = tcp_output(tp);
  379. tp->t_force = 0;
  380. break;
  381. case PRU_SOCKADDR:
  382. in_setsockaddr(inp, nam);
  383. break;
  384. case PRU_PEERADDR:
  385. in_setpeeraddr(inp, nam);
  386. break;
  387. /*
  388.  * TCP slow timer went off; going through this
  389.  * routine for tracing's sake.
  390.  */
  391. case PRU_SLOWTIMO:
  392. tp = tcp_timers(tp, (int)nam);
  393. req |= (int)nam << 8; /* for debug's sake */
  394. break;
  395. default:
  396. #ifdef WV_INSTRUMENTATION
  397. #ifdef INCLUDE_WVNET    /* WV_NET_EMERGENCY event */
  398.             WV_NET_MARKER_2 (NET_AUX_EVENT, WV_NET_EMERGENCY, 31, 1,
  399.                              WV_NETEVENT_TCPREQ_PANIC, so->so_fd, req)
  400. #endif  /* INCLUDE_WVNET */
  401. #endif
  402. panic("tcp_usrreq");
  403. }
  404. #ifdef BSDDEBUG
  405. if (tp && (so->so_options & SO_DEBUG))
  406. (*tcpTraceRtn)(TA_USER, ostate, tp, (struct tcpiphdr *)0, req);
  407. #endif /* BSDDEBUG */
  408. splx(s);
  409. #ifdef WV_INSTRUMENTATION
  410. #ifdef INCLUDE_WVNET    /* WV_NET_ERROR event */
  411.     if (error)
  412.         {
  413.         WV_NET_MARKER_3 (NET_AUX_EVENT, WV_NET_ERROR, 40, 6,
  414.                          WV_NETEVENT_TCPREQ_FAIL, so->so_fd, req, error)
  415.         }
  416. #endif  /* INCLUDE_WVNET */
  417. #endif
  418. return (error);
  419. }
  420. int
  421. tcp_ctloutput(op, so, level, optname, mp)
  422. int op;
  423. struct socket *so;
  424. int level, optname;
  425. struct mbuf **mp;
  426. {
  427. int error = 0, s;
  428. struct inpcb *inp;
  429. register struct tcpcb *tp;
  430. register struct mbuf *m;
  431. register int i;
  432. #ifdef WV_INSTRUMENTATION
  433. #ifdef INCLUDE_WVNET    /* WV_NET_INFO event */
  434.     WV_NET_MARKER_4 (NET_AUX_EVENT, WV_NET_INFO, 46, 7,
  435.                  WV_NETEVENT_TCPCTLOUT_START, so->so_fd, op, level, optname)
  436. #endif  /* INCLUDE_WVNET */
  437. #endif
  438. s = splnet();
  439. inp = sotoinpcb(so);
  440. if (inp == NULL) {
  441. splx(s);
  442. if (op == PRCO_SETOPT && *mp)
  443. (void) m_free(*mp);
  444. #ifdef WV_INSTRUMENTATION
  445. #ifdef INCLUDE_WVNET    /* WV_NET_CRITICAL event */
  446.         WV_NET_MARKER_4 (NET_AUX_EVENT, WV_NET_CRITICAL, 32, 2,
  447.                  WV_NETEVENT_TCPCTLOUT_NOPCB, so->so_fd, op, level, optname)
  448. #endif  /* INCLUDE_WVNET */
  449. #endif
  450. return (ECONNRESET);
  451. }
  452. if (level != IPPROTO_TCP) {
  453. error = ip_ctloutput(op, so, level, optname, mp);
  454. splx(s);
  455. return (error);
  456. }
  457. tp = intotcpcb(inp);
  458. switch (op) {
  459. case PRCO_SETOPT:
  460. m = *mp;
  461. switch (optname) {
  462. case TCP_NODELAY:
  463. if (m == NULL || m->m_len < sizeof (int))
  464. error = EINVAL;
  465. else if (*mtod(m, int *))
  466. tp->t_flags |= TF_NODELAY;
  467. else
  468. tp->t_flags &= ~TF_NODELAY;
  469. break;
  470. case TCP_MAXSEG:
  471. if (m && (i = *mtod(m, int *)) > 0 && i <= tp->t_maxseg)
  472. tp->t_maxseg = i;
  473. else
  474. error = EINVAL;
  475. break;
  476. default:
  477. error = ENOPROTOOPT;
  478. break;
  479. }
  480. if (m)
  481. (void) m_free(m);
  482. break;
  483. case PRCO_GETOPT:
  484. *mp = m = mBufClGet(M_WAIT, MT_SOOPTS, CL_SIZE_128, TRUE);
  485. if (m == (struct mbuf *) NULL)
  486.     {
  487.     error = ENOBUFS;
  488.     break;
  489.     }
  490. m->m_len = sizeof(int);
  491. switch (optname) {
  492. case TCP_NODELAY:
  493. *mtod(m, int *) = tp->t_flags & TF_NODELAY;
  494. break;
  495. case TCP_MAXSEG:
  496. *mtod(m, int *) = tp->t_maxseg;
  497. break;
  498. default:
  499. error = ENOPROTOOPT;
  500. break;
  501. }
  502. break;
  503. }
  504. splx(s);
  505. return (error);
  506. }
  507. #ifndef VIRTUAL_STACK
  508. u_long tcp_sendspace = 1024*8;
  509. u_long tcp_recvspace = 1024*8;
  510. #endif
  511. /*
  512.  * Attach TCP protocol to socket, allocating
  513.  * internet protocol control block, tcp control block,
  514.  * bufer space, and entering LISTEN state if to accept connections.
  515.  */
  516. int
  517. tcp_attach(so)
  518. struct socket *so;
  519. {
  520. register struct tcpcb *tp;
  521. struct inpcb *inp;
  522. int error;
  523. #ifdef WV_INSTRUMENTATION
  524. #ifdef INCLUDE_WVNET    /* WV_NET_VERBOSE event */
  525.     WV_NET_MARKER_1 (NET_AUX_EVENT, WV_NET_VERBOSE, 41, 9,
  526.                      WV_NETEVENT_TCPATTACH_START, so->so_fd)
  527. #endif  /* INCLUDE_WVNET */
  528. #endif
  529. if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
  530. error = soreserve(so, tcp_sendspace, tcp_recvspace);
  531. if (error)
  532. return (error);
  533. }
  534. error = in_pcballoc(so, &tcbinfo);
  535. if (error)
  536. return (error);
  537. inp = sotoinpcb(so);
  538. tp = tcp_newtcpcb(inp);
  539. if (tp == 0) {
  540. int nofd = so->so_state & SS_NOFDREF; /* XXX */
  541. so->so_state &= ~SS_NOFDREF; /* don't free the socket yet */
  542. in_pcbdetach(inp);
  543. so->so_state |= nofd;
  544. #ifdef WV_INSTRUMENTATION
  545. #ifdef INCLUDE_WVNET    /* WV_NET_CRITICAL event */
  546.         WV_NET_MARKER_1 (NET_AUX_EVENT, WV_NET_CRITICAL, 33, 3,
  547.                          WV_NETEVENT_TCPATTACH_NOBUFS, so->so_fd)
  548. #endif  /* INCLUDE_WVNET */
  549. #endif
  550. return (ENOBUFS);
  551. }
  552. tp->t_state = TCPS_CLOSED;
  553. return (0);
  554. }
  555. /*
  556.  * Initiate (or continue) disconnect.
  557.  * If embryonic state, just send reset (once).
  558.  * If in ``let data drain'' option and linger null, just drop.
  559.  * Otherwise (hard), mark socket disconnecting and drop
  560.  * current input data; switch states based on user close, and
  561.  * send segment to peer (with FIN).
  562.  */
  563. struct tcpcb *
  564. tcp_disconnect(tp)
  565. register struct tcpcb *tp;
  566. {
  567. struct socket *so = tp->t_inpcb->inp_socket;
  568. #ifdef WV_INSTRUMENTATION
  569. #ifdef INCLUDE_WVNET    /* WV_NET_VERBOSE event */
  570.     WV_NET_MARKER_1 (NET_AUX_EVENT, WV_NET_VERBOSE, 42, 10,
  571.                      WV_NETEVENT_TCPDISCONN_START, so->so_fd)
  572. #endif  /* INCLUDE_WVNET */
  573. #endif
  574. if (tp->t_state < TCPS_ESTABLISHED)
  575. tp = tcp_close(tp);
  576. else if ((so->so_options & SO_LINGER) && so->so_linger == 0)
  577. tp = tcp_drop(tp, 0);
  578. else {
  579. soisdisconnecting(so);
  580. sbflush(&so->so_rcv);
  581. tp = tcp_usrclosed(tp);
  582. if (tp)
  583. (void) tcp_output(tp);
  584. }
  585. return (tp);
  586. }
  587. /*
  588.  * User issued close, and wish to trail through shutdown states:
  589.  * if never received SYN, just forget it.  If got a SYN from peer,
  590.  * but haven't sent FIN, then go to FIN_WAIT_1 state to send peer a FIN.
  591.  * If already got a FIN from peer, then almost done; go to LAST_ACK
  592.  * state.  In all other cases, have already sent FIN to peer (e.g.
  593.  * after PRU_SHUTDOWN), and just have to play tedious game waiting
  594.  * for peer to send FIN or not respond to keep-alives, etc.
  595.  * We can let the user exit from the close as soon as the FIN is acked.
  596.  */
  597. struct tcpcb *
  598. tcp_usrclosed(tp)
  599. register struct tcpcb *tp;
  600. {
  601. switch (tp->t_state) {
  602. case TCPS_CLOSED:
  603. case TCPS_LISTEN:
  604. case TCPS_SYN_SENT:
  605. tp->t_state = TCPS_CLOSED;
  606. tp = tcp_close(tp);
  607. break;
  608. case TCPS_SYN_RECEIVED:
  609. case TCPS_ESTABLISHED:
  610. tp->t_state = TCPS_FIN_WAIT_1;
  611. break;
  612. case TCPS_CLOSE_WAIT:
  613. tp->t_state = TCPS_LAST_ACK;
  614. break;
  615. }
  616. if (tp && tp->t_state >= TCPS_FIN_WAIT_2)
  617. soisdisconnected(tp->t_inpcb->inp_socket);
  618. return (tp);
  619. }
  620. LOCAL void tcpTraceStub ()
  621.     {
  622.     }
  623. LOCAL void tcpReportStub ()
  624.     {
  625.     }