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

VxWorks

开发平台:

C/C++

  1. /* tcp_subr.c - TCP routines */
  2. /* Copyright 1984 - 2002 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5.  * Copyright (c) 1982, 1986, 1988, 1990, 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_subr.c 8.2 (Berkeley) 5/24/95
  37.  */
  38. /*
  39. modification history
  40. --------------------
  41. 01e,18apr02,vvv  trigger slow-start in response to ICMP fragmentation-needed
  42.  message (SPR #75058)
  43. 01d,12oct01,rae  merge from truestack ver 01o, base 01c (SPRs 70049,
  44.                  70330, 34005, 31244, etc)
  45. 01c,31mar97,vin  modified for hash look ups for pcbs(FREEBSD 2.2.1).
  46. 01b,30oct96,vin  changed tcp_template to return mbuf * instead of tcpiphdr.
  47.  changed m_free(dtom(...)) to m_free(tp->t_template).
  48. 01a,03mar96,vin  created from BSD4.4 stuff,integrated with 02i.
  49. */
  50. /*
  51. DESCRIPTION
  52. */
  53. #include "vxWorks.h"
  54. #include "net/systm.h"
  55. #include "net/mbuf.h"
  56. #include "sys/socket.h"
  57. #include "net/socketvar.h"
  58. #include "net/protosw.h"
  59. #include "errno.h"
  60. #include "net/route.h"
  61. #include "net/if.h"
  62. #include "netinet/in.h"
  63. #include "netinet/in_pcb.h"
  64. #include "netinet/in_systm.h"
  65. #include "netinet/ip.h"
  66. #include "netinet/ip_var.h"
  67. #include "netinet/ip_icmp.h"
  68. #include "netinet/tcp.h"
  69. #include "netinet/tcp_fsm.h"
  70. #include "netinet/tcp_seq.h"
  71. #include "netinet/tcp_timer.h"
  72. #include "netinet/tcp_var.h"
  73. #include "netinet/tcpip.h"
  74. #ifdef WV_INSTRUMENTATION
  75. #ifdef INCLUDE_WVNET
  76. #include "wvNetLib.h"
  77. #endif
  78. #endif
  79. #ifdef VIRTUAL_STACK
  80. #include "netinet/vsLib.h"
  81. #else
  82. /*
  83.  * Target size of TCP PCB hash table. Will be rounded down to a prime
  84.  * number.
  85.  */
  86. #ifndef TCBHASHSIZE
  87. #define TCBHASHSIZE     128
  88. #endif
  89. /* patchable/settable parameters for tcp */
  90. int  tcp_mssdflt = TCP_MSS;
  91. int  tcp_rttdflt = TCPTV_SRTTDFLT / PR_SLOWHZ;
  92. int tcp_do_rfc1323 = 1;
  93. u_short tcp_pcbhashsize = TCBHASHSIZE;
  94. extern struct inpcb * tcp_last_inpcb;
  95. #endif /* VIRTUAL_STACK */
  96. extern void _remque();
  97. extern int random();
  98. #ifdef WV_INSTRUMENTATION
  99. #ifdef INCLUDE_WVNET
  100.     /* Set common fields of event identifiers for this module. */
  101. LOCAL UCHAR wvNetModuleId = WV_NET_TCPSUBR_MODULE;  /* Value for tcp_subr.c */
  102. LOCAL UCHAR wvNetLocalFilter = WV_NET_NONE;     /* Available event filter */
  103. LOCAL ULONG wvNetEventId;       /* Event identifier: see wvNetLib.h */
  104. #endif    /* INCLUDE_WVNET */
  105. #endif
  106. /* globals */
  107. unsigned long (*pTcpRandHook)(void) = (unsigned long (*)(void))random;
  108. /*******************************************************************************
  109. *
  110. * tcpRandHookAdd - Changes pTcpRandHook to a user defined functioned
  111. *
  112. * The user supplies a random number generator to tcp_init via pTcpRandHook.
  113. *
  114. * RETURNS: OK if the function pointer is not null.
  115. */
  116. int tcpRandHookAdd
  117.     (
  118.     FUNCPTR pTcpRandFunc
  119.     )
  120.     {
  121.     if (pTcpRandFunc != NULL)
  122. {
  123.         pTcpRandHook = (unsigned long (*)(void))pTcpRandFunc;
  124. return (OK);
  125. }
  126.     else
  127.      return (ERROR);
  128.     }
  129. /*******************************************************************************
  130. *
  131. * tcpRandHookDelete - Changes pTcpRandHook back to the default setting
  132. *
  133. * This routine is not needed.
  134. *
  135. */
  136. void tcpRandHookDelete (void)
  137.     {
  138.     /*
  139.      * XXX
  140.      * Since random() returns 31bit random number, the highest bit
  141.      * is not set, therefore casting unsigned long will not affect
  142.      * against caller badly.    
  143.      */
  144.     pTcpRandHook = (unsigned long (*)(void))random; /* XXX */
  145.     }
  146. /*
  147.  * Tcp initialization
  148.  */
  149. void
  150. tcp_init()
  151. {
  152. #ifdef WV_INSTRUMENTATION
  153. #ifdef INCLUDE_WVNET    /* WV_NET_VERBOSE event */
  154.     WV_NET_MARKER_0 (NET_AUX_EVENT, WV_NET_VERBOSE, 39, 9,
  155.                      WV_NETEVENT_TCPINIT_START)
  156. #endif  /* INCLUDE_WVNET */
  157. #endif
  158. tcp_iss = pTcpRandHook();
  159.         LIST_INIT(&tcb);
  160.         tcbinfo.listhead = &tcb;
  161.         tcbinfo.hashbase = hashinit(tcp_pcbhashsize, MT_PCB, &tcbinfo.hashmask);
  162. if (max_protohdr < sizeof(struct tcpiphdr))
  163. max_protohdr = sizeof(struct tcpiphdr);
  164. if (max_linkhdr + sizeof(struct tcpiphdr) > CL_SIZE_128)
  165.             {
  166. #ifdef WV_INSTRUMENTATION
  167. #ifdef INCLUDE_WVNET    /* WV_NET_EMERGENCY event */
  168.         WV_NET_MARKER_0 (NET_AUX_EVENT, WV_NET_EMERGENCY, 30, 1,
  169.                          WV_NETEVENT_TCPINIT_HDRPANIC)
  170. #endif  /* INCLUDE_WVNET */
  171. #endif
  172.             panic("tcp_init");
  173.             }
  174. }
  175. /*
  176.  * Create template to be used to send tcp packets on a connection.
  177.  * Call after host entry created, allocates an mbuf and fills
  178.  * in a skeletal tcp/ip header, minimizing the amount of work
  179.  * necessary when the connection is used.
  180.  */
  181. struct mbuf *
  182. tcp_template(tp)
  183. struct tcpcb *tp;
  184. {
  185. register struct inpcb *inp = tp->t_inpcb;
  186. register struct mbuf *m;
  187. register struct tcpiphdr *n;
  188. if ((m = tp->t_template) == NULL) {
  189. m = mBufClGet (M_DONTWAIT, MT_HEADER, sizeof (struct tcpiphdr),
  190.        TRUE); 
  191. if (m == NULL)
  192. return (0);
  193. m->m_len = sizeof (struct tcpiphdr);
  194. }
  195. n = mtod (m, struct tcpiphdr *);
  196. n->ti_next = n->ti_prev = 0;
  197. n->ti_x1 = 0;
  198. n->ti_pr = IPPROTO_TCP;
  199. n->ti_len = htons(sizeof (struct tcpiphdr) - sizeof (struct ip));
  200. n->ti_src = inp->inp_laddr;
  201. n->ti_dst = inp->inp_faddr;
  202. n->ti_sport = inp->inp_lport;
  203. n->ti_dport = inp->inp_fport;
  204. n->ti_seq = 0;
  205. n->ti_ack = 0;
  206. n->ti_x2 = 0;
  207. n->ti_off = 5;
  208. n->ti_flags = 0;
  209. n->ti_win = 0;
  210. n->ti_sum = 0;
  211. n->ti_urp = 0;
  212. return (m);
  213. }
  214. /*
  215.  * Send a single message to the TCP at address specified by
  216.  * the given TCP/IP header.  If m == 0, then we make a copy
  217.  * of the tcpiphdr at ti and send directly to the addressed host.
  218.  * This is used to force keep alive messages out using the TCP
  219.  * template for a connection tp->t_template.  If flags are given
  220.  * then we send a message back to the TCP which originated the
  221.  * segment ti, and discard the mbuf containing it and any other
  222.  * attached mbufs.
  223.  *
  224.  * In any case the ack and sequence number of the transmitted
  225.  * segment are as specified by the parameters.
  226.  */
  227. void
  228. tcp_respond(tp, ti, m, ack, seq, flags)
  229. struct tcpcb *tp;
  230. register struct tcpiphdr *ti;
  231. register struct mbuf *m;
  232. tcp_seq ack, seq;
  233. int flags;
  234. {
  235. register int tlen;
  236. int win = 0;
  237. struct route *ro = 0;
  238. if (tp) {
  239. #ifdef WV_INSTRUMENTATION
  240. #ifdef INCLUDE_WVNET    /* WV_NET_NOTICE event */
  241.     WV_NET_PORTOUT_EVENT_4 (NET_CORE_EVENT, WV_NET_NOTICE, 20, 2,
  242.                             tp->t_inpcb->inp_lport, tp->t_inpcb->inp_fport,
  243.                             WV_NETEVENT_TCPRESPOND_START, WV_NET_SEND,
  244.                             tp->t_inpcb->inp_socket->so_fd, ack, seq, flags)
  245. #endif  /* INCLUDE_WVNET */
  246. #endif
  247. win = sbspace(&tp->t_inpcb->inp_socket->so_rcv);
  248. ro = &tp->t_inpcb->inp_route;
  249. }
  250. if (m == 0) {
  251. m = mHdrClGet(M_DONTWAIT, MT_HEADER, CL_SIZE_128, TRUE);
  252. if (m == NULL)
  253. return;
  254. #ifdef TCP_COMPAT_42
  255. tlen = 1;
  256. #else
  257. tlen = 0;
  258. #endif
  259. m->m_data += max_linkhdr;
  260. *mtod(m, struct tcpiphdr *) = *ti;
  261. ti = mtod(m, struct tcpiphdr *);
  262. flags = TH_ACK;
  263. } else {
  264. m_freem(m->m_next);
  265. m->m_next = 0;
  266. m->m_data = (caddr_t)ti;
  267. m->m_len = sizeof (struct tcpiphdr);
  268. tlen = 0;
  269. #define xchg(a,b,type) { type t; t=a; a=b; b=t; }
  270. xchg(ti->ti_dst.s_addr, ti->ti_src.s_addr, u_long);
  271. xchg(ti->ti_dport, ti->ti_sport, u_short);
  272. #undef xchg
  273. }
  274. ti->ti_len = htons((u_short)(sizeof (struct tcphdr) + tlen));
  275. tlen += sizeof (struct tcpiphdr);
  276. m->m_len = tlen;
  277. m->m_pkthdr.len = tlen;
  278. m->m_pkthdr.rcvif = (struct ifnet *) 0;
  279. ti->ti_next = ti->ti_prev = 0;
  280. ti->ti_x1 = 0;
  281. ti->ti_seq = htonl(seq);
  282. ti->ti_ack = htonl(ack);
  283. ti->ti_x2 = 0;
  284. ti->ti_off = sizeof (struct tcphdr) >> 2;
  285. ti->ti_flags = flags;
  286. if (tp)
  287. ti->ti_win = htons((u_short) (win >> tp->rcv_scale));
  288. else
  289. ti->ti_win = htons((u_short)win);
  290. ti->ti_urp = 0;
  291. ti->ti_sum = 0;
  292. ti->ti_sum = in_cksum(m, tlen);
  293. ((struct ip *)ti)->ip_len = tlen;
  294. ((struct ip *)ti)->ip_ttl = ip_defttl;
  295. if (tp)
  296.     ((struct ip *)ti)->ip_tos = tp->t_inpcb->inp_ip.ip_tos;
  297. (void) ip_output(m, NULL, ro, 0, NULL);
  298. }
  299. /*
  300.  * Create a new TCP control block, making an
  301.  * empty reassembly queue and hooking it to the argument
  302.  * protocol control block.
  303.  */
  304. struct tcpcb *
  305. tcp_newtcpcb(inp)
  306. struct inpcb *inp;
  307. {
  308. register struct tcpcb *tp;
  309. MALLOC(tp, struct tcpcb *, sizeof(*tp), MT_PCB, M_DONTWAIT);
  310. if (tp == NULL)
  311. return ((struct tcpcb *)0);
  312. bzero((char *) tp, sizeof(struct tcpcb));
  313. tp->seg_next = tp->seg_prev = (struct tcpiphdr *)tp;
  314. tp->t_maxseg = tp->t_maxsize = tcp_mssdflt;
  315. tp->t_flags = tcp_do_rfc1323 ? (TF_REQ_SCALE|TF_REQ_TSTMP) : 0;
  316. tp->t_inpcb = inp;
  317. /*
  318.  * Init srtt to TCPTV_SRTTBASE (0), so we can tell that we have no
  319.  * rtt estimate.  Set rttvar so that srtt + 2 * rttvar gives
  320.  * reasonable initial retransmit time.
  321.  */
  322. tp->t_srtt = TCPTV_SRTTBASE;
  323. tp->t_rttvar = tcp_rttdflt * PR_SLOWHZ << 2;
  324. tp->t_rttmin = TCPTV_MIN;
  325. TCPT_RANGESET(tp->t_rxtcur, 
  326.     ((TCPTV_SRTTBASE >> 2) + (TCPTV_SRTTDFLT << 2)) >> 1,
  327.     TCPTV_MIN, TCPTV_REXMTMAX);
  328. tp->snd_cwnd = TCP_MAXWIN << TCP_MAX_WINSHIFT;
  329. tp->snd_ssthresh = TCP_MAXWIN << TCP_MAX_WINSHIFT;
  330. inp->inp_ip.ip_ttl = ip_defttl;
  331. inp->inp_ppcb = (caddr_t)tp;
  332. return (tp);
  333. }
  334. /*
  335.  * Drop a TCP connection, reporting
  336.  * the specified error.  If connection is synchronized,
  337.  * then send a RST to peer.
  338.  */
  339. struct tcpcb *
  340. tcp_drop(tp, error)
  341. register struct tcpcb *tp;
  342. int error;
  343. {
  344. struct socket *so = tp->t_inpcb->inp_socket;
  345. #ifdef WV_INSTRUMENTATION
  346. #ifdef INCLUDE_WVNET    /* WV_NET_INFO event */
  347.     WV_NET_PORTOUT_MARKER_1 (NET_AUX_EVENT, WV_NET_INFO, 38, 3,
  348.                             tp->t_inpcb->inp_lport, tp->t_inpcb->inp_fport,
  349.                             WV_NETEVENT_TCPDROP_START, so->so_fd)
  350. #endif  /* INCLUDE_WVNET */
  351. #endif
  352. if (TCPS_HAVERCVDSYN(tp->t_state)) {
  353. tp->t_state = TCPS_CLOSED;
  354. (void) tcp_output(tp);
  355. tcpstat.tcps_drops++;
  356. } else
  357. tcpstat.tcps_conndrops++;
  358. if (error == ETIMEDOUT && tp->t_softerror)
  359. error = tp->t_softerror;
  360. so->so_error = error;
  361. return (tcp_close(tp));
  362. }
  363. /*
  364.  * Close a TCP control block:
  365.  * discard all space held by the tcp
  366.  * discard internet protocol block
  367.  * wake up any sleepers
  368.  */
  369. struct tcpcb *
  370. tcp_close(tp)
  371. register struct tcpcb *tp;
  372. {
  373. register struct tcpiphdr *t;
  374. struct inpcb *inp = tp->t_inpcb;
  375. struct socket *so = inp->inp_socket;
  376. register struct mbuf *m;
  377. register struct rtentry *rt;
  378. #ifdef WV_INSTRUMENTATION
  379. #ifdef INCLUDE_WVNET    /* WV_NET_INFO event */
  380.     WV_NET_MARKER_1 (NET_AUX_EVENT, WV_NET_INFO, 39, 4,
  381.                      WV_NETEVENT_TCPCLOSE_START, so->so_fd)
  382. #endif  /* INCLUDE_WVNET */
  383. #endif
  384. /*
  385.  * If we sent enough data to get some meaningful characteristics,
  386.  * save them in the routing entry.  'Enough' is arbitrarily 
  387.  * defined as the sendpipesize (default 4K) * 16.  This would
  388.  * give us 16 rtt samples assuming we only get one sample per
  389.  * window (the usual case on a long haul net).  16 samples is
  390.  * enough for the srtt filter to converge to within 5% of the correct
  391.  * value; fewer samples and we could save a very bogus rtt.
  392.  *
  393.  * Don't update the default route's characteristics and don't
  394.  * update anything that the user "locked".
  395.  */
  396. if (SEQ_LT(tp->iss + so->so_snd.sb_hiwat * 16, tp->snd_max) &&
  397.     (rt = inp->inp_route.ro_rt) &&
  398.     ((struct sockaddr_in *)rt_key(rt))->sin_addr.s_addr != INADDR_ANY) {
  399. register u_long i = 0;
  400. if ((rt->rt_rmx.rmx_locks & RTV_RTT) == 0) {
  401. i = tp->t_srtt *
  402.     (RTM_RTTUNIT / (PR_SLOWHZ * TCP_RTT_SCALE));
  403. if (rt->rt_rmx.rmx_rtt && i)
  404. /*
  405.  * filter this update to half the old & half
  406.  * the new values, converting scale.
  407.  * See route.h and tcp_var.h for a
  408.  * description of the scaling constants.
  409.  */
  410. rt->rt_rmx.rmx_rtt =
  411.     (rt->rt_rmx.rmx_rtt + i) / 2;
  412. else
  413. rt->rt_rmx.rmx_rtt = i;
  414. }
  415. if ((rt->rt_rmx.rmx_locks & RTV_RTTVAR) == 0) {
  416. i = tp->t_rttvar *
  417.     (RTM_RTTUNIT / (PR_SLOWHZ * TCP_RTTVAR_SCALE));
  418. if (rt->rt_rmx.rmx_rttvar && i)
  419. rt->rt_rmx.rmx_rttvar =
  420.     (rt->rt_rmx.rmx_rttvar + i) / 2;
  421. else
  422. rt->rt_rmx.rmx_rttvar = i;
  423. }
  424. /*
  425.  * update the pipelimit (ssthresh) if it has been updated
  426.  * already or if a pipesize was specified & the threshhold
  427.  * got below half the pipesize.  I.e., wait for bad news
  428.  * before we start updating, then update on both good
  429.  * and bad news.
  430.                  *
  431.                  * Update the slow start threshold when all of the
  432.                  * following conditions apply:
  433.                  *   1) The value is not locked (via a routing socket).
  434.                  *   2) Some packet loss occurred during the connection
  435.                  *       (snd_ssthresh is not zero)
  436.                  *   3) Packet loss also occurred during an earlier
  437.                  *      connection (rmx_ssthresh is not zero). This
  438.                  *      condition also applies if a user set a value
  439.                  *      in advance via a routing socket.
  440.                  *
  441.                  * If none of the above conditions apply, the system
  442.                  * still updates the slow start threshold if the
  443.                  * value for this connection's packet loss is less
  444.                  * than half the rmx_sendpipe value set via a routing
  445.                  * socket. If that pipe size is available, the update
  446.                  * occurs even if no packet loss happened.
  447.  */
  448. if (((rt->rt_rmx.rmx_locks & RTV_SSTHRESH) == 0 &&
  449.        (i = tp->snd_ssthresh) && rt->rt_rmx.rmx_ssthresh) ||
  450.     i < (rt->rt_rmx.rmx_sendpipe / 2)) {
  451. /*
  452.  * convert the limit from user data bytes to
  453.  * packets then to packet data bytes.
  454.  */
  455. i = (i + tp->t_maxseg / 2) / tp->t_maxseg;
  456. if (i < 2)
  457. i = 2;
  458. i *= (u_long)(tp->t_maxseg + sizeof (struct tcpiphdr));
  459. if (rt->rt_rmx.rmx_ssthresh)
  460. rt->rt_rmx.rmx_ssthresh =
  461.     (rt->rt_rmx.rmx_ssthresh + i) / 2;
  462. else
  463. rt->rt_rmx.rmx_ssthresh = i;
  464. }
  465. }
  466. /* free the reassembly queue, if any */
  467. t = tp->seg_next;
  468. while (t != (struct tcpiphdr *)tp) {
  469. t = (struct tcpiphdr *)t->ti_next;
  470. m = REASS_MBUF((struct tcpiphdr *)t->ti_prev);
  471. remque(t->ti_prev);
  472. m_freem(m);
  473. }
  474. if (tp->t_template)
  475. (void) m_free(tp->t_template);
  476. FREE(tp, MT_PCB); 
  477. inp->inp_ppcb = 0;
  478. soisdisconnected(so);
  479. /* clobber input pcb cache if we're closing the cached connection */
  480. if (inp == tcp_last_inpcb)
  481.             tcp_last_inpcb = NULL;
  482. in_pcbdetach(inp);
  483. tcpstat.tcps_closed++;
  484. return ((struct tcpcb *)0);
  485. }
  486. void
  487. tcp_drain()
  488. {
  489. }
  490. /*
  491.  * Notify a tcp user of an asynchronous error;
  492.  * store error as soft error, but wake up user
  493.  * (for now, won't do anything until can select for soft error).
  494.  */
  495. void tcp_notify
  496.     (
  497.     struct inpcb *inp, 
  498.     int error
  499.     )
  500.     {
  501.     register struct tcpcb *tp = (struct tcpcb *)inp->inp_ppcb;
  502.     register struct socket *so = inp->inp_socket;
  503.     /*
  504.      * Ignore some errors if we are hooked up.
  505.      * If connection hasn't completed, has retransmitted several times,
  506.      * and receives a second error, give up now.  This is better
  507.      * than waiting a long time to establish a connection that
  508.      * can never complete.
  509.      */
  510.     if (tp->t_state == TCPS_ESTABLISHED &&
  511.         (error == EHOSTUNREACH || error == ENETUNREACH ||
  512.          error == EHOSTDOWN))
  513.         {
  514. #ifdef WV_INSTRUMENTATION
  515. #ifdef INCLUDE_WVNET    /* WV_NET_INFO event */
  516.         WV_NET_MARKER_2 (NET_AUX_EVENT, WV_NET_INFO, 40, 5,
  517.                          WV_NETEVENT_TCPNOTIFY_IGNORE, so->so_fd, error)
  518. #endif  /* INCLUDE_WVNET */
  519. #endif
  520.         return;
  521.         }
  522.     else if (tp->t_state < TCPS_ESTABLISHED && tp->t_rxtshift > 3 &&
  523.              tp->t_softerror)
  524.         {
  525. #ifdef WV_INSTRUMENTATION
  526. #ifdef INCLUDE_WVNET    /* WV_NET_INFO event */
  527.         WV_NET_MARKER_2 (NET_AUX_EVENT, WV_NET_INFO, 41, 6,
  528.                          WV_NETEVENT_TCPNOTIFY_KILL, so->so_fd, error)
  529. #endif  /* INCLUDE_WVNET */
  530. #endif
  531.         so->so_error = error;
  532.         }
  533.     else 
  534.         {
  535. #ifdef WV_INSTRUMENTATION
  536. #ifdef INCLUDE_WVNET    /* WV_NET_INFO event */
  537.         WV_NET_MARKER_2 (NET_AUX_EVENT, WV_NET_INFO, 42, 7,
  538.                          WV_NETEVENT_TCPNOTIFY_ERROR, so->so_fd, error)
  539. #endif  /* INCLUDE_WVNET */
  540. #endif
  541.         tp->t_softerror = error;
  542.         }
  543.     if (so->so_timeoSem)
  544.         wakeup(so->so_timeoSem);
  545.     sorwakeup(so);
  546.     sowwakeup(so);
  547.     }
  548. void
  549. tcp_ctlinput(cmd, sa, ip)
  550. int cmd;
  551. struct sockaddr *sa;
  552. register struct ip *ip;
  553. {
  554. register struct tcphdr *th;
  555. extern struct in_addr zeroin_addr;
  556. extern u_char inetctlerrmap[];
  557. void (*notify) (struct inpcb *, int) = tcp_notify;
  558. #ifdef WV_INSTRUMENTATION
  559. #ifdef INCLUDE_WVNET    /* WV_NET_INFO event */
  560.     WV_NET_MARKER_1 (NET_AUX_EVENT, WV_NET_INFO, 43, 8,
  561.                      WV_NETEVENT_TCPCTLIN_START, cmd)
  562. #endif  /* INCLUDE_WVNET */
  563. #endif
  564. if (cmd == PRC_QUENCH)
  565. notify = tcp_quench;
  566.         else if (cmd == PRC_MSGSIZE)
  567.                 notify = tcp_updatemtu;
  568. else if (!PRC_IS_REDIRECT(cmd) &&
  569.  ((unsigned)cmd > PRC_NCMDS || inetctlerrmap[cmd] == 0))
  570. return;
  571. if (ip) {
  572. th = (struct tcphdr *)((caddr_t)ip + (ip->ip_hl << 2));
  573. in_pcbnotify(&tcb, sa, th->th_dport, ip->ip_src, th->th_sport,
  574. cmd, notify);
  575. } else
  576. in_pcbnotify(&tcb, sa, 0, zeroin_addr, 0, cmd, notify);
  577. }
  578. /*
  579.  * When a source quench is received, close congestion window
  580.  * to one segment.  We will gradually open it again as we proceed.
  581.  */
  582. void
  583. tcp_quench(inp, error)
  584. struct inpcb *inp;
  585. int error;
  586. {
  587. struct tcpcb *tp = intotcpcb(inp);
  588. if (tp)
  589. tp->snd_cwnd = tp->t_maxseg;
  590. }
  591. /*
  592.  * Look-up the routing entry to the peer of this inpcb.  If no route
  593.  * is found and it cannot be allocated the return NULL.  This routine
  594.  * is called by TCP routines that access the rmx structure.
  595.  */
  596. struct rtentry *
  597. tcp_rtlookup(inp)
  598.         struct inpcb *inp;
  599. {
  600.         struct route *ro;
  601.         struct rtentry *rt;
  602.         ro = &inp->inp_route;
  603.         rt = ro->ro_rt;
  604.         if (rt == NULL || !(rt->rt_flags & RTF_UP)) {
  605.                 /* No route yet, so try to acquire one */
  606.                 if (inp->inp_faddr.s_addr != INADDR_ANY) {
  607.                         ro->ro_dst.sa_family = AF_INET;
  608.                         ro->ro_dst.sa_len = sizeof(ro->ro_dst);
  609.                         ((struct sockaddr_in *) &ro->ro_dst)->sin_addr =
  610.                                 inp->inp_faddr;
  611.                         TOS_SET (&ro->ro_dst, inp->inp_ip.ip_tos);
  612.                         rtalloc(ro);
  613.                         rt = ro->ro_rt;
  614.                 }
  615.         }
  616.         return rt;
  617. }
  618. /*
  619.  * When an ICMP error "need fragmentation" message causes the stack to
  620.  * update the MSS based on the (already updated) path MTU estimate and
  621.  * signal TCP to send data so that the dropped packet is detected. This 
  622.  * routine duplicates some code from the tcp_mss() routine in tcp_input.c
  623.  */
  624. void tcp_updatemtu
  625.     (
  626.     struct inpcb * inp,
  627.     int error
  628.     )
  629.     {
  630.     struct tcpcb *tp = intotcpcb(inp);
  631.     struct rtentry *rt;
  632.     struct socket *so = inp->inp_socket;
  633.     int mss;
  634.     int maxseg;
  635.     int cwnd = 0;
  636.     if (tp)
  637.         {
  638.         rt = tcp_rtlookup (inp);
  639.         if ( (rt == NULL) || (rt->rt_rmx.rmx_locks & RTV_MTU))
  640.             {
  641.             /*
  642.              * New path MTU estimate unavailable or discovery process
  643.              * ended - set segment size to default value if less than
  644.              * current estimate.
  645.              */
  646.             tp->t_maxsize = min (tp->t_maxsize, tcp_mssdflt);
  647.             tp->t_maxseg = min (so->so_snd.sb_hiwat, tp->t_maxsize);
  648.             return;
  649.             }
  650.         maxseg = rt->rt_rmx.rmx_mtu - sizeof(struct tcpiphdr);
  651.         mss = rt->rt_rmx.rmx_mss;
  652.         /*
  653.          * The following comparison violates the TCP specification by
  654.          * permitting IP datagrams larger than the mandatory default
  655.          * if the peer has not sent the initial SYN (which assigns the
  656.          * MSS value). Although TCP is forbidden to exceed the default
  657.          * unless explicitly allowed by the MSS option from a peer, that
  658.          * behavior would probably prevent path MTU discovery from occurring
  659.          * since the default is already less than many typical MTU sizes.
  660.          *
  661.          * Avoiding the conservative default might not have a significant
  662.          * impact. Any unexpectedly large segments will only occur when
  663.          * sending an initial SYN which includes options and/or data to a
  664.          * host which has never been connected. Once the remote peer sends
  665.          * a return SYN (during the connection handshake), the system will
  666.          * record a MSS value and reduce the maximum segment size if
  667.          * necessary. If that remote peer ignores the generally recommended
  668.          * "liberal acceptance" policy and discards the segment which its
  669.          * network layer successfully received, the failed connection attempts
  670.          * will reveal the problem.
  671.          */
  672.         if (mss)
  673.             {
  674.             /*
  675.              * If necessary, reduce the path MTU estimate according to the
  676.              * known segment size which the peer is required to accept.
  677.              */
  678.             maxseg = min (maxseg, mss);
  679.             }
  680.         /*
  681.          * Do not allow ICMP error messages to increase the maximum
  682.          * segment size above the initial value determined in the
  683.          * tcp_mss() routine.
  684.          */
  685.         if (tp->t_maxsize <= maxseg)
  686.             return;
  687.         tp->t_maxsize = maxseg;
  688.         /* Update the mss to ignore newly received options? */
  689.         if ((tp->t_flags & (TF_REQ_TSTMP|TF_NOOPT)) == TF_REQ_TSTMP &&
  690.             (tp->t_flags & TF_RCVD_TSTMP) == TF_RCVD_TSTMP)
  691.             maxseg -= TCPOLEN_TSTAMP_APPA;
  692. #if     (MCLBYTES & (MCLBYTES - 1)) == 0
  693.         if (maxseg > MCLBYTES)
  694.             maxseg &= ~(MCLBYTES-1);
  695. #else
  696.         if (maxseg > MCLBYTES)
  697.             maxseg = maxseg / MCLBYTES * MCLBYTES;
  698. #endif
  699.         if (so->so_snd.sb_hiwat < maxseg)
  700.             maxseg = so->so_snd.sb_hiwat;
  701.         tp->t_maxseg = maxseg;
  702.         tp->t_rtt = 0;
  703.         tp->snd_nxt = tp->snd_una;
  704.         /*
  705.  * If tcp_updatemtu was called in response to an ICMP fragmentation-
  706.  * needed message (error = EMSGSIZE), trigger slow-start without 
  707.  * changing the congestion window. Temporarily set cwnd to 1 segment 
  708.  * and then restore it to original value after tcp_output. tcp_updatemtu
  709.  * is also called from tcp_output but in that case error is 0. We do
  710.  * not want to trigger slow-start for that scenario.
  711.  */
  712.         if (error == EMSGSIZE)
  713.     {
  714.     cwnd = tp->snd_cwnd;
  715.     tp->snd_cwnd = maxseg;
  716.     }
  717.         tcp_output(tp);
  718. if (error == EMSGSIZE)
  719.     tp->snd_cwnd = cwnd;
  720.         }
  721.     }