|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1982, 1986, 1988, 1990 Regents of the University of California. ! 3: * All rights reserved. ! 4: * ! 5: * Redistribution is only permitted until one year after the first shipment ! 6: * of 4.4BSD by the Regents. Otherwise, redistribution and use in source and ! 7: * binary forms are permitted provided that: (1) source distributions retain ! 8: * this entire copyright notice and comment, and (2) distributions including ! 9: * binaries display the following acknowledgement: This product includes ! 10: * software developed by the University of California, Berkeley and its ! 11: * contributors'' in the documentation or other materials provided with the ! 12: * distribution and in all advertising materials mentioning features or use ! 13: * of this software. Neither the name of the University nor the names of ! 14: * its contributors may be used to endorse or promote products derived from ! 15: * this software without specific prior written permission. ! 16: * THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED ! 17: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF ! 18: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ! 19: * ! 20: * @(#)tcp_subr.c 7.19 (Berkeley) 7/25/90 ! 21: */ ! 22: ! 23: #include "param.h" ! 24: #include "systm.h" ! 25: #include "malloc.h" ! 26: #include "mbuf.h" ! 27: #include "socket.h" ! 28: #include "socketvar.h" ! 29: #include "protosw.h" ! 30: #include "errno.h" ! 31: ! 32: #include "../net/route.h" ! 33: #include "../net/if.h" ! 34: ! 35: #include "in.h" ! 36: #include "in_systm.h" ! 37: #include "ip.h" ! 38: #include "in_pcb.h" ! 39: #include "ip_var.h" ! 40: #include "ip_icmp.h" ! 41: #include "tcp.h" ! 42: #include "tcp_fsm.h" ! 43: #include "tcp_seq.h" ! 44: #include "tcp_timer.h" ! 45: #include "tcp_var.h" ! 46: #include "tcpip.h" ! 47: ! 48: /* patchable/settable parameters for tcp */ ! 49: int tcp_ttl = TCP_TTL; ! 50: int tcp_mssdflt = TCP_MSS; ! 51: int tcp_rttdflt = TCPTV_SRTTDFLT / PR_SLOWHZ; ! 52: ! 53: extern struct inpcb *tcp_last_inpcb; ! 54: ! 55: /* ! 56: * Tcp initialization ! 57: */ ! 58: tcp_init() ! 59: { ! 60: ! 61: tcp_iss = 1; /* wrong */ ! 62: tcb.inp_next = tcb.inp_prev = &tcb; ! 63: if (max_protohdr < sizeof(struct tcpiphdr)) ! 64: max_protohdr = sizeof(struct tcpiphdr); ! 65: if (max_linkhdr + sizeof(struct tcpiphdr) > MHLEN) ! 66: panic("tcp_init"); ! 67: } ! 68: ! 69: /* ! 70: * Create template to be used to send tcp packets on a connection. ! 71: * Call after host entry created, allocates an mbuf and fills ! 72: * in a skeletal tcp/ip header, minimizing the amount of work ! 73: * necessary when the connection is used. ! 74: */ ! 75: struct tcpiphdr * ! 76: tcp_template(tp) ! 77: struct tcpcb *tp; ! 78: { ! 79: register struct inpcb *inp = tp->t_inpcb; ! 80: register struct mbuf *m; ! 81: register struct tcpiphdr *n; ! 82: ! 83: if ((n = tp->t_template) == 0) { ! 84: m = m_get(M_DONTWAIT, MT_HEADER); ! 85: if (m == NULL) ! 86: return (0); ! 87: m->m_len = sizeof (struct tcpiphdr); ! 88: n = mtod(m, struct tcpiphdr *); ! 89: } ! 90: n->ti_next = n->ti_prev = 0; ! 91: n->ti_x1 = 0; ! 92: n->ti_pr = IPPROTO_TCP; ! 93: n->ti_len = htons(sizeof (struct tcpiphdr) - sizeof (struct ip)); ! 94: n->ti_src = inp->inp_laddr; ! 95: n->ti_dst = inp->inp_faddr; ! 96: n->ti_sport = inp->inp_lport; ! 97: n->ti_dport = inp->inp_fport; ! 98: n->ti_seq = 0; ! 99: n->ti_ack = 0; ! 100: n->ti_x2 = 0; ! 101: n->ti_off = 5; ! 102: n->ti_flags = 0; ! 103: n->ti_win = 0; ! 104: n->ti_sum = 0; ! 105: n->ti_urp = 0; ! 106: return (n); ! 107: } ! 108: ! 109: /* ! 110: * Send a single message to the TCP at address specified by ! 111: * the given TCP/IP header. If m == 0, then we make a copy ! 112: * of the tcpiphdr at ti and send directly to the addressed host. ! 113: * This is used to force keep alive messages out using the TCP ! 114: * template for a connection tp->t_template. If flags are given ! 115: * then we send a message back to the TCP which originated the ! 116: * segment ti, and discard the mbuf containing it and any other ! 117: * attached mbufs. ! 118: * ! 119: * In any case the ack and sequence number of the transmitted ! 120: * segment are as specified by the parameters. ! 121: */ ! 122: tcp_respond(tp, ti, m, ack, seq, flags) ! 123: struct tcpcb *tp; ! 124: register struct tcpiphdr *ti; ! 125: register struct mbuf *m; ! 126: tcp_seq ack, seq; ! 127: int flags; ! 128: { ! 129: register int tlen; ! 130: int win = 0; ! 131: struct route *ro = 0; ! 132: ! 133: if (tp) { ! 134: win = sbspace(&tp->t_inpcb->inp_socket->so_rcv); ! 135: ro = &tp->t_inpcb->inp_route; ! 136: } ! 137: if (m == 0) { ! 138: m = m_gethdr(M_DONTWAIT, MT_HEADER); ! 139: if (m == NULL) ! 140: return; ! 141: #ifdef TCP_COMPAT_42 ! 142: tlen = 1; ! 143: #else ! 144: tlen = 0; ! 145: #endif ! 146: m->m_data += max_linkhdr; ! 147: *mtod(m, struct tcpiphdr *) = *ti; ! 148: ti = mtod(m, struct tcpiphdr *); ! 149: flags = TH_ACK; ! 150: } else { ! 151: m_freem(m->m_next); ! 152: m->m_next = 0; ! 153: m->m_data = (caddr_t)ti; ! 154: m->m_len = sizeof (struct tcpiphdr); ! 155: tlen = 0; ! 156: #define xchg(a,b,type) { type t; t=a; a=b; b=t; } ! 157: xchg(ti->ti_dst.s_addr, ti->ti_src.s_addr, u_long); ! 158: xchg(ti->ti_dport, ti->ti_sport, u_short); ! 159: #undef xchg ! 160: } ! 161: ti->ti_len = htons((u_short)(sizeof (struct tcphdr) + tlen)); ! 162: tlen += sizeof (struct tcpiphdr); ! 163: m->m_len = tlen; ! 164: m->m_pkthdr.len = tlen; ! 165: m->m_pkthdr.rcvif = (struct ifnet *) 0; ! 166: ti->ti_next = ti->ti_prev = 0; ! 167: ti->ti_x1 = 0; ! 168: ti->ti_seq = htonl(seq); ! 169: ti->ti_ack = htonl(ack); ! 170: ti->ti_x2 = 0; ! 171: ti->ti_off = sizeof (struct tcphdr) >> 2; ! 172: ti->ti_flags = flags; ! 173: ti->ti_win = htons((u_short)win); ! 174: ti->ti_urp = 0; ! 175: ti->ti_sum = in_cksum(m, tlen); ! 176: ((struct ip *)ti)->ip_len = tlen; ! 177: ((struct ip *)ti)->ip_ttl = tcp_ttl; ! 178: (void) ip_output(m, (struct mbuf *)0, ro, 0); ! 179: } ! 180: ! 181: /* ! 182: * Create a new TCP control block, making an ! 183: * empty reassembly queue and hooking it to the argument ! 184: * protocol control block. ! 185: */ ! 186: struct tcpcb * ! 187: tcp_newtcpcb(inp) ! 188: struct inpcb *inp; ! 189: { ! 190: struct mbuf *m = m_getclr(M_DONTWAIT, MT_PCB); ! 191: register struct tcpcb *tp; ! 192: ! 193: if (m == NULL) ! 194: return ((struct tcpcb *)0); ! 195: tp = mtod(m, struct tcpcb *); ! 196: tp->seg_next = tp->seg_prev = (struct tcpiphdr *)tp; ! 197: tp->t_maxseg = tcp_mssdflt; ! 198: ! 199: tp->t_flags = 0; /* sends options! */ ! 200: tp->t_inpcb = inp; ! 201: /* ! 202: * Init srtt to TCPTV_SRTTBASE (0), so we can tell that we have no ! 203: * rtt estimate. Set rttvar so that srtt + 2 * rttvar gives ! 204: * reasonable initial retransmit time. ! 205: */ ! 206: tp->t_srtt = TCPTV_SRTTBASE; ! 207: tp->t_rttvar = tcp_rttdflt * PR_SLOWHZ << 2; ! 208: tp->t_rttmin = TCPTV_MIN; ! 209: TCPT_RANGESET(tp->t_rxtcur, ! 210: ((TCPTV_SRTTBASE >> 2) + (TCPTV_SRTTDFLT << 2)) >> 1, ! 211: TCPTV_MIN, TCPTV_REXMTMAX); ! 212: tp->snd_cwnd = TCP_MAXWIN; ! 213: tp->snd_ssthresh = TCP_MAXWIN; ! 214: inp->inp_ip.ip_ttl = tcp_ttl; ! 215: inp->inp_ppcb = (caddr_t)tp; ! 216: return (tp); ! 217: } ! 218: ! 219: /* ! 220: * Drop a TCP connection, reporting ! 221: * the specified error. If connection is synchronized, ! 222: * then send a RST to peer. ! 223: */ ! 224: struct tcpcb * ! 225: tcp_drop(tp, errno) ! 226: register struct tcpcb *tp; ! 227: int errno; ! 228: { ! 229: struct socket *so = tp->t_inpcb->inp_socket; ! 230: ! 231: if (TCPS_HAVERCVDSYN(tp->t_state)) { ! 232: tp->t_state = TCPS_CLOSED; ! 233: (void) tcp_output(tp); ! 234: tcpstat.tcps_drops++; ! 235: } else ! 236: tcpstat.tcps_conndrops++; ! 237: if (errno == ETIMEDOUT && tp->t_softerror) ! 238: errno = tp->t_softerror; ! 239: so->so_error = errno; ! 240: return (tcp_close(tp)); ! 241: } ! 242: ! 243: /* ! 244: * Close a TCP control block: ! 245: * discard all space held by the tcp ! 246: * discard internet protocol block ! 247: * wake up any sleepers ! 248: */ ! 249: struct tcpcb * ! 250: tcp_close(tp) ! 251: register struct tcpcb *tp; ! 252: { ! 253: register struct tcpiphdr *t; ! 254: struct inpcb *inp = tp->t_inpcb; ! 255: struct socket *so = inp->inp_socket; ! 256: register struct mbuf *m; ! 257: #ifdef RTV_RTT ! 258: register struct rtentry *rt; ! 259: ! 260: /* ! 261: * If we sent enough data to get some meaningful characteristics, ! 262: * save them in the routing entry. 'Enough' is arbitrarily ! 263: * defined as 4K (default tcp_sendspace) * 16. This would ! 264: * give us 16 rtt samples assuming we only get one sample per ! 265: * window (the usual case on a long haul net). 16 samples is ! 266: * enough for the srtt filter to converge to within 5% of the correct ! 267: * value; fewer samples and we could save a very bogus rtt. ! 268: * ! 269: * Don't update the default route's characteristics and don't ! 270: * update anything that the user "locked". ! 271: */ ! 272: if (SEQ_LT(tp->iss+(4096*16), tp->snd_max) && ! 273: (rt = inp->inp_route.ro_rt) && ! 274: ((struct sockaddr_in *) rt_key(rt))->sin_addr.s_addr != ! 275: INADDR_ANY) { ! 276: register u_long i; ! 277: ! 278: if ((rt->rt_rmx.rmx_locks & RTV_RTT) == 0) { ! 279: i = tp->t_srtt * ! 280: (RTM_RTTUNIT / (PR_SLOWHZ * TCP_RTT_SCALE)); ! 281: if (rt->rt_rmx.rmx_rtt && i) ! 282: /* ! 283: * filter this update to half the old & half ! 284: * the new values, converting scale. ! 285: * See route.h and tcp_var.h for a ! 286: * description of the scaling constants. ! 287: */ ! 288: rt->rt_rmx.rmx_rtt = ! 289: (rt->rt_rmx.rmx_rtt + i) / 2; ! 290: else ! 291: rt->rt_rmx.rmx_rtt = i; ! 292: } ! 293: if ((rt->rt_rmx.rmx_locks & RTV_RTTVAR) == 0) { ! 294: i = tp->t_rttvar * ! 295: (RTM_RTTUNIT / (PR_SLOWHZ * TCP_RTTVAR_SCALE)); ! 296: if (rt->rt_rmx.rmx_rttvar && i) ! 297: rt->rt_rmx.rmx_rttvar = ! 298: (rt->rt_rmx.rmx_rttvar + i) / 2; ! 299: else ! 300: rt->rt_rmx.rmx_rttvar = i; ! 301: } ! 302: /* ! 303: * update the pipelimit (ssthresh) if it has been updated ! 304: * already or if a pipesize was specified & the threshhold ! 305: * got below half the pipesize. I.e., wait for bad news ! 306: * before we start updating, then update on both good ! 307: * and bad news. ! 308: */ ! 309: if ((rt->rt_rmx.rmx_locks & RTV_SSTHRESH) == 0 && ! 310: (i = tp->snd_ssthresh) && rt->rt_rmx.rmx_ssthresh || ! 311: i < (rt->rt_rmx.rmx_sendpipe / 2)) { ! 312: /* ! 313: * convert the limit from user data bytes to ! 314: * packets then to packet data bytes. ! 315: */ ! 316: i = (i + tp->t_maxseg / 2) / tp->t_maxseg; ! 317: if (i < 2) ! 318: i = 2; ! 319: i *= (u_long)(tp->t_maxseg + sizeof (struct tcpiphdr)); ! 320: if (rt->rt_rmx.rmx_ssthresh) ! 321: rt->rt_rmx.rmx_ssthresh = ! 322: (rt->rt_rmx.rmx_ssthresh + i) / 2; ! 323: else ! 324: rt->rt_rmx.rmx_ssthresh = i; ! 325: } ! 326: } ! 327: #endif RTV_RTT ! 328: /* free the reassembly queue, if any */ ! 329: t = tp->seg_next; ! 330: while (t != (struct tcpiphdr *)tp) { ! 331: t = (struct tcpiphdr *)t->ti_next; ! 332: m = REASS_MBUF((struct tcpiphdr *)t->ti_prev); ! 333: remque(t->ti_prev); ! 334: m_freem(m); ! 335: } ! 336: if (tp->t_template) ! 337: (void) m_free(dtom(tp->t_template)); ! 338: (void) m_free(dtom(tp)); ! 339: inp->inp_ppcb = 0; ! 340: soisdisconnected(so); ! 341: /* clobber input pcb cache if we're closing the cached connection */ ! 342: if (inp == tcp_last_inpcb) ! 343: tcp_last_inpcb = &tcb; ! 344: in_pcbdetach(inp); ! 345: tcpstat.tcps_closed++; ! 346: return ((struct tcpcb *)0); ! 347: } ! 348: ! 349: tcp_drain() ! 350: { ! 351: ! 352: } ! 353: ! 354: /* ! 355: * Notify a tcp user of an asynchronous error; ! 356: * store error as soft error, but wake up user ! 357: * (for now, won't do anything until can select for soft error). ! 358: */ ! 359: tcp_notify(inp, error) ! 360: register struct inpcb *inp; ! 361: int error; ! 362: { ! 363: ! 364: ((struct tcpcb *)inp->inp_ppcb)->t_softerror = error; ! 365: wakeup((caddr_t) &inp->inp_socket->so_timeo); ! 366: sorwakeup(inp->inp_socket); ! 367: sowwakeup(inp->inp_socket); ! 368: } ! 369: ! 370: tcp_ctlinput(cmd, sa, ip) ! 371: int cmd; ! 372: struct sockaddr *sa; ! 373: register struct ip *ip; ! 374: { ! 375: register struct tcphdr *th; ! 376: extern struct in_addr zeroin_addr; ! 377: extern u_char inetctlerrmap[]; ! 378: int (*notify)() = tcp_notify, tcp_quench(); ! 379: ! 380: if (cmd == PRC_QUENCH) ! 381: notify = tcp_quench; ! 382: else if ((unsigned)cmd > PRC_NCMDS || inetctlerrmap[cmd] == 0) ! 383: return; ! 384: if (ip) { ! 385: th = (struct tcphdr *)((caddr_t)ip + (ip->ip_hl << 2)); ! 386: in_pcbnotify(&tcb, sa, th->th_dport, ip->ip_src, th->th_sport, ! 387: cmd, notify); ! 388: } else ! 389: in_pcbnotify(&tcb, sa, 0, zeroin_addr, 0, cmd, notify); ! 390: } ! 391: ! 392: /* ! 393: * When a source quench is received, close congestion window ! 394: * to one segment. We will gradually open it again as we proceed. ! 395: */ ! 396: tcp_quench(inp) ! 397: struct inpcb *inp; ! 398: { ! 399: struct tcpcb *tp = intotcpcb(inp); ! 400: ! 401: if (tp) ! 402: tp->snd_cwnd = tp->t_maxseg; ! 403: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.