|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * The contents of this file constitute Original Code as defined in and ! 7: * are subject to the Apple Public Source License Version 1.1 (the ! 8: * "License"). You may not use this file except in compliance with the ! 9: * License. Please obtain a copy of the License at ! 10: * http://www.apple.com/publicsource and read it before using this file. ! 11: * ! 12: * This Original Code and all software distributed under the License are ! 13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 17: * License for the specific language governing rights and limitations ! 18: * under the License. ! 19: * ! 20: * @APPLE_LICENSE_HEADER_END@ ! 21: */ ! 22: /* ! 23: * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1995 ! 24: * The Regents of the University of California. All rights reserved. ! 25: * ! 26: * Redistribution and use in source and binary forms, with or without ! 27: * modification, are permitted provided that the following conditions ! 28: * are met: ! 29: * 1. Redistributions of source code must retain the above copyright ! 30: * notice, this list of conditions and the following disclaimer. ! 31: * 2. Redistributions in binary form must reproduce the above copyright ! 32: * notice, this list of conditions and the following disclaimer in the ! 33: * documentation and/or other materials provided with the distribution. ! 34: * 3. All advertising materials mentioning features or use of this software ! 35: * must display the following acknowledgement: ! 36: * This product includes software developed by the University of ! 37: * California, Berkeley and its contributors. ! 38: * 4. Neither the name of the University nor the names of its contributors ! 39: * may be used to endorse or promote products derived from this software ! 40: * without specific prior written permission. ! 41: * ! 42: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ! 43: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! 44: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! 45: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE ! 46: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! 47: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! 48: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 49: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! 50: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! 51: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! 52: * SUCH DAMAGE. ! 53: * ! 54: * @(#)tcp_subr.c 8.2 (Berkeley) 5/24/95 ! 55: */ ! 56: ! 57: #if ISFB31 ! 58: #include "opt_compat.h" ! 59: #include "opt_tcpdebug.h" ! 60: #endif ! 61: ! 62: #include <sys/param.h> ! 63: #include <sys/systm.h> ! 64: #include <sys/kernel.h> ! 65: #include <sys/sysctl.h> ! 66: #include <sys/malloc.h> ! 67: #include <sys/mbuf.h> ! 68: #include <sys/socket.h> ! 69: #include <sys/socketvar.h> ! 70: #include <sys/protosw.h> ! 71: ! 72: #if ISFB31 ! 73: #include <vm/vm_zone.h> ! 74: #endif ! 75: ! 76: #include <net/route.h> ! 77: #include <net/if.h> ! 78: ! 79: #define _IP_VHL ! 80: #include <netinet/in.h> ! 81: #include <netinet/in_systm.h> ! 82: #include <netinet/ip.h> ! 83: #include <netinet/in_pcb.h> ! 84: #include <netinet/in_var.h> ! 85: #include <netinet/ip_var.h> ! 86: #include <netinet/tcp.h> ! 87: #include <netinet/tcp_fsm.h> ! 88: #include <netinet/tcp_seq.h> ! 89: #include <netinet/tcp_timer.h> ! 90: #include <netinet/tcp_var.h> ! 91: #include <netinet/tcpip.h> ! 92: #if TCPDEBUG ! 93: #include <netinet/tcp_debug.h> ! 94: #endif ! 95: ! 96: int tcp_mssdflt = TCP_MSS; ! 97: SYSCTL_INT(_net_inet_tcp, TCPCTL_MSSDFLT, mssdflt, ! 98: CTLFLAG_RW, &tcp_mssdflt , 0, ""); ! 99: ! 100: static int tcp_rttdflt = TCPTV_SRTTDFLT / PR_SLOWHZ; ! 101: SYSCTL_INT(_net_inet_tcp, TCPCTL_RTTDFLT, rttdflt, ! 102: CTLFLAG_RW, &tcp_rttdflt , 0, ""); ! 103: ! 104: static int tcp_do_rfc1323 = 1; ! 105: SYSCTL_INT(_net_inet_tcp, TCPCTL_DO_RFC1323, rfc1323, ! 106: CTLFLAG_RW, &tcp_do_rfc1323 , 0, ""); ! 107: ! 108: static int tcp_do_rfc1644 = 0; ! 109: SYSCTL_INT(_net_inet_tcp, TCPCTL_DO_RFC1644, rfc1644, ! 110: CTLFLAG_RW, &tcp_do_rfc1644 , 0, ""); ! 111: ! 112: SYSCTL_INT(_net_inet_tcp, OID_AUTO, pcbcount, CTLFLAG_RD, &tcbinfo.ipi_count, ! 113: 0, "Number of active PCBs"); ! 114: ! 115: static void tcp_cleartaocache __P((void)); ! 116: static void tcp_notify __P((struct inpcb *, int)); ! 117: ! 118: /* ! 119: * Target size of TCP PCB hash tables. Must be a power of two. ! 120: * ! 121: * Note that this can be overridden by the kernel environment ! 122: * variable net.inet.tcp.tcbhashsize ! 123: */ ! 124: #ifndef TCBHASHSIZE ! 125: #define TCBHASHSIZE 4096 ! 126: #endif ! 127: ! 128: /* ! 129: * This is the actual shape of what we allocate using the zone ! 130: * allocator. Doing it this way allows us to protect both structures ! 131: * using the same generation count, and also eliminates the overhead ! 132: * of allocating tcpcbs separately. By hiding the structure here, ! 133: * we avoid changing most of the rest of the code (although it needs ! 134: * to be changed, eventually, for greater efficiency). ! 135: */ ! 136: #define ALIGNMENT 32 ! 137: #define ALIGNM1 (ALIGNMENT - 1) ! 138: struct inp_tp { ! 139: union { ! 140: struct inpcb inp; ! 141: char align[(sizeof(struct inpcb) + ALIGNM1) & ~ALIGNM1]; ! 142: } inp_tp_u; ! 143: struct tcpcb tcb; ! 144: }; ! 145: #undef ALIGNMENT ! 146: #undef ALIGNM1 ! 147: ! 148: static struct tcpcb dummy_tcb; ! 149: ! 150: /* ! 151: * Tcp initialization ! 152: */ ! 153: void ! 154: tcp_init() ! 155: { ! 156: int hashsize; ! 157: vm_size_t str_size; ! 158: ! 159: ! 160: tcp_iss = random(); /* wrong, but better than a constant */ ! 161: tcp_ccgen = 1; ! 162: tcp_cleartaocache(); ! 163: LIST_INIT(&tcb); ! 164: tcbinfo.listhead = &tcb; ! 165: if (!(getenv_int("net.inet.tcp.tcbhashsize", &hashsize))) ! 166: hashsize = TCBHASHSIZE; ! 167: if (!powerof2(hashsize)) { ! 168: printf("WARNING: TCB hash size not a power of 2\n"); ! 169: hashsize = 512; /* safe default */ ! 170: } ! 171: tcbinfo.hashbase = hashinit(hashsize, M_PCB, &tcbinfo.hashmask); ! 172: tcbinfo.porthashbase = hashinit(hashsize, M_PCB, ! 173: &tcbinfo.porthashmask); ! 174: #if ISFB31 ! 175: tcbinfo.ipi_zone = (void *) zinit("tcpcb", sizeof(struct inp_tp), maxsockets, ! 176: ZONE_INTERRUPT, 0); ! 177: #else ! 178: str_size = (vm_size_t) sizeof(struct inp_tp); ! 179: tcbinfo.ipi_zone = (void *) zinit(str_size, 120000*str_size, 8192, "inpcb_zone"); ! 180: #endif ! 181: ! 182: ! 183: if (max_protohdr < sizeof(struct tcpiphdr)) ! 184: max_protohdr = sizeof(struct tcpiphdr); ! 185: if (max_linkhdr + sizeof(struct tcpiphdr) > MHLEN) ! 186: panic("tcp_init"); ! 187: ! 188: tcbinfo.last_pcb = 0; ! 189: dummy_tcb.t_state = TCP_NSTATES; ! 190: dummy_tcb.t_flags = 0; ! 191: tcbinfo.dummy_cb = (caddr_t) &dummy_tcb; ! 192: in_pcb_nat_init(&tcbinfo, AF_INET, IPPROTO_TCP, SOCK_STREAM); ! 193: } ! 194: ! 195: /* ! 196: * Create template to be used to send tcp packets on a connection. ! 197: * Call after host entry created, allocates an mbuf and fills ! 198: * in a skeletal tcp/ip header, minimizing the amount of work ! 199: * necessary when the connection is used. ! 200: */ ! 201: struct tcpiphdr * ! 202: tcp_template(tp) ! 203: struct tcpcb *tp; ! 204: { ! 205: register struct inpcb *inp = tp->t_inpcb; ! 206: register struct mbuf *m; ! 207: register struct tcpiphdr *n; ! 208: ! 209: if ((n = tp->t_template) == 0) { ! 210: m = m_get(M_DONTWAIT, MT_HEADER); ! 211: if (m == NULL) ! 212: return (0); ! 213: m->m_len = sizeof (struct tcpiphdr); ! 214: n = mtod(m, struct tcpiphdr *); ! 215: } ! 216: bzero(n->ti_x1, sizeof(n->ti_x1)); ! 217: n->ti_pr = IPPROTO_TCP; ! 218: n->ti_len = htons(sizeof (struct tcpiphdr) - sizeof (struct ip)); ! 219: n->ti_src = inp->inp_laddr; ! 220: n->ti_dst = inp->inp_faddr; ! 221: n->ti_sport = inp->inp_lport; ! 222: n->ti_dport = inp->inp_fport; ! 223: n->ti_seq = 0; ! 224: n->ti_ack = 0; ! 225: n->ti_x2 = 0; ! 226: n->ti_off = 5; ! 227: n->ti_flags = 0; ! 228: n->ti_win = 0; ! 229: n->ti_sum = 0; ! 230: n->ti_urp = 0; ! 231: return (n); ! 232: } ! 233: ! 234: /* ! 235: * Send a single message to the TCP at address specified by ! 236: * the given TCP/IP header. If m == 0, then we make a copy ! 237: * of the tcpiphdr at ti and send directly to the addressed host. ! 238: * This is used to force keep alive messages out using the TCP ! 239: * template for a connection tp->t_template. If flags are given ! 240: * then we send a message back to the TCP which originated the ! 241: * segment ti, and discard the mbuf containing it and any other ! 242: * attached mbufs. ! 243: * ! 244: * In any case the ack and sequence number of the transmitted ! 245: * segment are as specified by the parameters. ! 246: * ! 247: * NOTE: If m != NULL, then ti must point to *inside* the mbuf. ! 248: */ ! 249: void ! 250: tcp_respond(tp, ti, m, ack, seq, flags) ! 251: struct tcpcb *tp; ! 252: register struct tcpiphdr *ti; ! 253: register struct mbuf *m; ! 254: tcp_seq ack, seq; ! 255: int flags; ! 256: { ! 257: register int tlen; ! 258: int win = 0; ! 259: struct route *ro = 0; ! 260: struct route sro; ! 261: ! 262: if (tp) { ! 263: if (!(flags & TH_RST)) ! 264: win = sbspace(&tp->t_inpcb->inp_socket->so_rcv); ! 265: ro = &tp->t_inpcb->inp_route; ! 266: } else { ! 267: ro = &sro; ! 268: bzero(ro, sizeof *ro); ! 269: } ! 270: if (m == 0) { ! 271: m = m_gethdr(M_DONTWAIT, MT_HEADER); ! 272: if (m == NULL) ! 273: return; ! 274: #if TCP_COMPAT_42 ! 275: tlen = 1; ! 276: #else ! 277: tlen = 0; ! 278: #endif ! 279: m->m_data += max_linkhdr; ! 280: *mtod(m, struct tcpiphdr *) = *ti; ! 281: ti = mtod(m, struct tcpiphdr *); ! 282: flags = TH_ACK; ! 283: } else { ! 284: m_freem(m->m_next); ! 285: m->m_next = 0; ! 286: m->m_data = (caddr_t)ti; ! 287: m->m_len = sizeof (struct tcpiphdr); ! 288: tlen = 0; ! 289: #define xchg(a,b,type) { type t; t=a; a=b; b=t; } ! 290: xchg(ti->ti_dst.s_addr, ti->ti_src.s_addr, n_long); ! 291: xchg(ti->ti_dport, ti->ti_sport, n_short); ! 292: #undef xchg ! 293: } ! 294: ti->ti_len = htons((u_short)(sizeof (struct tcphdr) + tlen)); ! 295: tlen += sizeof (struct tcpiphdr); ! 296: m->m_len = tlen; ! 297: m->m_pkthdr.len = tlen; ! 298: m->m_pkthdr.rcvif = (struct ifnet *) 0; ! 299: bzero(ti->ti_x1, sizeof(ti->ti_x1)); ! 300: ti->ti_seq = htonl(seq); ! 301: ti->ti_ack = htonl(ack); ! 302: ti->ti_x2 = 0; ! 303: ti->ti_off = sizeof (struct tcphdr) >> 2; ! 304: ti->ti_flags = flags; ! 305: if (tp) ! 306: ti->ti_win = htons((u_short) (win >> tp->rcv_scale)); ! 307: else ! 308: ti->ti_win = htons((u_short)win); ! 309: ti->ti_urp = 0; ! 310: ti->ti_sum = 0; ! 311: ti->ti_sum = in_cksum(m, tlen); ! 312: ((struct ip *)ti)->ip_len = tlen; ! 313: ((struct ip *)ti)->ip_ttl = ip_defttl; ! 314: #if TCPDEBUG ! 315: if (tp == NULL || (tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) ! 316: tcp_trace(TA_OUTPUT, 0, tp, ti, 0); ! 317: #endif ! 318: (void) ip_output(m, NULL, ro, 0, NULL); ! 319: if (ro == &sro && ro->ro_rt) { ! 320: RTFREE(ro->ro_rt); ! 321: } ! 322: } ! 323: ! 324: /* ! 325: * Create a new TCP control block, making an ! 326: * empty reassembly queue and hooking it to the argument ! 327: * protocol control block. The `inp' parameter must have ! 328: * come from the zone allocator set up in tcp_init(). ! 329: */ ! 330: struct tcpcb * ! 331: tcp_newtcpcb(inp) ! 332: struct inpcb *inp; ! 333: { ! 334: struct inp_tp *it; ! 335: register struct tcpcb *tp; ! 336: ! 337: it = (struct inp_tp *)inp; ! 338: tp = &it->tcb; ! 339: bzero((char *) tp, sizeof(struct tcpcb)); ! 340: tp->t_segq = NULL; ! 341: tp->t_maxseg = tp->t_maxopd = tcp_mssdflt; ! 342: ! 343: if (tcp_do_rfc1323) ! 344: tp->t_flags = (TF_REQ_SCALE|TF_REQ_TSTMP); ! 345: if (tcp_do_rfc1644) ! 346: tp->t_flags |= TF_REQ_CC; ! 347: tp->t_inpcb = inp; /* XXX */ ! 348: /* ! 349: * Init srtt to TCPTV_SRTTBASE (0), so we can tell that we have no ! 350: * rtt estimate. Set rttvar so that srtt + 4 * rttvar gives ! 351: * reasonable initial retransmit time. ! 352: */ ! 353: tp->t_srtt = TCPTV_SRTTBASE; ! 354: tp->t_rttvar = ((TCPTV_RTOBASE - TCPTV_SRTTBASE) << TCP_RTTVAR_SHIFT) / 4; ! 355: tp->t_rttmin = TCPTV_MIN; ! 356: tp->t_rxtcur = TCPTV_RTOBASE; ! 357: tp->snd_cwnd = TCP_MAXWIN << TCP_MAX_WINSHIFT; ! 358: tp->snd_ssthresh = TCP_MAXWIN << TCP_MAX_WINSHIFT; ! 359: inp->inp_ip_ttl = ip_defttl; ! 360: inp->inp_ppcb = (caddr_t)tp; ! 361: return (tp); /* XXX */ ! 362: } ! 363: ! 364: /* ! 365: * Drop a TCP connection, reporting ! 366: * the specified error. If connection is synchronized, ! 367: * then send a RST to peer. ! 368: */ ! 369: struct tcpcb * ! 370: tcp_drop(tp, errno) ! 371: register struct tcpcb *tp; ! 372: int errno; ! 373: { ! 374: struct socket *so = tp->t_inpcb->inp_socket; ! 375: ! 376: if (TCPS_HAVERCVDSYN(tp->t_state)) { ! 377: tp->t_state = TCPS_CLOSED; ! 378: (void) tcp_output(tp); ! 379: tcpstat.tcps_drops++; ! 380: } else ! 381: tcpstat.tcps_conndrops++; ! 382: if (errno == ETIMEDOUT && tp->t_softerror) ! 383: errno = tp->t_softerror; ! 384: so->so_error = errno; ! 385: return (tcp_close(tp)); ! 386: } ! 387: ! 388: /* ! 389: * Close a TCP control block: ! 390: * discard all space held by the tcp ! 391: * discard internet protocol block ! 392: * wake up any sleepers ! 393: */ ! 394: struct tcpcb * ! 395: tcp_close(tp) ! 396: register struct tcpcb *tp; ! 397: { ! 398: register struct mbuf *q; ! 399: register struct mbuf *nq; ! 400: struct inpcb *inp = tp->t_inpcb; ! 401: struct socket *so = inp->inp_socket; ! 402: register struct rtentry *rt; ! 403: int dosavessthresh; ! 404: ! 405: /* ! 406: * If we got enough samples through the srtt filter, ! 407: * save the rtt and rttvar in the routing entry. ! 408: * 'Enough' is arbitrarily defined as the 16 samples. ! 409: * 16 samples is enough for the srtt filter to converge ! 410: * to within 5% of the correct value; fewer samples and ! 411: * we could save a very bogus rtt. ! 412: * ! 413: * Don't update the default route's characteristics and don't ! 414: * update anything that the user "locked". ! 415: */ ! 416: if (tp->t_rttupdated >= 16 && ! 417: (rt = inp->inp_route.ro_rt) && ! 418: ((struct sockaddr_in *)rt_key(rt))->sin_addr.s_addr != INADDR_ANY) { ! 419: register u_long i = 0; ! 420: ! 421: if ((rt->rt_rmx.rmx_locks & RTV_RTT) == 0) { ! 422: i = tp->t_srtt * ! 423: (RTM_RTTUNIT / (PR_SLOWHZ * TCP_RTT_SCALE)); ! 424: if (rt->rt_rmx.rmx_rtt && i) ! 425: /* ! 426: * filter this update to half the old & half ! 427: * the new values, converting scale. ! 428: * See route.h and tcp_var.h for a ! 429: * description of the scaling constants. ! 430: */ ! 431: rt->rt_rmx.rmx_rtt = ! 432: (rt->rt_rmx.rmx_rtt + i) / 2; ! 433: else ! 434: rt->rt_rmx.rmx_rtt = i; ! 435: tcpstat.tcps_cachedrtt++; ! 436: } ! 437: if ((rt->rt_rmx.rmx_locks & RTV_RTTVAR) == 0) { ! 438: i = tp->t_rttvar * ! 439: (RTM_RTTUNIT / (PR_SLOWHZ * TCP_RTTVAR_SCALE)); ! 440: if (rt->rt_rmx.rmx_rttvar && i) ! 441: rt->rt_rmx.rmx_rttvar = ! 442: (rt->rt_rmx.rmx_rttvar + i) / 2; ! 443: else ! 444: rt->rt_rmx.rmx_rttvar = i; ! 445: tcpstat.tcps_cachedrttvar++; ! 446: } ! 447: /* ! 448: * The old comment here said: ! 449: * update the pipelimit (ssthresh) if it has been updated ! 450: * already or if a pipesize was specified & the threshhold ! 451: * got below half the pipesize. I.e., wait for bad news ! 452: * before we start updating, then update on both good ! 453: * and bad news. ! 454: * ! 455: * But we want to save the ssthresh even if no pipesize is ! 456: * specified explicitly in the route, because such ! 457: * connections still have an implicit pipesize specified ! 458: * by the global tcp_sendspace. In the absence of a reliable ! 459: * way to calculate the pipesize, it will have to do. ! 460: */ ! 461: i = tp->snd_ssthresh; ! 462: if (rt->rt_rmx.rmx_sendpipe != 0) ! 463: dosavessthresh = (i < rt->rt_rmx.rmx_sendpipe / 2); ! 464: else ! 465: dosavessthresh = (i < so->so_snd.sb_hiwat / 2); ! 466: if (((rt->rt_rmx.rmx_locks & RTV_SSTHRESH) == 0 && ! 467: i != 0 && rt->rt_rmx.rmx_ssthresh != 0) ! 468: || dosavessthresh) { ! 469: /* ! 470: * convert the limit from user data bytes to ! 471: * packets then to packet data bytes. ! 472: */ ! 473: i = (i + tp->t_maxseg / 2) / tp->t_maxseg; ! 474: if (i < 2) ! 475: i = 2; ! 476: i *= (u_long)(tp->t_maxseg + sizeof (struct tcpiphdr)); ! 477: if (rt->rt_rmx.rmx_ssthresh) ! 478: rt->rt_rmx.rmx_ssthresh = ! 479: (rt->rt_rmx.rmx_ssthresh + i) / 2; ! 480: else ! 481: rt->rt_rmx.rmx_ssthresh = i; ! 482: tcpstat.tcps_cachedssthresh++; ! 483: } ! 484: } ! 485: /* free the reassembly queue, if any */ ! 486: for (q = tp->t_segq; q; q = nq) { ! 487: nq = q->m_nextpkt; ! 488: tp->t_segq = nq; ! 489: m_freem(q); ! 490: } ! 491: if (tp->t_template) ! 492: (void) m_free(dtom(tp->t_template)); ! 493: inp->inp_ppcb = NULL; ! 494: soisdisconnected(so); ! 495: in_pcbdetach(inp); ! 496: tcpstat.tcps_closed++; ! 497: return ((struct tcpcb *)0); ! 498: } ! 499: ! 500: void ! 501: tcp_drain() ! 502: { ! 503: ! 504: } ! 505: ! 506: /* ! 507: * Notify a tcp user of an asynchronous error; ! 508: * store error as soft error, but wake up user ! 509: * (for now, won't do anything until can select for soft error). ! 510: */ ! 511: static void ! 512: tcp_notify(inp, error) ! 513: struct inpcb *inp; ! 514: int error; ! 515: { ! 516: register struct tcpcb *tp = (struct tcpcb *)inp->inp_ppcb; ! 517: register struct socket *so = inp->inp_socket; ! 518: ! 519: /* ! 520: * Ignore some errors if we are hooked up. ! 521: * If connection hasn't completed, has retransmitted several times, ! 522: * and receives a second error, give up now. This is better ! 523: * than waiting a long time to establish a connection that ! 524: * can never complete. ! 525: */ ! 526: if (tp->t_state == TCPS_ESTABLISHED && ! 527: (error == EHOSTUNREACH || error == ENETUNREACH || ! 528: error == EHOSTDOWN)) { ! 529: return; ! 530: } else if (tp->t_state < TCPS_ESTABLISHED && tp->t_rxtshift > 3 && ! 531: tp->t_softerror) ! 532: so->so_error = error; ! 533: else ! 534: tp->t_softerror = error; ! 535: wakeup((caddr_t) &so->so_timeo); ! 536: sorwakeup(so); ! 537: sowwakeup(so); ! 538: } ! 539: ! 540: ! 541: static int ! 542: tcp_pcblist SYSCTL_HANDLER_ARGS ! 543: { ! 544: int error, i, n, s; ! 545: struct inpcb *inp, **inp_list; ! 546: inp_gen_t gencnt; ! 547: struct xinpgen xig; ! 548: ! 549: /* ! 550: * The process of preparing the TCB list is too time-consuming and ! 551: * resource-intensive to repeat twice on every request. ! 552: */ ! 553: if (req->oldptr == 0) { ! 554: n = tcbinfo.ipi_count; ! 555: req->oldidx = 2 * (sizeof xig) ! 556: + (n + n/8) * sizeof(struct xtcpcb); ! 557: return 0; ! 558: } ! 559: ! 560: if (req->newptr != 0) ! 561: return EPERM; ! 562: ! 563: /* ! 564: * OK, now we're committed to doing something. ! 565: */ ! 566: s = splnet(); ! 567: gencnt = tcbinfo.ipi_gencnt; ! 568: n = tcbinfo.ipi_count; ! 569: splx(s); ! 570: ! 571: xig.xig_len = sizeof xig; ! 572: xig.xig_count = n; ! 573: xig.xig_gen = gencnt; ! 574: xig.xig_sogen = so_gencnt; ! 575: error = SYSCTL_OUT(req, &xig, sizeof xig); ! 576: if (error) ! 577: return error; ! 578: ! 579: inp_list = _MALLOC(n * sizeof *inp_list, M_TEMP, M_WAITOK); ! 580: if (inp_list == 0) ! 581: return ENOMEM; ! 582: ! 583: s = splnet(); ! 584: for (inp = tcbinfo.listhead->lh_first, i = 0; inp && i < n; ! 585: inp = inp->inp_list.le_next) { ! 586: if (inp->inp_gencnt <= gencnt) ! 587: inp_list[i++] = inp; ! 588: } ! 589: splx(s); ! 590: n = i; ! 591: ! 592: error = 0; ! 593: for (i = 0; i < n; i++) { ! 594: inp = inp_list[i]; ! 595: if (inp->inp_gencnt <= gencnt) { ! 596: struct xtcpcb xt; ! 597: xt.xt_len = sizeof xt; ! 598: /* XXX should avoid extra copy */ ! 599: bcopy(inp, &xt.xt_inp, sizeof *inp); ! 600: bcopy(inp->inp_ppcb, &xt.xt_tp, sizeof xt.xt_tp); ! 601: if (inp->inp_socket) ! 602: sotoxsocket(inp->inp_socket, &xt.xt_socket); ! 603: error = SYSCTL_OUT(req, &xt, sizeof xt); ! 604: } ! 605: } ! 606: if (!error) { ! 607: /* ! 608: * Give the user an updated idea of our state. ! 609: * If the generation differs from what we told ! 610: * her before, she knows that something happened ! 611: * while we were processing this request, and it ! 612: * might be necessary to retry. ! 613: */ ! 614: s = splnet(); ! 615: xig.xig_gen = tcbinfo.ipi_gencnt; ! 616: xig.xig_sogen = so_gencnt; ! 617: xig.xig_count = tcbinfo.ipi_count; ! 618: splx(s); ! 619: error = SYSCTL_OUT(req, &xig, sizeof xig); ! 620: } ! 621: FREE(inp_list, M_TEMP); ! 622: return error; ! 623: } ! 624: ! 625: ! 626: SYSCTL_PROC(_net_inet_tcp, TCPCTL_PCBLIST, pcblist, CTLFLAG_RD, 0, 0, ! 627: tcp_pcblist, "S,xtcpcb", "List of active TCP connections"); ! 628: ! 629: void ! 630: tcp_ctlinput(cmd, sa, vip) ! 631: int cmd; ! 632: struct sockaddr *sa; ! 633: void *vip; ! 634: { ! 635: register struct ip *ip = vip; ! 636: register struct tcphdr *th; ! 637: void (*notify) __P((struct inpcb *, int)) = tcp_notify; ! 638: ! 639: if (cmd == PRC_QUENCH) ! 640: notify = tcp_quench; ! 641: else if (cmd == PRC_MSGSIZE) ! 642: notify = tcp_mtudisc; ! 643: else if (!PRC_IS_REDIRECT(cmd) && ! 644: ((unsigned)cmd > PRC_NCMDS || inetctlerrmap[cmd] == 0)) ! 645: return; ! 646: if (ip) { ! 647: th = (struct tcphdr *)((caddr_t)ip ! 648: + (IP_VHL_HL(ip->ip_vhl) << 2)); ! 649: in_pcbnotify(&tcb, sa, th->th_dport, ip->ip_src, th->th_sport, ! 650: cmd, notify); ! 651: } else ! 652: in_pcbnotify(&tcb, sa, 0, zeroin_addr, 0, cmd, notify); ! 653: } ! 654: ! 655: /* ! 656: * When a source quench is received, close congestion window ! 657: * to one segment. We will gradually open it again as we proceed. ! 658: */ ! 659: void ! 660: tcp_quench(inp, errno) ! 661: struct inpcb *inp; ! 662: int errno; ! 663: { ! 664: struct tcpcb *tp = intotcpcb(inp); ! 665: ! 666: if (tp) ! 667: tp->snd_cwnd = tp->t_maxseg; ! 668: } ! 669: ! 670: /* ! 671: * When `need fragmentation' ICMP is received, update our idea of the MSS ! 672: * based on the new value in the route. Also nudge TCP to send something, ! 673: * since we know the packet we just sent was dropped. ! 674: * This duplicates some code in the tcp_mss() function in tcp_input.c. ! 675: */ ! 676: void ! 677: tcp_mtudisc(inp, errno) ! 678: struct inpcb *inp; ! 679: int errno; ! 680: { ! 681: struct tcpcb *tp = intotcpcb(inp); ! 682: struct rtentry *rt; ! 683: struct rmxp_tao *taop; ! 684: struct socket *so = inp->inp_socket; ! 685: int offered; ! 686: int mss; ! 687: ! 688: if (tp) { ! 689: rt = tcp_rtlookup(inp); ! 690: if (!rt || !rt->rt_rmx.rmx_mtu) { ! 691: tp->t_maxopd = tp->t_maxseg = tcp_mssdflt; ! 692: return; ! 693: } ! 694: taop = rmx_taop(rt->rt_rmx); ! 695: offered = taop->tao_mssopt; ! 696: mss = rt->rt_rmx.rmx_mtu - sizeof(struct tcpiphdr); ! 697: if (offered) ! 698: mss = min(mss, offered); ! 699: /* ! 700: * XXX - The above conditional probably violates the TCP ! 701: * spec. The problem is that, since we don't know the ! 702: * other end's MSS, we are supposed to use a conservative ! 703: * default. But, if we do that, then MTU discovery will ! 704: * never actually take place, because the conservative ! 705: * default is much less than the MTUs typically seen ! 706: * on the Internet today. For the moment, we'll sweep ! 707: * this under the carpet. ! 708: * ! 709: * The conservative default might not actually be a problem ! 710: * if the only case this occurs is when sending an initial ! 711: * SYN with options and data to a host we've never talked ! 712: * to before. Then, they will reply with an MSS value which ! 713: * will get recorded and the new parameters should get ! 714: * recomputed. For Further Study. ! 715: */ ! 716: if (tp->t_maxopd <= mss) ! 717: return; ! 718: tp->t_maxopd = mss; ! 719: ! 720: if ((tp->t_flags & (TF_REQ_TSTMP|TF_NOOPT)) == TF_REQ_TSTMP && ! 721: (tp->t_flags & TF_RCVD_TSTMP) == TF_RCVD_TSTMP) ! 722: mss -= TCPOLEN_TSTAMP_APPA; ! 723: if ((tp->t_flags & (TF_REQ_CC|TF_NOOPT)) == TF_REQ_CC && ! 724: (tp->t_flags & TF_RCVD_CC) == TF_RCVD_CC) ! 725: mss -= TCPOLEN_CC_APPA; ! 726: #if (MCLBYTES & (MCLBYTES - 1)) == 0 ! 727: if (mss > MCLBYTES) ! 728: mss &= ~(MCLBYTES-1); ! 729: #else ! 730: if (mss > MCLBYTES) ! 731: mss = mss / MCLBYTES * MCLBYTES; ! 732: #endif ! 733: if (so->so_snd.sb_hiwat < mss) ! 734: mss = so->so_snd.sb_hiwat; ! 735: ! 736: tp->t_maxseg = mss; ! 737: ! 738: tcpstat.tcps_mturesent++; ! 739: tp->t_rtt = 0; ! 740: tp->snd_nxt = tp->snd_una; ! 741: tcp_output(tp); ! 742: } ! 743: } ! 744: ! 745: /* ! 746: * Look-up the routing entry to the peer of this inpcb. If no route ! 747: * is found and it cannot be allocated the return NULL. This routine ! 748: * is called by TCP routines that access the rmx structure and by tcp_mss ! 749: * to get the interface MTU. ! 750: */ ! 751: struct rtentry * ! 752: tcp_rtlookup(inp) ! 753: struct inpcb *inp; ! 754: { ! 755: struct route *ro; ! 756: struct rtentry *rt; ! 757: ! 758: ro = &inp->inp_route; ! 759: rt = ro->ro_rt; ! 760: if (rt == NULL || !(rt->rt_flags & RTF_UP)) { ! 761: /* No route yet, so try to acquire one */ ! 762: if (inp->inp_faddr.s_addr != INADDR_ANY) { ! 763: ro->ro_dst.sa_family = AF_INET; ! 764: ro->ro_dst.sa_len = sizeof(ro->ro_dst); ! 765: ((struct sockaddr_in *) &ro->ro_dst)->sin_addr = ! 766: inp->inp_faddr; ! 767: rtalloc(ro); ! 768: rt = ro->ro_rt; ! 769: } ! 770: } ! 771: return rt; ! 772: } ! 773: ! 774: /* ! 775: * Return a pointer to the cached information about the remote host. ! 776: * The cached information is stored in the protocol specific part of ! 777: * the route metrics. ! 778: */ ! 779: struct rmxp_tao * ! 780: tcp_gettaocache(inp) ! 781: struct inpcb *inp; ! 782: { ! 783: struct rtentry *rt = tcp_rtlookup(inp); ! 784: ! 785: /* Make sure this is a host route and is up. */ ! 786: if (rt == NULL || ! 787: (rt->rt_flags & (RTF_UP|RTF_HOST)) != (RTF_UP|RTF_HOST)) ! 788: return NULL; ! 789: ! 790: return rmx_taop(rt->rt_rmx); ! 791: } ! 792: ! 793: /* ! 794: * Clear all the TAO cache entries, called from tcp_init. ! 795: * ! 796: * XXX ! 797: * This routine is just an empty one, because we assume that the routing ! 798: * routing tables are initialized at the same time when TCP, so there is ! 799: * nothing in the cache left over. ! 800: */ ! 801: static void ! 802: tcp_cleartaocache() ! 803: { ! 804: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.