Annotation of sys/netinet/tcp_subr.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: tcp_subr.c,v 1.98 2007/06/25 12:17:43 markus Exp $ */
! 2: /* $NetBSD: tcp_subr.c,v 1.22 1996/02/13 23:44:00 christos Exp $ */
! 3:
! 4: /*
! 5: * Copyright (c) 1982, 1986, 1988, 1990, 1993
! 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. Neither the name of the University nor the names of its contributors
! 17: * may be used to endorse or promote products derived from this software
! 18: * without specific prior written permission.
! 19: *
! 20: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
! 21: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 22: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 23: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
! 24: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 25: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 26: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 27: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 28: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 29: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 30: * SUCH DAMAGE.
! 31: *
! 32: * @(#)COPYRIGHT 1.1 (NRL) 17 January 1995
! 33: *
! 34: * NRL grants permission for redistribution and use in source and binary
! 35: * forms, with or without modification, of the software and documentation
! 36: * created at NRL provided that the following conditions are met:
! 37: *
! 38: * 1. Redistributions of source code must retain the above copyright
! 39: * notice, this list of conditions and the following disclaimer.
! 40: * 2. Redistributions in binary form must reproduce the above copyright
! 41: * notice, this list of conditions and the following disclaimer in the
! 42: * documentation and/or other materials provided with the distribution.
! 43: * 3. All advertising materials mentioning features or use of this software
! 44: * must display the following acknowledgements:
! 45: * This product includes software developed by the University of
! 46: * California, Berkeley and its contributors.
! 47: * This product includes software developed at the Information
! 48: * Technology Division, US Naval Research Laboratory.
! 49: * 4. Neither the name of the NRL nor the names of its contributors
! 50: * may be used to endorse or promote products derived from this software
! 51: * without specific prior written permission.
! 52: *
! 53: * THE SOFTWARE PROVIDED BY NRL IS PROVIDED BY NRL AND CONTRIBUTORS ``AS
! 54: * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
! 55: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
! 56: * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NRL OR
! 57: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
! 58: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
! 59: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
! 60: * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
! 61: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
! 62: * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
! 63: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
! 64: *
! 65: * The views and conclusions contained in the software and documentation
! 66: * are those of the authors and should not be interpreted as representing
! 67: * official policies, either expressed or implied, of the US Naval
! 68: * Research Laboratory (NRL).
! 69: */
! 70:
! 71: #include <sys/param.h>
! 72: #include <sys/systm.h>
! 73: #include <sys/proc.h>
! 74: #include <sys/mbuf.h>
! 75: #include <sys/socket.h>
! 76: #include <sys/socketvar.h>
! 77: #include <sys/protosw.h>
! 78: #include <sys/kernel.h>
! 79:
! 80: #include <net/route.h>
! 81: #include <net/if.h>
! 82:
! 83: #include <netinet/in.h>
! 84: #include <netinet/in_systm.h>
! 85: #include <netinet/ip.h>
! 86: #include <netinet/in_pcb.h>
! 87: #include <netinet/ip_var.h>
! 88: #include <netinet/ip_icmp.h>
! 89: #include <netinet/tcp.h>
! 90: #include <netinet/tcp_fsm.h>
! 91: #include <netinet/tcp_seq.h>
! 92: #include <netinet/tcp_timer.h>
! 93: #include <netinet/tcp_var.h>
! 94: #include <netinet/tcpip.h>
! 95: #include <dev/rndvar.h>
! 96:
! 97: #ifdef INET6
! 98: #include <netinet6/in6_var.h>
! 99: #include <netinet6/ip6protosw.h>
! 100: #endif /* INET6 */
! 101:
! 102: #include <crypto/md5.h>
! 103:
! 104: /* patchable/settable parameters for tcp */
! 105: int tcp_mssdflt = TCP_MSS;
! 106: int tcp_rttdflt = TCPTV_SRTTDFLT / PR_SLOWHZ;
! 107:
! 108: /* values controllable via sysctl */
! 109: int tcp_do_rfc1323 = 1;
! 110: #ifdef TCP_SACK
! 111: int tcp_do_sack = 1; /* RFC 2018 selective ACKs */
! 112: #endif
! 113: int tcp_ack_on_push = 0; /* set to enable immediate ACK-on-PUSH */
! 114: #ifdef TCP_ECN
! 115: int tcp_do_ecn = 0; /* RFC3168 ECN enabled/disabled? */
! 116: #endif
! 117: int tcp_do_rfc3390 = 1; /* RFC3390 Increasing TCP's Initial Window */
! 118:
! 119: u_int32_t tcp_now = 1;
! 120:
! 121: #ifndef TCBHASHSIZE
! 122: #define TCBHASHSIZE 128
! 123: #endif
! 124: int tcbhashsize = TCBHASHSIZE;
! 125:
! 126: /* syn hash parameters */
! 127: #define TCP_SYN_HASH_SIZE 293
! 128: #define TCP_SYN_BUCKET_SIZE 35
! 129: int tcp_syn_cache_size = TCP_SYN_HASH_SIZE;
! 130: int tcp_syn_cache_limit = TCP_SYN_HASH_SIZE*TCP_SYN_BUCKET_SIZE;
! 131: int tcp_syn_bucket_limit = 3*TCP_SYN_BUCKET_SIZE;
! 132: struct syn_cache_head tcp_syn_cache[TCP_SYN_HASH_SIZE];
! 133:
! 134: int tcp_reass_limit = NMBCLUSTERS / 2; /* hardlimit for tcpqe_pool */
! 135: #ifdef TCP_SACK
! 136: int tcp_sackhole_limit = 32*1024; /* hardlimit for sackhl_pool */
! 137: #endif
! 138:
! 139: #ifdef INET6
! 140: extern int ip6_defhlim;
! 141: #endif /* INET6 */
! 142:
! 143: struct pool tcpcb_pool;
! 144: struct pool tcpqe_pool;
! 145: #ifdef TCP_SACK
! 146: struct pool sackhl_pool;
! 147: #endif
! 148:
! 149: struct tcpstat tcpstat; /* tcp statistics */
! 150: tcp_seq tcp_iss;
! 151:
! 152: /*
! 153: * Tcp initialization
! 154: */
! 155: void
! 156: tcp_init()
! 157: {
! 158: tcp_iss = 1; /* wrong */
! 159: pool_init(&tcpcb_pool, sizeof(struct tcpcb), 0, 0, 0, "tcpcbpl",
! 160: NULL);
! 161: pool_init(&tcpqe_pool, sizeof(struct tcpqent), 0, 0, 0, "tcpqepl",
! 162: NULL);
! 163: pool_sethardlimit(&tcpqe_pool, tcp_reass_limit, NULL, 0);
! 164: #ifdef TCP_SACK
! 165: pool_init(&sackhl_pool, sizeof(struct sackhole), 0, 0, 0, "sackhlpl",
! 166: NULL);
! 167: pool_sethardlimit(&sackhl_pool, tcp_sackhole_limit, NULL, 0);
! 168: #endif /* TCP_SACK */
! 169: in_pcbinit(&tcbtable, tcbhashsize);
! 170:
! 171: #ifdef INET6
! 172: /*
! 173: * Since sizeof(struct ip6_hdr) > sizeof(struct ip), we
! 174: * do max length checks/computations only on the former.
! 175: */
! 176: if (max_protohdr < (sizeof(struct ip6_hdr) + sizeof(struct tcphdr)))
! 177: max_protohdr = (sizeof(struct ip6_hdr) + sizeof(struct tcphdr));
! 178: if ((max_linkhdr + sizeof(struct ip6_hdr) + sizeof(struct tcphdr)) >
! 179: MHLEN)
! 180: panic("tcp_init");
! 181:
! 182: icmp6_mtudisc_callback_register(tcp6_mtudisc_callback);
! 183: #endif /* INET6 */
! 184:
! 185: /* Initialize the compressed state engine. */
! 186: syn_cache_init();
! 187:
! 188: /* Initialize timer state. */
! 189: tcp_timer_init();
! 190: }
! 191:
! 192: /*
! 193: * Create template to be used to send tcp packets on a connection.
! 194: * Call after host entry created, allocates an mbuf and fills
! 195: * in a skeletal tcp/ip header, minimizing the amount of work
! 196: * necessary when the connection is used.
! 197: *
! 198: * To support IPv6 in addition to IPv4 and considering that the sizes of
! 199: * the IPv4 and IPv6 headers are not the same, we now use a separate pointer
! 200: * for the TCP header. Also, we made the former tcpiphdr header pointer
! 201: * into just an IP overlay pointer, with casting as appropriate for v6. rja
! 202: */
! 203: struct mbuf *
! 204: tcp_template(tp)
! 205: struct tcpcb *tp;
! 206: {
! 207: struct inpcb *inp = tp->t_inpcb;
! 208: struct mbuf *m;
! 209: struct tcphdr *th;
! 210:
! 211: if ((m = tp->t_template) == 0) {
! 212: m = m_get(M_DONTWAIT, MT_HEADER);
! 213: if (m == NULL)
! 214: return (0);
! 215:
! 216: switch (tp->pf) {
! 217: case 0: /*default to PF_INET*/
! 218: #ifdef INET
! 219: case AF_INET:
! 220: m->m_len = sizeof(struct ip);
! 221: break;
! 222: #endif /* INET */
! 223: #ifdef INET6
! 224: case AF_INET6:
! 225: m->m_len = sizeof(struct ip6_hdr);
! 226: break;
! 227: #endif /* INET6 */
! 228: }
! 229: m->m_len += sizeof (struct tcphdr);
! 230:
! 231: /*
! 232: * The link header, network header, TCP header, and TCP options
! 233: * all must fit in this mbuf. For now, assume the worst case of
! 234: * TCP options size. Eventually, compute this from tp flags.
! 235: */
! 236: if (m->m_len + MAX_TCPOPTLEN + max_linkhdr >= MHLEN) {
! 237: MCLGET(m, M_DONTWAIT);
! 238: if ((m->m_flags & M_EXT) == 0) {
! 239: m_free(m);
! 240: return (0);
! 241: }
! 242: }
! 243: }
! 244:
! 245: switch(tp->pf) {
! 246: #ifdef INET
! 247: case AF_INET:
! 248: {
! 249: struct ipovly *ipovly;
! 250:
! 251: ipovly = mtod(m, struct ipovly *);
! 252:
! 253: bzero(ipovly->ih_x1, sizeof ipovly->ih_x1);
! 254: ipovly->ih_pr = IPPROTO_TCP;
! 255: ipovly->ih_len = htons(sizeof (struct tcphdr));
! 256: ipovly->ih_src = inp->inp_laddr;
! 257: ipovly->ih_dst = inp->inp_faddr;
! 258:
! 259: th = (struct tcphdr *)(mtod(m, caddr_t) +
! 260: sizeof(struct ip));
! 261: th->th_sum = in_cksum_phdr(ipovly->ih_src.s_addr,
! 262: ipovly->ih_dst.s_addr,
! 263: htons(sizeof (struct tcphdr) + IPPROTO_TCP));
! 264: }
! 265: break;
! 266: #endif /* INET */
! 267: #ifdef INET6
! 268: case AF_INET6:
! 269: {
! 270: struct ip6_hdr *ip6;
! 271:
! 272: ip6 = mtod(m, struct ip6_hdr *);
! 273:
! 274: ip6->ip6_src = inp->inp_laddr6;
! 275: ip6->ip6_dst = inp->inp_faddr6;
! 276: ip6->ip6_flow = htonl(0x60000000) |
! 277: (inp->inp_flowinfo & IPV6_FLOWLABEL_MASK);
! 278:
! 279: ip6->ip6_nxt = IPPROTO_TCP;
! 280: ip6->ip6_plen = htons(sizeof(struct tcphdr)); /*XXX*/
! 281: ip6->ip6_hlim = in6_selecthlim(inp, NULL); /*XXX*/
! 282:
! 283: th = (struct tcphdr *)(mtod(m, caddr_t) +
! 284: sizeof(struct ip6_hdr));
! 285: th->th_sum = 0;
! 286: }
! 287: break;
! 288: #endif /* INET6 */
! 289: }
! 290:
! 291: th->th_sport = inp->inp_lport;
! 292: th->th_dport = inp->inp_fport;
! 293: th->th_seq = 0;
! 294: th->th_ack = 0;
! 295: th->th_x2 = 0;
! 296: th->th_off = 5;
! 297: th->th_flags = 0;
! 298: th->th_win = 0;
! 299: th->th_urp = 0;
! 300: return (m);
! 301: }
! 302:
! 303: /*
! 304: * Send a single message to the TCP at address specified by
! 305: * the given TCP/IP header. If m == 0, then we make a copy
! 306: * of the tcpiphdr at ti and send directly to the addressed host.
! 307: * This is used to force keep alive messages out using the TCP
! 308: * template for a connection tp->t_template. If flags are given
! 309: * then we send a message back to the TCP which originated the
! 310: * segment ti, and discard the mbuf containing it and any other
! 311: * attached mbufs.
! 312: *
! 313: * In any case the ack and sequence number of the transmitted
! 314: * segment are as specified by the parameters.
! 315: */
! 316: #ifdef INET6
! 317: /* This function looks hairy, because it was so IPv4-dependent. */
! 318: #endif /* INET6 */
! 319: void
! 320: tcp_respond(tp, template, m, ack, seq, flags)
! 321: struct tcpcb *tp;
! 322: caddr_t template;
! 323: struct mbuf *m;
! 324: tcp_seq ack, seq;
! 325: int flags;
! 326: {
! 327: int tlen;
! 328: int win = 0;
! 329: struct route *ro = 0;
! 330: struct tcphdr *th;
! 331: struct tcpiphdr *ti = (struct tcpiphdr *)template;
! 332: int af; /* af on wire */
! 333:
! 334: if (tp) {
! 335: win = sbspace(&tp->t_inpcb->inp_socket->so_rcv);
! 336: /*
! 337: * If this is called with an unconnected
! 338: * socket/tp/pcb (tp->pf is 0), we lose.
! 339: */
! 340: af = tp->pf;
! 341:
! 342: /*
! 343: * The route/route6 distinction is meaningless
! 344: * unless you're allocating space or passing parameters.
! 345: */
! 346: ro = &tp->t_inpcb->inp_route;
! 347: } else
! 348: af = (((struct ip *)ti)->ip_v == 6) ? AF_INET6 : AF_INET;
! 349: if (m == 0) {
! 350: m = m_gethdr(M_DONTWAIT, MT_HEADER);
! 351: if (m == NULL)
! 352: return;
! 353: #ifdef TCP_COMPAT_42
! 354: tlen = 1;
! 355: #else
! 356: tlen = 0;
! 357: #endif
! 358: m->m_data += max_linkhdr;
! 359: switch (af) {
! 360: #ifdef INET6
! 361: case AF_INET6:
! 362: bcopy(ti, mtod(m, caddr_t), sizeof(struct tcphdr) +
! 363: sizeof(struct ip6_hdr));
! 364: break;
! 365: #endif /* INET6 */
! 366: case AF_INET:
! 367: bcopy(ti, mtod(m, caddr_t), sizeof(struct tcphdr) +
! 368: sizeof(struct ip));
! 369: break;
! 370: }
! 371:
! 372: ti = mtod(m, struct tcpiphdr *);
! 373: flags = TH_ACK;
! 374: } else {
! 375: m_freem(m->m_next);
! 376: m->m_next = 0;
! 377: m->m_data = (caddr_t)ti;
! 378: tlen = 0;
! 379: #define xchg(a,b,type) do { type t; t=a; a=b; b=t; } while (0)
! 380: switch (af) {
! 381: #ifdef INET6
! 382: case AF_INET6:
! 383: m->m_len = sizeof(struct tcphdr) + sizeof(struct ip6_hdr);
! 384: xchg(((struct ip6_hdr *)ti)->ip6_dst,
! 385: ((struct ip6_hdr *)ti)->ip6_src, struct in6_addr);
! 386: th = (void *)((caddr_t)ti + sizeof(struct ip6_hdr));
! 387: break;
! 388: #endif /* INET6 */
! 389: case AF_INET:
! 390: m->m_len = sizeof (struct tcpiphdr);
! 391: xchg(ti->ti_dst.s_addr, ti->ti_src.s_addr, u_int32_t);
! 392: th = (void *)((caddr_t)ti + sizeof(struct ip));
! 393: break;
! 394: }
! 395: xchg(th->th_dport, th->th_sport, u_int16_t);
! 396: #undef xchg
! 397: }
! 398: switch (af) {
! 399: #ifdef INET6
! 400: case AF_INET6:
! 401: tlen += sizeof(struct tcphdr) + sizeof(struct ip6_hdr);
! 402: th = (struct tcphdr *)((caddr_t)ti + sizeof(struct ip6_hdr));
! 403: break;
! 404: #endif /* INET6 */
! 405: case AF_INET:
! 406: ti->ti_len = htons((u_int16_t)(sizeof (struct tcphdr) + tlen));
! 407: tlen += sizeof (struct tcpiphdr);
! 408: th = (struct tcphdr *)((caddr_t)ti + sizeof(struct ip));
! 409: break;
! 410: }
! 411:
! 412: m->m_len = tlen;
! 413: m->m_pkthdr.len = tlen;
! 414: m->m_pkthdr.rcvif = (struct ifnet *) 0;
! 415: th->th_seq = htonl(seq);
! 416: th->th_ack = htonl(ack);
! 417: th->th_x2 = 0;
! 418: th->th_off = sizeof (struct tcphdr) >> 2;
! 419: th->th_flags = flags;
! 420: if (tp)
! 421: win >>= tp->rcv_scale;
! 422: if (win > TCP_MAXWIN)
! 423: win = TCP_MAXWIN;
! 424: th->th_win = htons((u_int16_t)win);
! 425: th->th_urp = 0;
! 426:
! 427: switch (af) {
! 428: #ifdef INET6
! 429: case AF_INET6:
! 430: ((struct ip6_hdr *)ti)->ip6_flow = htonl(0x60000000);
! 431: ((struct ip6_hdr *)ti)->ip6_nxt = IPPROTO_TCP;
! 432: ((struct ip6_hdr *)ti)->ip6_hlim =
! 433: in6_selecthlim(tp ? tp->t_inpcb : NULL, NULL); /*XXX*/
! 434: ((struct ip6_hdr *)ti)->ip6_plen = tlen - sizeof(struct ip6_hdr);
! 435: th->th_sum = 0;
! 436: th->th_sum = in6_cksum(m, IPPROTO_TCP,
! 437: sizeof(struct ip6_hdr), ((struct ip6_hdr *)ti)->ip6_plen);
! 438: HTONS(((struct ip6_hdr *)ti)->ip6_plen);
! 439: ip6_output(m, tp ? tp->t_inpcb->inp_outputopts6 : NULL,
! 440: (struct route_in6 *)ro, 0, NULL, NULL,
! 441: tp ? tp->t_inpcb : NULL);
! 442: break;
! 443: #endif /* INET6 */
! 444: case AF_INET:
! 445: bzero(ti->ti_x1, sizeof ti->ti_x1);
! 446: ti->ti_len = htons((u_short)tlen - sizeof(struct ip));
! 447:
! 448: /*
! 449: * There's no point deferring to hardware checksum processing
! 450: * here, as we only send a minimal TCP packet whose checksum
! 451: * we need to compute in any case.
! 452: */
! 453: th->th_sum = 0;
! 454: th->th_sum = in_cksum(m, tlen);
! 455: ((struct ip *)ti)->ip_len = htons(tlen);
! 456: ((struct ip *)ti)->ip_ttl = ip_defttl;
! 457: ip_output(m, (void *)NULL, ro, ip_mtudisc ? IP_MTUDISC : 0,
! 458: (void *)NULL, tp ? tp->t_inpcb : (void *)NULL);
! 459: }
! 460: }
! 461:
! 462: /*
! 463: * Create a new TCP control block, making an
! 464: * empty reassembly queue and hooking it to the argument
! 465: * protocol control block.
! 466: */
! 467: struct tcpcb *
! 468: tcp_newtcpcb(struct inpcb *inp)
! 469: {
! 470: struct tcpcb *tp;
! 471: int i;
! 472:
! 473: tp = pool_get(&tcpcb_pool, PR_NOWAIT);
! 474: if (tp == NULL)
! 475: return ((struct tcpcb *)0);
! 476: bzero((char *) tp, sizeof(struct tcpcb));
! 477: TAILQ_INIT(&tp->t_segq);
! 478: tp->t_maxseg = tcp_mssdflt;
! 479: tp->t_maxopd = 0;
! 480:
! 481: TCP_INIT_DELACK(tp);
! 482: for (i = 0; i < TCPT_NTIMERS; i++)
! 483: TCP_TIMER_INIT(tp, i);
! 484: timeout_set(&tp->t_reap_to, tcp_reaper, tp);
! 485:
! 486: #ifdef TCP_SACK
! 487: tp->sack_enable = tcp_do_sack;
! 488: #endif
! 489: tp->t_flags = tcp_do_rfc1323 ? (TF_REQ_SCALE|TF_REQ_TSTMP) : 0;
! 490: tp->t_inpcb = inp;
! 491: /*
! 492: * Init srtt to TCPTV_SRTTBASE (0), so we can tell that we have no
! 493: * rtt estimate. Set rttvar so that srtt + 2 * rttvar gives
! 494: * reasonable initial retransmit time.
! 495: */
! 496: tp->t_srtt = TCPTV_SRTTBASE;
! 497: tp->t_rttvar = tcp_rttdflt * PR_SLOWHZ <<
! 498: (TCP_RTTVAR_SHIFT + TCP_RTT_BASE_SHIFT - 1);
! 499: tp->t_rttmin = TCPTV_MIN;
! 500: TCPT_RANGESET(tp->t_rxtcur, TCP_REXMTVAL(tp),
! 501: TCPTV_MIN, TCPTV_REXMTMAX);
! 502: tp->snd_cwnd = TCP_MAXWIN << TCP_MAX_WINSHIFT;
! 503: tp->snd_ssthresh = TCP_MAXWIN << TCP_MAX_WINSHIFT;
! 504:
! 505: tp->t_pmtud_mtu_sent = 0;
! 506: tp->t_pmtud_mss_acked = 0;
! 507:
! 508: #ifdef INET6
! 509: /* we disallow IPv4 mapped address completely. */
! 510: if ((inp->inp_flags & INP_IPV6) == 0)
! 511: tp->pf = PF_INET;
! 512: else
! 513: tp->pf = PF_INET6;
! 514: #else
! 515: tp->pf = PF_INET;
! 516: #endif
! 517:
! 518: #ifdef INET6
! 519: if (inp->inp_flags & INP_IPV6)
! 520: inp->inp_ipv6.ip6_hlim = ip6_defhlim;
! 521: else
! 522: #endif /* INET6 */
! 523: inp->inp_ip.ip_ttl = ip_defttl;
! 524:
! 525: inp->inp_ppcb = (caddr_t)tp;
! 526: return (tp);
! 527: }
! 528:
! 529: /*
! 530: * Drop a TCP connection, reporting
! 531: * the specified error. If connection is synchronized,
! 532: * then send a RST to peer.
! 533: */
! 534: struct tcpcb *
! 535: tcp_drop(tp, errno)
! 536: struct tcpcb *tp;
! 537: int errno;
! 538: {
! 539: struct socket *so = tp->t_inpcb->inp_socket;
! 540:
! 541: if (TCPS_HAVERCVDSYN(tp->t_state)) {
! 542: tp->t_state = TCPS_CLOSED;
! 543: (void) tcp_output(tp);
! 544: tcpstat.tcps_drops++;
! 545: } else
! 546: tcpstat.tcps_conndrops++;
! 547: if (errno == ETIMEDOUT && tp->t_softerror)
! 548: errno = tp->t_softerror;
! 549: so->so_error = errno;
! 550: return (tcp_close(tp));
! 551: }
! 552:
! 553: /*
! 554: * Close a TCP control block:
! 555: * discard all space held by the tcp
! 556: * discard internet protocol block
! 557: * wake up any sleepers
! 558: */
! 559: struct tcpcb *
! 560: tcp_close(struct tcpcb *tp)
! 561: {
! 562: struct inpcb *inp = tp->t_inpcb;
! 563: struct socket *so = inp->inp_socket;
! 564: #ifdef TCP_SACK
! 565: struct sackhole *p, *q;
! 566: #endif
! 567:
! 568: /* free the reassembly queue, if any */
! 569: tcp_reass_lock(tp);
! 570: tcp_freeq(tp);
! 571: tcp_reass_unlock(tp);
! 572:
! 573: tcp_canceltimers(tp);
! 574: TCP_CLEAR_DELACK(tp);
! 575: syn_cache_cleanup(tp);
! 576:
! 577: #ifdef TCP_SACK
! 578: /* Free SACK holes. */
! 579: q = p = tp->snd_holes;
! 580: while (p != 0) {
! 581: q = p->next;
! 582: pool_put(&sackhl_pool, p);
! 583: p = q;
! 584: }
! 585: #endif
! 586: if (tp->t_template)
! 587: (void) m_free(tp->t_template);
! 588:
! 589: tp->t_flags |= TF_DEAD;
! 590: timeout_add(&tp->t_reap_to, 0);
! 591:
! 592: inp->inp_ppcb = 0;
! 593: soisdisconnected(so);
! 594: in_pcbdetach(inp);
! 595: return ((struct tcpcb *)0);
! 596: }
! 597:
! 598: void
! 599: tcp_reaper(void *arg)
! 600: {
! 601: struct tcpcb *tp = arg;
! 602: int s;
! 603:
! 604: s = splsoftnet();
! 605: pool_put(&tcpcb_pool, tp);
! 606: splx(s);
! 607: tcpstat.tcps_closed++;
! 608: }
! 609:
! 610: int
! 611: tcp_freeq(struct tcpcb *tp)
! 612: {
! 613: struct tcpqent *qe;
! 614: int rv = 0;
! 615:
! 616: while ((qe = TAILQ_FIRST(&tp->t_segq)) != NULL) {
! 617: TAILQ_REMOVE(&tp->t_segq, qe, tcpqe_q);
! 618: m_freem(qe->tcpqe_m);
! 619: pool_put(&tcpqe_pool, qe);
! 620: rv = 1;
! 621: }
! 622: return (rv);
! 623: }
! 624:
! 625: void
! 626: tcp_drain()
! 627: {
! 628: struct inpcb *inp;
! 629:
! 630: /* called at splnet() */
! 631: CIRCLEQ_FOREACH(inp, &tcbtable.inpt_queue, inp_queue) {
! 632: struct tcpcb *tp = (struct tcpcb *)inp->inp_ppcb;
! 633:
! 634: if (tp != NULL) {
! 635: if (tcp_reass_lock_try(tp) == 0)
! 636: continue;
! 637: if (tcp_freeq(tp))
! 638: tcpstat.tcps_conndrained++;
! 639: tcp_reass_unlock(tp);
! 640: }
! 641: }
! 642: }
! 643:
! 644: /*
! 645: * Compute proper scaling value for receiver window from buffer space
! 646: */
! 647:
! 648: void
! 649: tcp_rscale(struct tcpcb *tp, u_long hiwat)
! 650: {
! 651: tp->request_r_scale = 0;
! 652: while (tp->request_r_scale < TCP_MAX_WINSHIFT &&
! 653: TCP_MAXWIN << tp->request_r_scale < hiwat)
! 654: tp->request_r_scale++;
! 655: }
! 656:
! 657: /*
! 658: * Notify a tcp user of an asynchronous error;
! 659: * store error as soft error, but wake up user
! 660: * (for now, won't do anything until can select for soft error).
! 661: */
! 662: void
! 663: tcp_notify(inp, error)
! 664: struct inpcb *inp;
! 665: int error;
! 666: {
! 667: struct tcpcb *tp = (struct tcpcb *)inp->inp_ppcb;
! 668: struct socket *so = inp->inp_socket;
! 669:
! 670: /*
! 671: * Ignore some errors if we are hooked up.
! 672: * If connection hasn't completed, has retransmitted several times,
! 673: * and receives a second error, give up now. This is better
! 674: * than waiting a long time to establish a connection that
! 675: * can never complete.
! 676: */
! 677: if (tp->t_state == TCPS_ESTABLISHED &&
! 678: (error == EHOSTUNREACH || error == ENETUNREACH ||
! 679: error == EHOSTDOWN)) {
! 680: return;
! 681: } else if (TCPS_HAVEESTABLISHED(tp->t_state) == 0 &&
! 682: tp->t_rxtshift > 3 && tp->t_softerror)
! 683: so->so_error = error;
! 684: else
! 685: tp->t_softerror = error;
! 686: wakeup((caddr_t) &so->so_timeo);
! 687: sorwakeup(so);
! 688: sowwakeup(so);
! 689: }
! 690:
! 691: #ifdef INET6
! 692: void
! 693: tcp6_ctlinput(cmd, sa, d)
! 694: int cmd;
! 695: struct sockaddr *sa;
! 696: void *d;
! 697: {
! 698: struct tcphdr th;
! 699: struct tcpcb *tp;
! 700: void (*notify)(struct inpcb *, int) = tcp_notify;
! 701: struct ip6_hdr *ip6;
! 702: const struct sockaddr_in6 *sa6_src = NULL;
! 703: struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)sa;
! 704: struct inpcb *inp;
! 705: struct mbuf *m;
! 706: tcp_seq seq;
! 707: int off;
! 708: struct {
! 709: u_int16_t th_sport;
! 710: u_int16_t th_dport;
! 711: u_int32_t th_seq;
! 712: } *thp;
! 713:
! 714: if (sa->sa_family != AF_INET6 ||
! 715: sa->sa_len != sizeof(struct sockaddr_in6) ||
! 716: IN6_IS_ADDR_UNSPECIFIED(&sa6->sin6_addr) ||
! 717: IN6_IS_ADDR_V4MAPPED(&sa6->sin6_addr))
! 718: return;
! 719: if ((unsigned)cmd >= PRC_NCMDS)
! 720: return;
! 721: else if (cmd == PRC_QUENCH) {
! 722: /*
! 723: * Don't honor ICMP Source Quench messages meant for
! 724: * TCP connections.
! 725: */
! 726: /* XXX there's no PRC_QUENCH in IPv6 */
! 727: return;
! 728: } else if (PRC_IS_REDIRECT(cmd))
! 729: notify = in_rtchange, d = NULL;
! 730: else if (cmd == PRC_MSGSIZE)
! 731: ; /* special code is present, see below */
! 732: else if (cmd == PRC_HOSTDEAD)
! 733: d = NULL;
! 734: else if (inet6ctlerrmap[cmd] == 0)
! 735: return;
! 736:
! 737: /* if the parameter is from icmp6, decode it. */
! 738: if (d != NULL) {
! 739: struct ip6ctlparam *ip6cp = (struct ip6ctlparam *)d;
! 740: m = ip6cp->ip6c_m;
! 741: ip6 = ip6cp->ip6c_ip6;
! 742: off = ip6cp->ip6c_off;
! 743: sa6_src = ip6cp->ip6c_src;
! 744: } else {
! 745: m = NULL;
! 746: ip6 = NULL;
! 747: sa6_src = &sa6_any;
! 748: }
! 749:
! 750: if (ip6) {
! 751: /*
! 752: * XXX: We assume that when ip6 is non NULL,
! 753: * M and OFF are valid.
! 754: */
! 755:
! 756: /* check if we can safely examine src and dst ports */
! 757: if (m->m_pkthdr.len < off + sizeof(*thp))
! 758: return;
! 759:
! 760: bzero(&th, sizeof(th));
! 761: #ifdef DIAGNOSTIC
! 762: if (sizeof(*thp) > sizeof(th))
! 763: panic("assumption failed in tcp6_ctlinput");
! 764: #endif
! 765: m_copydata(m, off, sizeof(*thp), (caddr_t)&th);
! 766:
! 767: /*
! 768: * Check to see if we have a valid TCP connection
! 769: * corresponding to the address in the ICMPv6 message
! 770: * payload.
! 771: */
! 772: inp = in6_pcbhashlookup(&tcbtable, &sa6->sin6_addr,
! 773: th.th_dport, (struct in6_addr *)&sa6_src->sin6_addr,
! 774: th.th_sport);
! 775: if (cmd == PRC_MSGSIZE) {
! 776: /*
! 777: * Depending on the value of "valid" and routing table
! 778: * size (mtudisc_{hi,lo}wat), we will:
! 779: * - recalcurate the new MTU and create the
! 780: * corresponding routing entry, or
! 781: * - ignore the MTU change notification.
! 782: */
! 783: icmp6_mtudisc_update((struct ip6ctlparam *)d, inp != NULL);
! 784: return;
! 785: }
! 786: if (inp) {
! 787: seq = ntohl(th.th_seq);
! 788: if (inp->inp_socket &&
! 789: (tp = intotcpcb(inp)) &&
! 790: SEQ_GEQ(seq, tp->snd_una) &&
! 791: SEQ_LT(seq, tp->snd_max))
! 792: notify(inp, inet6ctlerrmap[cmd]);
! 793: } else if (syn_cache_count &&
! 794: (inet6ctlerrmap[cmd] == EHOSTUNREACH ||
! 795: inet6ctlerrmap[cmd] == ENETUNREACH ||
! 796: inet6ctlerrmap[cmd] == EHOSTDOWN))
! 797: syn_cache_unreach((struct sockaddr *)sa6_src,
! 798: sa, &th);
! 799: } else {
! 800: (void) in6_pcbnotify(&tcbtable, sa, 0,
! 801: (struct sockaddr *)sa6_src, 0, cmd, NULL, notify);
! 802: }
! 803: }
! 804: #endif
! 805:
! 806: void *
! 807: tcp_ctlinput(cmd, sa, v)
! 808: int cmd;
! 809: struct sockaddr *sa;
! 810: void *v;
! 811: {
! 812: struct ip *ip = v;
! 813: struct tcphdr *th;
! 814: struct tcpcb *tp;
! 815: struct inpcb *inp;
! 816: struct in_addr faddr;
! 817: tcp_seq seq;
! 818: u_int mtu;
! 819: extern int inetctlerrmap[];
! 820: void (*notify)(struct inpcb *, int) = tcp_notify;
! 821: int errno;
! 822:
! 823: if (sa->sa_family != AF_INET)
! 824: return NULL;
! 825: faddr = satosin(sa)->sin_addr;
! 826: if (faddr.s_addr == INADDR_ANY)
! 827: return NULL;
! 828:
! 829: if ((unsigned)cmd >= PRC_NCMDS)
! 830: return NULL;
! 831: errno = inetctlerrmap[cmd];
! 832: if (cmd == PRC_QUENCH)
! 833: /*
! 834: * Don't honor ICMP Source Quench messages meant for
! 835: * TCP connections.
! 836: */
! 837: return NULL;
! 838: else if (PRC_IS_REDIRECT(cmd))
! 839: notify = in_rtchange, ip = 0;
! 840: else if (cmd == PRC_MSGSIZE && ip_mtudisc && ip) {
! 841: /*
! 842: * Verify that the packet in the icmp payload refers
! 843: * to an existing TCP connection.
! 844: */
! 845: th = (struct tcphdr *)((caddr_t)ip + (ip->ip_hl << 2));
! 846: seq = ntohl(th->th_seq);
! 847: inp = in_pcbhashlookup(&tcbtable,
! 848: ip->ip_dst, th->th_dport, ip->ip_src, th->th_sport);
! 849: if (inp && (tp = intotcpcb(inp)) &&
! 850: SEQ_GEQ(seq, tp->snd_una) &&
! 851: SEQ_LT(seq, tp->snd_max)) {
! 852: struct icmp *icp;
! 853: icp = (struct icmp *)((caddr_t)ip -
! 854: offsetof(struct icmp, icmp_ip));
! 855:
! 856: /*
! 857: * If the ICMP message advertises a Next-Hop MTU
! 858: * equal or larger than the maximum packet size we have
! 859: * ever sent, drop the message.
! 860: */
! 861: mtu = (u_int)ntohs(icp->icmp_nextmtu);
! 862: if (mtu >= tp->t_pmtud_mtu_sent)
! 863: return NULL;
! 864: if (mtu >= tcp_hdrsz(tp) + tp->t_pmtud_mss_acked) {
! 865: /*
! 866: * Calculate new MTU, and create corresponding
! 867: * route (traditional PMTUD).
! 868: */
! 869: tp->t_flags &= ~TF_PMTUD_PEND;
! 870: icmp_mtudisc(icp);
! 871: } else {
! 872: /*
! 873: * Record the information got in the ICMP
! 874: * message; act on it later.
! 875: * If we had already recorded an ICMP message,
! 876: * replace the old one only if the new message
! 877: * refers to an older TCP segment
! 878: */
! 879: if (tp->t_flags & TF_PMTUD_PEND) {
! 880: if (SEQ_LT(tp->t_pmtud_th_seq, seq))
! 881: return NULL;
! 882: } else
! 883: tp->t_flags |= TF_PMTUD_PEND;
! 884: tp->t_pmtud_th_seq = seq;
! 885: tp->t_pmtud_nextmtu = icp->icmp_nextmtu;
! 886: tp->t_pmtud_ip_len = icp->icmp_ip.ip_len;
! 887: tp->t_pmtud_ip_hl = icp->icmp_ip.ip_hl;
! 888: return NULL;
! 889: }
! 890: } else {
! 891: /* ignore if we don't have a matching connection */
! 892: return NULL;
! 893: }
! 894: notify = tcp_mtudisc, ip = 0;
! 895: } else if (cmd == PRC_MTUINC)
! 896: notify = tcp_mtudisc_increase, ip = 0;
! 897: else if (cmd == PRC_HOSTDEAD)
! 898: ip = 0;
! 899: else if (errno == 0)
! 900: return NULL;
! 901:
! 902: if (ip) {
! 903: th = (struct tcphdr *)((caddr_t)ip + (ip->ip_hl << 2));
! 904: inp = in_pcbhashlookup(&tcbtable,
! 905: ip->ip_dst, th->th_dport, ip->ip_src, th->th_sport);
! 906: if (inp) {
! 907: seq = ntohl(th->th_seq);
! 908: if (inp->inp_socket &&
! 909: (tp = intotcpcb(inp)) &&
! 910: SEQ_GEQ(seq, tp->snd_una) &&
! 911: SEQ_LT(seq, tp->snd_max))
! 912: notify(inp, errno);
! 913: } else if (syn_cache_count &&
! 914: (inetctlerrmap[cmd] == EHOSTUNREACH ||
! 915: inetctlerrmap[cmd] == ENETUNREACH ||
! 916: inetctlerrmap[cmd] == EHOSTDOWN)) {
! 917: struct sockaddr_in sin;
! 918:
! 919: bzero(&sin, sizeof(sin));
! 920: sin.sin_len = sizeof(sin);
! 921: sin.sin_family = AF_INET;
! 922: sin.sin_port = th->th_sport;
! 923: sin.sin_addr = ip->ip_src;
! 924: syn_cache_unreach((struct sockaddr *)&sin,
! 925: sa, th);
! 926: }
! 927: } else
! 928: in_pcbnotifyall(&tcbtable, sa, errno, notify);
! 929:
! 930: return NULL;
! 931: }
! 932:
! 933:
! 934: #ifdef INET6
! 935: /*
! 936: * Path MTU Discovery handlers.
! 937: */
! 938: void
! 939: tcp6_mtudisc_callback(faddr)
! 940: struct in6_addr *faddr;
! 941: {
! 942: struct sockaddr_in6 sin6;
! 943:
! 944: bzero(&sin6, sizeof(sin6));
! 945: sin6.sin6_family = AF_INET6;
! 946: sin6.sin6_len = sizeof(struct sockaddr_in6);
! 947: sin6.sin6_addr = *faddr;
! 948: (void) in6_pcbnotify(&tcbtable, (struct sockaddr *)&sin6, 0,
! 949: (struct sockaddr *)&sa6_any, 0, PRC_MSGSIZE, NULL, tcp_mtudisc);
! 950: }
! 951: #endif /* INET6 */
! 952:
! 953: /*
! 954: * On receipt of path MTU corrections, flush old route and replace it
! 955: * with the new one. Retransmit all unacknowledged packets, to ensure
! 956: * that all packets will be received.
! 957: */
! 958: void
! 959: tcp_mtudisc(inp, errno)
! 960: struct inpcb *inp;
! 961: int errno;
! 962: {
! 963: struct tcpcb *tp = intotcpcb(inp);
! 964: struct rtentry *rt = in_pcbrtentry(inp);
! 965: int change = 0;
! 966:
! 967: if (tp != 0) {
! 968: int orig_maxseg = tp->t_maxseg;
! 969: if (rt != 0) {
! 970: /*
! 971: * If this was not a host route, remove and realloc.
! 972: */
! 973: if ((rt->rt_flags & RTF_HOST) == 0) {
! 974: in_rtchange(inp, errno);
! 975: if ((rt = in_pcbrtentry(inp)) == 0)
! 976: return;
! 977: }
! 978: if (orig_maxseg != tp->t_maxseg ||
! 979: (rt->rt_rmx.rmx_locks & RTV_MTU))
! 980: change = 1;
! 981: }
! 982: tcp_mss(tp, -1);
! 983:
! 984: /*
! 985: * Resend unacknowledged packets
! 986: */
! 987: tp->snd_nxt = tp->snd_una;
! 988: if (change || errno > 0)
! 989: tcp_output(tp);
! 990: }
! 991: }
! 992:
! 993: void
! 994: tcp_mtudisc_increase(inp, errno)
! 995: struct inpcb *inp;
! 996: int errno;
! 997: {
! 998: struct tcpcb *tp = intotcpcb(inp);
! 999: struct rtentry *rt = in_pcbrtentry(inp);
! 1000:
! 1001: if (tp != 0 && rt != 0) {
! 1002: /*
! 1003: * If this was a host route, remove and realloc.
! 1004: */
! 1005: if (rt->rt_flags & RTF_HOST)
! 1006: in_rtchange(inp, errno);
! 1007:
! 1008: /* also takes care of congestion window */
! 1009: tcp_mss(tp, -1);
! 1010: }
! 1011: }
! 1012:
! 1013: #define TCP_ISS_CONN_INC 4096
! 1014: int tcp_secret_init;
! 1015: u_char tcp_secret[16];
! 1016: MD5_CTX tcp_secret_ctx;
! 1017:
! 1018: void
! 1019: tcp_set_iss_tsm(struct tcpcb *tp)
! 1020: {
! 1021: MD5_CTX ctx;
! 1022: u_int32_t digest[4];
! 1023:
! 1024: if (tcp_secret_init == 0) {
! 1025: arc4random_bytes(tcp_secret, sizeof(tcp_secret));
! 1026: MD5Init(&tcp_secret_ctx);
! 1027: MD5Update(&tcp_secret_ctx, tcp_secret, sizeof(tcp_secret));
! 1028: tcp_secret_init = 1;
! 1029: }
! 1030: ctx = tcp_secret_ctx;
! 1031: MD5Update(&ctx, (char *)&tp->t_inpcb->inp_lport, sizeof(u_short));
! 1032: MD5Update(&ctx, (char *)&tp->t_inpcb->inp_fport, sizeof(u_short));
! 1033: if (tp->pf == AF_INET6) {
! 1034: MD5Update(&ctx, (char *)&tp->t_inpcb->inp_laddr6,
! 1035: sizeof(struct in6_addr));
! 1036: MD5Update(&ctx, (char *)&tp->t_inpcb->inp_faddr6,
! 1037: sizeof(struct in6_addr));
! 1038: } else {
! 1039: MD5Update(&ctx, (char *)&tp->t_inpcb->inp_laddr,
! 1040: sizeof(struct in_addr));
! 1041: MD5Update(&ctx, (char *)&tp->t_inpcb->inp_faddr,
! 1042: sizeof(struct in_addr));
! 1043: }
! 1044: MD5Final((u_char *)digest, &ctx);
! 1045: tcp_iss += TCP_ISS_CONN_INC;
! 1046: tp->iss = digest[0] + tcp_iss;
! 1047: tp->ts_modulate = digest[1];
! 1048: }
! 1049:
! 1050: #ifdef TCP_SIGNATURE
! 1051: int
! 1052: tcp_signature_tdb_attach()
! 1053: {
! 1054: return (0);
! 1055: }
! 1056:
! 1057: int
! 1058: tcp_signature_tdb_init(tdbp, xsp, ii)
! 1059: struct tdb *tdbp;
! 1060: struct xformsw *xsp;
! 1061: struct ipsecinit *ii;
! 1062: {
! 1063: if ((ii->ii_authkeylen < 1) || (ii->ii_authkeylen > 80))
! 1064: return (EINVAL);
! 1065:
! 1066: tdbp->tdb_amxkey = malloc(ii->ii_authkeylen, M_XDATA, M_DONTWAIT);
! 1067: if (tdbp->tdb_amxkey == NULL)
! 1068: return (ENOMEM);
! 1069: bcopy(ii->ii_authkey, tdbp->tdb_amxkey, ii->ii_authkeylen);
! 1070: tdbp->tdb_amxkeylen = ii->ii_authkeylen;
! 1071:
! 1072: return (0);
! 1073: }
! 1074:
! 1075: int
! 1076: tcp_signature_tdb_zeroize(tdbp)
! 1077: struct tdb *tdbp;
! 1078: {
! 1079: if (tdbp->tdb_amxkey) {
! 1080: bzero(tdbp->tdb_amxkey, tdbp->tdb_amxkeylen);
! 1081: free(tdbp->tdb_amxkey, M_XDATA);
! 1082: tdbp->tdb_amxkey = NULL;
! 1083: }
! 1084:
! 1085: return (0);
! 1086: }
! 1087:
! 1088: int
! 1089: tcp_signature_tdb_input(m, tdbp, skip, protoff)
! 1090: struct mbuf *m;
! 1091: struct tdb *tdbp;
! 1092: int skip, protoff;
! 1093: {
! 1094: return (0);
! 1095: }
! 1096:
! 1097: int
! 1098: tcp_signature_tdb_output(m, tdbp, mp, skip, protoff)
! 1099: struct mbuf *m;
! 1100: struct tdb *tdbp;
! 1101: struct mbuf **mp;
! 1102: int skip, protoff;
! 1103: {
! 1104: return (EINVAL);
! 1105: }
! 1106:
! 1107: int
! 1108: tcp_signature_apply(fstate, data, len)
! 1109: caddr_t fstate;
! 1110: caddr_t data;
! 1111: unsigned int len;
! 1112: {
! 1113: MD5Update((MD5_CTX *)fstate, (char *)data, len);
! 1114: return 0;
! 1115: }
! 1116:
! 1117: int
! 1118: tcp_signature(struct tdb *tdb, int af, struct mbuf *m, struct tcphdr *th,
! 1119: int iphlen, int doswap, char *sig)
! 1120: {
! 1121: MD5_CTX ctx;
! 1122: int len;
! 1123: struct tcphdr th0;
! 1124:
! 1125: MD5Init(&ctx);
! 1126:
! 1127: switch(af) {
! 1128: case 0:
! 1129: #ifdef INET
! 1130: case AF_INET: {
! 1131: struct ippseudo ippseudo;
! 1132: struct ip *ip;
! 1133:
! 1134: ip = mtod(m, struct ip *);
! 1135:
! 1136: ippseudo.ippseudo_src = ip->ip_src;
! 1137: ippseudo.ippseudo_dst = ip->ip_dst;
! 1138: ippseudo.ippseudo_pad = 0;
! 1139: ippseudo.ippseudo_p = IPPROTO_TCP;
! 1140: ippseudo.ippseudo_len = htons(m->m_pkthdr.len - iphlen);
! 1141:
! 1142: MD5Update(&ctx, (char *)&ippseudo,
! 1143: sizeof(struct ippseudo));
! 1144: break;
! 1145: }
! 1146: #endif
! 1147: #ifdef INET6
! 1148: case AF_INET6: {
! 1149: struct ip6_hdr_pseudo ip6pseudo;
! 1150: struct ip6_hdr *ip6;
! 1151:
! 1152: ip6 = mtod(m, struct ip6_hdr *);
! 1153: bzero(&ip6pseudo, sizeof(ip6pseudo));
! 1154: ip6pseudo.ip6ph_src = ip6->ip6_src;
! 1155: ip6pseudo.ip6ph_dst = ip6->ip6_dst;
! 1156: in6_clearscope(&ip6pseudo.ip6ph_src);
! 1157: in6_clearscope(&ip6pseudo.ip6ph_dst);
! 1158: ip6pseudo.ip6ph_nxt = IPPROTO_TCP;
! 1159: ip6pseudo.ip6ph_len = htonl(m->m_pkthdr.len - iphlen);
! 1160:
! 1161: MD5Update(&ctx, (char *)&ip6pseudo,
! 1162: sizeof(ip6pseudo));
! 1163: break;
! 1164: }
! 1165: #endif
! 1166: }
! 1167:
! 1168: th0 = *th;
! 1169: th0.th_sum = 0;
! 1170:
! 1171: if (doswap) {
! 1172: HTONL(th0.th_seq);
! 1173: HTONL(th0.th_ack);
! 1174: HTONS(th0.th_win);
! 1175: HTONS(th0.th_urp);
! 1176: }
! 1177: MD5Update(&ctx, (char *)&th0, sizeof(th0));
! 1178:
! 1179: len = m->m_pkthdr.len - iphlen - th->th_off * sizeof(uint32_t);
! 1180:
! 1181: if (len > 0 &&
! 1182: m_apply(m, iphlen + th->th_off * sizeof(uint32_t), len,
! 1183: tcp_signature_apply, (caddr_t)&ctx))
! 1184: return (-1);
! 1185:
! 1186: MD5Update(&ctx, tdb->tdb_amxkey, tdb->tdb_amxkeylen);
! 1187: MD5Final(sig, &ctx);
! 1188:
! 1189: return (0);
! 1190: }
! 1191: #endif /* TCP_SIGNATURE */
! 1192:
! 1193: #define TCP_RNDISS_ROUNDS 16
! 1194: #define TCP_RNDISS_OUT 7200
! 1195: #define TCP_RNDISS_MAX 30000
! 1196:
! 1197: u_int8_t tcp_rndiss_sbox[128];
! 1198: u_int16_t tcp_rndiss_msb;
! 1199: u_int16_t tcp_rndiss_cnt;
! 1200: long tcp_rndiss_reseed;
! 1201:
! 1202: u_int16_t
! 1203: tcp_rndiss_encrypt(val)
! 1204: u_int16_t val;
! 1205: {
! 1206: u_int16_t sum = 0, i;
! 1207:
! 1208: for (i = 0; i < TCP_RNDISS_ROUNDS; i++) {
! 1209: sum += 0x79b9;
! 1210: val ^= ((u_int16_t)tcp_rndiss_sbox[(val^sum) & 0x7f]) << 7;
! 1211: val = ((val & 0xff) << 7) | (val >> 8);
! 1212: }
! 1213:
! 1214: return val;
! 1215: }
! 1216:
! 1217: void
! 1218: tcp_rndiss_init()
! 1219: {
! 1220: get_random_bytes(tcp_rndiss_sbox, sizeof(tcp_rndiss_sbox));
! 1221:
! 1222: tcp_rndiss_reseed = time_second + TCP_RNDISS_OUT;
! 1223: tcp_rndiss_msb = tcp_rndiss_msb == 0x8000 ? 0 : 0x8000;
! 1224: tcp_rndiss_cnt = 0;
! 1225: }
! 1226:
! 1227: tcp_seq
! 1228: tcp_rndiss_next()
! 1229: {
! 1230: if (tcp_rndiss_cnt >= TCP_RNDISS_MAX ||
! 1231: time_second > tcp_rndiss_reseed)
! 1232: tcp_rndiss_init();
! 1233:
! 1234: /* (arc4random() & 0x7fff) ensures a 32768 byte gap between ISS */
! 1235: return ((tcp_rndiss_encrypt(tcp_rndiss_cnt++) | tcp_rndiss_msb) <<16) |
! 1236: (arc4random() & 0x7fff);
! 1237: }
! 1238:
CVSweb