|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights ! 7: * Reserved. This file contains Original Code and/or Modifications of ! 8: * Original Code as defined in and that are subject to the Apple Public ! 9: * Source License Version 1.1 (the "License"). You may not use this file ! 10: * except in compliance with the License. Please obtain a copy of the ! 11: * License at http://www.apple.com/publicsource and read it before using ! 12: * this file. ! 13: * ! 14: * The Original Code and all software distributed under the License are ! 15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 19: * License for the specific language governing rights and limitations ! 20: * under the License. ! 21: * ! 22: * @APPLE_LICENSE_HEADER_END@ ! 23: */ ! 24: ! 25: /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */ ! 26: /* ! 27: * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1995 ! 28: * The Regents of the University of California. All rights reserved. ! 29: * ! 30: * Redistribution and use in source and binary forms, with or without ! 31: * modification, are permitted provided that the following conditions ! 32: * are met: ! 33: * 1. Redistributions of source code must retain the above copyright ! 34: * notice, this list of conditions and the following disclaimer. ! 35: * 2. Redistributions in binary form must reproduce the above copyright ! 36: * notice, this list of conditions and the following disclaimer in the ! 37: * documentation and/or other materials provided with the distribution. ! 38: * 3. All advertising materials mentioning features or use of this software ! 39: * must display the following acknowledgement: ! 40: * This product includes software developed by the University of ! 41: * California, Berkeley and its contributors. ! 42: * 4. Neither the name of the University nor the names of its contributors ! 43: * may be used to endorse or promote products derived from this software ! 44: * without specific prior written permission. ! 45: * ! 46: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ! 47: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! 48: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! 49: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE ! 50: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! 51: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! 52: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 53: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! 54: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! 55: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! 56: * SUCH DAMAGE. ! 57: * ! 58: * @(#)tcp_subr.c 8.2 (Berkeley) 5/24/95 ! 59: */ ! 60: ! 61: #include <sys/param.h> ! 62: #include <sys/proc.h> ! 63: #include <sys/systm.h> ! 64: #include <sys/malloc.h> ! 65: #include <sys/mbuf.h> ! 66: #include <sys/socket.h> ! 67: #include <sys/socketvar.h> ! 68: #include <sys/protosw.h> ! 69: #include <sys/errno.h> ! 70: ! 71: #include <net/route.h> ! 72: #include <net/if.h> ! 73: ! 74: #include <netinet/in.h> ! 75: #include <netinet/in_systm.h> ! 76: #include <netinet/ip.h> ! 77: #include <netinet/in_pcb.h> ! 78: #include <netinet/ip_var.h> ! 79: #include <netinet/ip_icmp.h> ! 80: #include <netinet/tcp.h> ! 81: #include <netinet/tcp_fsm.h> ! 82: #include <netinet/tcp_seq.h> ! 83: #include <netinet/tcp_timer.h> ! 84: #include <netinet/tcp_var.h> ! 85: #include <netinet/tcpip.h> ! 86: ! 87: #include <kern/kdebug.h> ! 88: ! 89: extern struct inpcb *tcp_hash_array[]; ! 90: extern struct inpcb *tcp_lport_hash_array[]; ! 91: ! 92: ! 93: #if KDEBUG ! 94: ! 95: #define DBG_FNC_TCP_CLOSE NETDBG_CODE(DBG_NETTCP, ((5 << 8) | 2)) ! 96: ! 97: #endif ! 98: ! 99: #ifndef SOCKET_CACHE_ON ! 100: struct zone *tcpcb_zone; ! 101: #endif ! 102: ! 103: extern struct zone *inpcb_zone; ! 104: ! 105: struct inpcb tcb; /* head of queue of active tcpcb's */ ! 106: ! 107: ! 108: struct tcpstat tcpstat; /* tcp statistics */ ! 109: u_long tcp_now; /* for RFC 1323 timestamps */ ! 110: tcp_seq tcp_iss; /* tcp initial send seq # */ ! 111: ! 112: /* patchable/settable parameters for tcp */ ! 113: int tcp_mssdflt = TCP_MSS; ! 114: int tcp_rttdflt = TCPTV_SRTTDFLT / PR_SLOWHZ; ! 115: int tcp_do_rfc1323 = 1; ! 116: int memzone_init_done = 0; ! 117: ! 118: ! 119: extern struct inpcb time_wait_slots[]; ! 120: extern int cur_tw_slot; ! 121: ! 122: #if DELACK_BITMASK_ON ! 123: extern u_long delack_bitmask[]; ! 124: #endif ! 125: ! 126: void tcpip_memzone_init() ! 127: { ! 128: vm_size_t str_size; ! 129: ! 130: if (memzone_init_done == 0) { ! 131: memzone_init_done = 1; ! 132: ! 133: #ifndef SOCKET_CACHE_ON ! 134: str_size = (vm_size_t) sizeof(struct tcpcb); ! 135: tcpcb_zone = zinit (str_size, 120000*str_size, 8192, FALSE, "tcpcb zone"); ! 136: #endif ! 137: str_size = (vm_size_t) sizeof(struct inpcb); ! 138: inpcb_zone = zinit (str_size, 120000*str_size, 8192, FALSE, "inpcb zone"); ! 139: } ! 140: } ! 141: ! 142: int get_inpcb_str_size() ! 143: { ! 144: return sizeof(struct inpcb); ! 145: } ! 146: ! 147: ! 148: int get_tcp_str_size() ! 149: { ! 150: return sizeof(struct tcpcb); ! 151: } ! 152: ! 153: ! 154: /* ! 155: * Tcp initialization ! 156: */ ! 157: void ! 158: tcp_init() ! 159: { ! 160: int i; ! 161: ! 162: tcp_iss = random(); /* wrong, but better than a constant */ ! 163: for (i=0; i < N_TCP_HASH_ELEMENTS; i++) ! 164: tcp_hash_array[i] = 0; ! 165: ! 166: #if DELACK_BITMASK_ON ! 167: for (i=0; i < (N_TCP_HASH_ELEMENTS / 32); i++) ! 168: delack_bitmask[i] = 0; ! 169: #endif ! 170: for (i=0; i < N_TCP_LPORT_HASH_ELEMENTS; i++) ! 171: tcp_lport_hash_array[i] = 0; ! 172: ! 173: for (i=0; i < N_TIME_WAIT_SLOTS; i++) { ! 174: time_wait_slots[i].inp_next = &time_wait_slots[i]; ! 175: time_wait_slots[i].inp_prev = &time_wait_slots[i]; ! 176: } ! 177: ! 178: tcpip_memzone_init(); ! 179: tcb.inp_next = &tcb; ! 180: tcb.inp_prev = &tcb; ! 181: ! 182: if (max_protohdr < sizeof(struct tcpiphdr)) ! 183: max_protohdr = sizeof(struct tcpiphdr); ! 184: if (max_linkhdr + sizeof(struct tcpiphdr) > MHLEN) ! 185: panic("tcp_init"); ! 186: ! 187: ! 188: } ! 189: ! 190: /* ! 191: * Create template to be used to send tcp packets on a connection. ! 192: * Call after host entry created, allocates an mbuf and fills ! 193: * in a skeletal tcp/ip header, minimizing the amount of work ! 194: * necessary when the connection is used. ! 195: */ ! 196: struct tcpiphdr * ! 197: tcp_template(tp) ! 198: struct tcpcb *tp; ! 199: { ! 200: register struct inpcb *inp = tp->t_inpcb; ! 201: register struct mbuf *m; ! 202: register struct tcpiphdr *n; ! 203: ! 204: if ((n = tp->t_template) == 0) { ! 205: m = m_get(M_DONTWAIT, MT_HEADER); ! 206: if (m == NULL) ! 207: return (0); ! 208: m->m_len = sizeof (struct tcpiphdr); ! 209: n = mtod(m, struct tcpiphdr *); ! 210: } ! 211: n->ti_next = n->ti_prev = 0; ! 212: n->ti_x1 = 0; ! 213: n->ti_pr = IPPROTO_TCP; ! 214: n->ti_len = htons(sizeof (struct tcpiphdr) - sizeof (struct ip)); ! 215: n->ti_src = inp->inp_laddr; ! 216: n->ti_dst = inp->inp_faddr; ! 217: n->ti_sport = inp->inp_lport; ! 218: n->ti_dport = inp->inp_fport; ! 219: n->ti_seq = 0; ! 220: n->ti_ack = 0; ! 221: n->ti_x2 = 0; ! 222: n->ti_off = 5; ! 223: n->ti_flags = 0; ! 224: n->ti_win = 0; ! 225: n->ti_sum = 0; ! 226: n->ti_urp = 0; ! 227: return (n); ! 228: } ! 229: ! 230: ! 231: /* ! 232: * Send a single message to the TCP at address specified by ! 233: * the given TCP/IP header. If m == 0, then we make a copy ! 234: * of the tcpiphdr at ti and send directly to the addressed host. ! 235: * This is used to force keep alive messages out using the TCP ! 236: * template for a connection tp->t_template. If flags are given ! 237: * then we send a message back to the TCP which originated the ! 238: * segment ti, and discard the mbuf containing it and any other ! 239: * attached mbufs. ! 240: * ! 241: * In any case the ack and sequence number of the transmitted ! 242: * segment are as specified by the parameters. ! 243: */ ! 244: void ! 245: tcp_respond(tp, ti, m, ack, seq, flags) ! 246: struct tcpcb *tp; ! 247: register struct tcpiphdr *ti; ! 248: register struct mbuf *m; ! 249: tcp_seq ack, seq; ! 250: int flags; ! 251: { ! 252: register int tlen; ! 253: int win = 0; ! 254: struct route *ro = 0; ! 255: ! 256: if (tp) { ! 257: win = sbspace(&tp->t_inpcb->inp_socket->so_rcv); ! 258: ro = &tp->t_inpcb->inp_route; ! 259: } ! 260: if (m == 0) { ! 261: m = m_gethdr(M_DONTWAIT, MT_HEADER); ! 262: if (m == NULL) ! 263: return; ! 264: #ifdef TCP_COMPAT_42 ! 265: tlen = 1; ! 266: #else ! 267: tlen = 0; ! 268: #endif ! 269: m->m_data += max_linkhdr; ! 270: *mtod(m, struct tcpiphdr *) = *ti; ! 271: ti = mtod(m, struct tcpiphdr *); ! 272: flags = TH_ACK; ! 273: } else { ! 274: m_freem(m->m_next); ! 275: m->m_next = 0; ! 276: m->m_data = (caddr_t)ti; ! 277: m->m_len = sizeof (struct tcpiphdr); ! 278: tlen = 0; ! 279: #define xchg(a,b,type) { type t; t=a; a=b; b=t; } ! 280: xchg(ti->ti_dst.s_addr, ti->ti_src.s_addr, u_long); ! 281: xchg(ti->ti_dport, ti->ti_sport, u_short); ! 282: #undef xchg ! 283: } ! 284: ti->ti_len = htons((u_short)(sizeof (struct tcphdr) + tlen)); ! 285: tlen += sizeof (struct tcpiphdr); ! 286: m->m_len = tlen; ! 287: m->m_pkthdr.len = tlen; ! 288: m->m_pkthdr.rcvif = (struct ifnet *) 0; ! 289: ti->ti_next = ti->ti_prev = 0; ! 290: ti->ti_x1 = 0; ! 291: ti->ti_seq = htonl(seq); ! 292: ti->ti_ack = htonl(ack); ! 293: ti->ti_x2 = 0; ! 294: ti->ti_off = sizeof (struct tcphdr) >> 2; ! 295: ti->ti_flags = flags; ! 296: if (tp) ! 297: ti->ti_win = htons((u_short) (win >> tp->rcv_scale)); ! 298: else ! 299: ti->ti_win = htons((u_short)win); ! 300: ti->ti_urp = 0; ! 301: ti->ti_sum = 0; ! 302: ti->ti_sum = in_cksum(m, tlen); ! 303: ((struct ip *)ti)->ip_len = tlen; ! 304: ((struct ip *)ti)->ip_ttl = ip_defttl; ! 305: (void) ip_output(m, NULL, ro, 0, NULL); ! 306: } ! 307: ! 308: /* ! 309: * Create a new TCP control block, making an ! 310: * empty reassembly queue and hooking it to the argument ! 311: * protocol control block. ! 312: */ ! 313: struct tcpcb * ! 314: tcp_newtcpcb(inp) ! 315: struct inpcb *inp; ! 316: { ! 317: register struct tcpcb *tp; ! 318: register struct socket *so = inp->inp_socket; ! 319: ! 320: #ifndef SOCKET_CACHE_ON ! 321: if (so->cached_in_sock_layer == 0) { ! 322: tp = (struct tcpcb *) zalloc_noblock(tcpcb_zone); ! 323: if (tp == NULL) ! 324: return ((struct tcpcb *)0); ! 325: } ! 326: else ! 327: #endif ! 328: tp = inp->inp_saved_ppcb; ! 329: ! 330: bzero((char *) tp, sizeof(struct tcpcb)); ! 331: tp->seg_next = tp->seg_prev = (struct tcpiphdr *)tp; ! 332: tp->t_maxseg = tcp_mssdflt; ! 333: ! 334: tp->t_flags = tcp_do_rfc1323 ? (TF_REQ_SCALE|TF_REQ_TSTMP) : 0; ! 335: tp->t_inpcb = inp; ! 336: /* ! 337: * Init srtt to TCPTV_SRTTBASE (0), so we can tell that we have no ! 338: * rtt estimate. Set rttvar so that srtt + 2 * rttvar gives ! 339: * reasonable initial retransmit time. ! 340: */ ! 341: tp->t_srtt = TCPTV_SRTTBASE; ! 342: tp->t_rttvar = tcp_rttdflt * PR_SLOWHZ << 2; ! 343: tp->t_rttmin = TCPTV_MIN; ! 344: TCPT_RANGESET(tp->t_rxtcur, ! 345: ((TCPTV_SRTTBASE >> 2) + (TCPTV_SRTTDFLT << 2)) >> 1, ! 346: TCPTV_MIN, TCPTV_REXMTMAX); ! 347: tp->snd_cwnd = TCP_MAXWIN << TCP_MAX_WINSHIFT; ! 348: tp->snd_ssthresh = TCP_MAXWIN << TCP_MAX_WINSHIFT; ! 349: inp->inp_ip.ip_ttl = ip_defttl; ! 350: inp->inp_ppcb = (caddr_t)tp; ! 351: return (tp); ! 352: } ! 353: ! 354: /* ! 355: * Drop a TCP connection, reporting ! 356: * the specified error. If connection is synchronized, ! 357: * then send a RST to peer. ! 358: */ ! 359: struct tcpcb * ! 360: tcp_drop(tp, errno) ! 361: register struct tcpcb *tp; ! 362: int errno; ! 363: { ! 364: struct socket *so = tp->t_inpcb->inp_socket; ! 365: ! 366: if (TCPS_HAVERCVDSYN(tp->t_state)) { ! 367: tp->t_state = TCPS_CLOSED; ! 368: (void) tcp_output(tp); ! 369: tcpstat.tcps_drops++; ! 370: } else ! 371: tcpstat.tcps_conndrops++; ! 372: if (errno == ETIMEDOUT && tp->t_softerror) ! 373: errno = tp->t_softerror; ! 374: so->so_error = errno; ! 375: return (tcp_close(tp)); ! 376: } ! 377: ! 378: /* ! 379: * Close a TCP control block: ! 380: * discard all space held by the tcp ! 381: * discard internet protocol block ! 382: * wake up any sleepers ! 383: */ ! 384: struct tcpcb * ! 385: tcp_close(tp) ! 386: register struct tcpcb *tp; ! 387: { ! 388: register struct tcpiphdr *t; ! 389: struct inpcb *inp = tp->t_inpcb; ! 390: struct socket *so = inp->inp_socket; ! 391: register struct mbuf *m; ! 392: #ifdef RTV_RTT ! 393: register struct rtentry *rt; ! 394: ! 395: KERNEL_DEBUG(DBG_FNC_TCP_CLOSE | DBG_FUNC_START, tp,0,0,0,0); ! 396: /* ! 397: * If we sent enough data to get some meaningful characteristics, ! 398: * save them in the routing entry. 'Enough' is arbitrarily ! 399: * defined as the sendpipesize (default 4K) * 16. This would ! 400: * give us 16 rtt samples assuming we only get one sample per ! 401: * window (the usual case on a long haul net). 16 samples is ! 402: * enough for the srtt filter to converge to within 5% of the correct ! 403: * value; fewer samples and we could save a very bogus rtt. ! 404: * ! 405: * Don't update the default route's characteristics and don't ! 406: * update anything that the user "locked". ! 407: */ ! 408: if (SEQ_LT(tp->iss + so->so_snd.sb_hiwat * 16, tp->snd_max) && ! 409: (rt = inp->inp_route.ro_rt) && ! 410: ((struct sockaddr_in *)rt_key(rt))->sin_addr.s_addr != INADDR_ANY) { ! 411: register u_long i; ! 412: ! 413: if ((rt->rt_rmx.rmx_locks & RTV_RTT) == 0) { ! 414: i = tp->t_srtt * ! 415: (RTM_RTTUNIT / (PR_SLOWHZ * TCP_RTT_SCALE)); ! 416: if (rt->rt_rmx.rmx_rtt && i) ! 417: /* ! 418: * filter this update to half the old & half ! 419: * the new values, converting scale. ! 420: * See route.h and tcp_var.h for a ! 421: * description of the scaling constants. ! 422: */ ! 423: rt->rt_rmx.rmx_rtt = ! 424: (rt->rt_rmx.rmx_rtt + i) / 2; ! 425: else ! 426: rt->rt_rmx.rmx_rtt = i; ! 427: } ! 428: if ((rt->rt_rmx.rmx_locks & RTV_RTTVAR) == 0) { ! 429: i = tp->t_rttvar * ! 430: (RTM_RTTUNIT / (PR_SLOWHZ * TCP_RTTVAR_SCALE)); ! 431: if (rt->rt_rmx.rmx_rttvar && i) ! 432: rt->rt_rmx.rmx_rttvar = ! 433: (rt->rt_rmx.rmx_rttvar + i) / 2; ! 434: else ! 435: rt->rt_rmx.rmx_rttvar = i; ! 436: } ! 437: /* ! 438: * update the pipelimit (ssthresh) if it has been updated ! 439: * already or if a pipesize was specified & the threshhold ! 440: * got below half the pipesize. I.e., wait for bad news ! 441: * before we start updating, then update on both good ! 442: * and bad news. ! 443: */ ! 444: if ((rt->rt_rmx.rmx_locks & RTV_SSTHRESH) == 0 && ! 445: (i = tp->snd_ssthresh) && rt->rt_rmx.rmx_ssthresh || ! 446: i < (rt->rt_rmx.rmx_sendpipe / 2)) { ! 447: /* ! 448: * convert the limit from user data bytes to ! 449: * packets then to packet data bytes. ! 450: */ ! 451: i = (i + tp->t_maxseg / 2) / tp->t_maxseg; ! 452: if (i < 2) ! 453: i = 2; ! 454: i *= (u_long)(tp->t_maxseg + sizeof (struct tcpiphdr)); ! 455: if (rt->rt_rmx.rmx_ssthresh) ! 456: rt->rt_rmx.rmx_ssthresh = ! 457: (rt->rt_rmx.rmx_ssthresh + i) / 2; ! 458: else ! 459: rt->rt_rmx.rmx_ssthresh = i; ! 460: } ! 461: } ! 462: #endif /* RTV_RTT */ ! 463: /* free the reassembly queue, if any */ ! 464: t = tp->seg_next; ! 465: while (t != (struct tcpiphdr *)tp) { ! 466: t = (struct tcpiphdr *)t->ti_next; ! 467: m = REASS_MBUF((struct tcpiphdr *)t->ti_prev); ! 468: remque((queue_t) t->ti_prev); ! 469: m_freem(m); ! 470: } ! 471: if (tp->t_template) ! 472: (void) m_free(dtom(tp->t_template)); ! 473: ! 474: #ifdef SOCKET_CACHE_ON ! 475: inp->inp_saved_ppcb = tp; ! 476: #else ! 477: if (so->cached_in_sock_layer) ! 478: inp->inp_saved_ppcb = tp; ! 479: else ! 480: zfree(tcpcb_zone, (vm_offset_t) tp); ! 481: #endif ! 482: ! 483: inp->inp_ppcb = 0; ! 484: ! 485: soisdisconnected(so); ! 486: ! 487: in_pcbdetach(inp); ! 488: tcpstat.tcps_closed++; ! 489: ! 490: KERNEL_DEBUG(DBG_FNC_TCP_CLOSE | DBG_FUNC_END, tcpstat.tcps_closed,0,0,0,0); ! 491: ! 492: return ((struct tcpcb *)0); ! 493: } ! 494: ! 495: void ! 496: tcp_drain() ! 497: { ! 498: ! 499: } ! 500: ! 501: /* ! 502: * Notify a tcp user of an asynchronous error; ! 503: * store error as soft error, but wake up user ! 504: * (for now, won't do anything until can select for soft error). ! 505: */ ! 506: void ! 507: tcp_notify(inp, error) ! 508: struct inpcb *inp; ! 509: int error; ! 510: { ! 511: register struct tcpcb *tp = (struct tcpcb *)inp->inp_ppcb; ! 512: register struct socket *so = inp->inp_socket; ! 513: ! 514: /* ! 515: * Ignore some errors if we are hooked up. ! 516: * If connection hasn't completed, has retransmitted several times, ! 517: * and receives a second error, give up now. This is better ! 518: * than waiting a long time to establish a connection that ! 519: * can never complete. ! 520: */ ! 521: if (tp->t_state == TCPS_ESTABLISHED && ! 522: (error == EHOSTUNREACH || error == ENETUNREACH || ! 523: error == EHOSTDOWN)) { ! 524: return; ! 525: } else if (tp->t_state < TCPS_ESTABLISHED && tp->t_rxtshift > 3 && ! 526: tp->t_softerror) ! 527: so->so_error = error; ! 528: else ! 529: tp->t_softerror = error; ! 530: wakeup((caddr_t) &so->so_timeo); ! 531: sorwakeup(so); ! 532: sowwakeup(so); ! 533: } ! 534: ! 535: void ! 536: tcp_ctlinput(cmd, sa, ip) ! 537: int cmd; ! 538: struct sockaddr *sa; ! 539: register struct ip *ip; ! 540: { ! 541: register struct tcphdr *th; ! 542: extern struct in_addr zeroin_addr; ! 543: extern u_char inetctlerrmap[]; ! 544: void (*notify) __P((struct inpcb *, int)) = tcp_notify; ! 545: ! 546: if (cmd == PRC_QUENCH) ! 547: notify = tcp_quench; ! 548: else if (!PRC_IS_REDIRECT(cmd) && ! 549: ((unsigned)cmd > PRC_NCMDS || inetctlerrmap[cmd] == 0)) ! 550: return; ! 551: if (ip) { ! 552: th = (struct tcphdr *)((caddr_t)ip + (ip->ip_hl << 2)); ! 553: in_pcbnotify(&tcb, sa, th->th_dport, ip->ip_src, th->th_sport, ! 554: cmd, notify); ! 555: } else ! 556: in_pcbnotify(&tcb, sa, 0, zeroin_addr, 0, cmd, notify); ! 557: } ! 558: ! 559: /* ! 560: * When a source quench is received, close congestion window ! 561: * to one segment. We will gradually open it again as we proceed. ! 562: */ ! 563: void ! 564: tcp_quench(inp, errno) ! 565: struct inpcb *inp; ! 566: int errno; ! 567: { ! 568: struct tcpcb *tp = intotcpcb(inp); ! 569: ! 570: if (tp) ! 571: tp->snd_cwnd = tp->t_maxseg; ! 572: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.