1: /* 2: * Copyright (c) 1982, 1986 Regents of the University of California. 3: * All rights reserved. 4: * 5: * Redistribution and use in source and binary forms are permitted 6: * provided that this notice is preserved and that due credit is given 7: * to the University of California at Berkeley. The name of the University 8: * may not be used to endorse or promote products derived from this 9: * software without specific prior written permission. This software 10: * is provided ``as is'' without express or implied warranty. 11: * 12: * @(#)tcp_subr.c 7.13.3 (2.11BSD GTE) 1995/10/10 13: */ 14: 15: #include "param.h" 16: #include "systm.h" 17: #include "mbuf.h" 18: #include "socket.h" 19: #include "socketvar.h" 20: #include "protosw.h" 21: #include "errno.h" 22: 23: #include "../net/route.h" 24: #include "../net/if.h" 25: 26: #include "domain.h" 27: #include "in.h" 28: #include "in_pcb.h" 29: #include "in_systm.h" 30: #include "ip.h" 31: #include "ip_var.h" 32: #include "ip_icmp.h" 33: #include "tcp.h" 34: #include "tcp_fsm.h" 35: #include "tcp_seq.h" 36: #include "tcp_timer.h" 37: #include "tcp_var.h" 38: #include "tcpip.h" 39: 40: /* 41: * Tcp initialization 42: */ 43: tcp_init() 44: { 45: 46: tcp_iss = 1; /* wrong */ 47: tcb.inp_next = tcb.inp_prev = &tcb; 48: } 49: 50: /* 51: * Create template to be used to send tcp packets on a connection. 52: * Call after host entry created, allocates an mbuf and fills 53: * in a skeletal tcp/ip header, minimizing the amount of work 54: * necessary when the connection is used. 55: */ 56: struct tcpiphdr * 57: tcp_template(tp) 58: struct tcpcb *tp; 59: { 60: register struct inpcb *inp = tp->t_inpcb; 61: register struct mbuf *m; 62: register struct tcpiphdr *n; 63: 64: if ((n = tp->t_template) == 0) { 65: m = m_get(M_DONTWAIT, MT_HEADER); 66: if (m == NULL) 67: return (0); 68: m->m_off = MMAXOFF - sizeof (struct tcpiphdr); 69: m->m_len = sizeof (struct tcpiphdr); 70: n = mtod(m, struct tcpiphdr *); 71: } 72: n->ti_next = n->ti_prev = 0; 73: n->ti_x1 = 0; 74: n->ti_pad = 0; 75: n->ti_pr = IPPROTO_TCP; 76: n->ti_len = htons(sizeof (struct tcpiphdr) - sizeof (struct ip)); 77: n->ti_src = inp->inp_laddr; 78: n->ti_dst = inp->inp_faddr; 79: n->ti_sport = inp->inp_lport; 80: n->ti_dport = inp->inp_fport; 81: n->ti_seq = 0; 82: n->ti_ack = 0; 83: n->ti_x2 = 0; 84: n->ti_off = 5; 85: n->ti_flags = 0; 86: n->ti_win = 0; 87: n->ti_sum = 0; 88: n->ti_urp = 0; 89: return (n); 90: } 91: 92: /* 93: * Send a single message to the TCP at address specified by 94: * the given TCP/IP header. If flags==0, then we make a copy 95: * of the tcpiphdr at ti and send directly to the addressed host. 96: * This is used to force keep alive messages out using the TCP 97: * template for a connection tp->t_template. If flags are given 98: * then we send a message back to the TCP which originated the 99: * segment ti, and discard the mbuf containing it and any other 100: * attached mbufs. 101: * 102: * In any case the ack and sequence number of the transmitted 103: * segment are as specified by the parameters. 104: */ 105: tcp_respond(tp, ti, ack, seq, flags) 106: struct tcpcb *tp; 107: register struct tcpiphdr *ti; 108: tcp_seq ack, seq; 109: int flags; 110: { 111: register struct mbuf *m; 112: int win = 0, tlen; 113: struct route *ro = 0; 114: 115: if (tp) { 116: win = sbspace(&tp->t_inpcb->inp_socket->so_rcv); 117: ro = &tp->t_inpcb->inp_route; 118: } 119: if (flags == 0) { 120: m = m_get(M_DONTWAIT, MT_HEADER); 121: if (m == NULL) 122: return; 123: #ifdef TCP_COMPAT_42 124: tlen = 1; 125: #else 126: tlen = 0; 127: #endif 128: m->m_len = sizeof (struct tcpiphdr) + tlen; 129: *mtod(m, struct tcpiphdr *) = *ti; 130: ti = mtod(m, struct tcpiphdr *); 131: flags = TH_ACK; 132: } else { 133: m = dtom(ti); 134: m_freem(m->m_next); 135: m->m_next = 0; 136: m->m_off = (int)ti - (int)m; 137: tlen = 0; 138: m->m_len = sizeof (struct tcpiphdr); 139: #define xchg(a,b,type) { type t; t=a; a=b; b=t; } 140: xchg(ti->ti_dst.s_addr, ti->ti_src.s_addr, u_long); 141: xchg(ti->ti_dport, ti->ti_sport, u_short); 142: #undef xchg 143: } 144: ti->ti_next = ti->ti_prev = 0; 145: ti->ti_x1 = 0; 146: ti->ti_pad = 0; 147: ti->ti_len = htons((u_short)(sizeof (struct tcphdr) + tlen)); 148: ti->ti_seq = htonl(seq); 149: ti->ti_ack = htonl(ack); 150: ti->ti_x2 = 0; 151: ti->ti_off = sizeof (struct tcphdr) >> 2; 152: ti->ti_flags = flags; 153: ti->ti_win = htons((u_short)win); 154: ti->ti_urp = 0; 155: ti->ti_sum = in_cksum(m, sizeof (struct tcpiphdr) + tlen); 156: ((struct ip *)ti)->ip_len = sizeof (struct tcpiphdr) + tlen; 157: ((struct ip *)ti)->ip_ttl = ip_defttl; 158: (void) ip_output(m, (struct mbuf *)0, ro, 0); 159: } 160: 161: /* 162: * Create a new TCP control block, making an 163: * empty reassembly queue and hooking it to the argument 164: * protocol control block. 165: */ 166: struct tcpcb * 167: tcp_newtcpcb(inp) 168: struct inpcb *inp; 169: { 170: struct mbuf *m = m_getclr(M_DONTWAIT, MT_PCB); 171: register struct tcpcb *tp; 172: 173: if (m == NULL) 174: return ((struct tcpcb *)0); 175: tp = mtod(m, struct tcpcb *); 176: tp->seg_next = tp->seg_prev = (struct tcpiphdr *)tp; 177: tp->t_maxseg = TCP_MSS; 178: tp->t_flags = 0; /* sends options! */ 179: tp->t_inpcb = inp; 180: /* 181: * Init srtt to TCPTV_SRTTBASE (0), so we can tell that we have no 182: * rtt estimate. Set rttvar so that srtt + 2 * rttvar gives 183: * reasonable initial retransmit time. 184: */ 185: tp->t_srtt = TCPTV_SRTTBASE; 186: tp->t_rttvar = TCPTV_SRTTDFLT << 2; 187: TCPT_RANGESET(tp->t_rxtcur, 188: ((TCPTV_SRTTBASE >> 2) + (TCPTV_SRTTDFLT << 2)) >> 1, 189: TCPTV_MIN, TCPTV_REXMTMAX); 190: tp->snd_cwnd = sbspace(&inp->inp_socket->so_snd); 191: tp->snd_ssthresh = 65535; /* XXX */ 192: inp->inp_ppcb = (caddr_t)tp; 193: return (tp); 194: } 195: 196: /* 197: * Drop a TCP connection, reporting 198: * the specified error. If connection is synchronized, 199: * then send a RST to peer. 200: */ 201: struct tcpcb * 202: tcp_drop(tp, errno) 203: register struct tcpcb *tp; 204: int errno; 205: { 206: struct socket *so = tp->t_inpcb->inp_socket; 207: 208: if (TCPS_HAVERCVDSYN(tp->t_state)) { 209: tp->t_state = TCPS_CLOSED; 210: (void) tcp_output(tp); 211: tcpstat.tcps_drops++; 212: } else 213: tcpstat.tcps_conndrops++; 214: so->so_error = errno; 215: return (tcp_close(tp)); 216: } 217: 218: /* 219: * Close a TCP control block: 220: * discard all space held by the tcp 221: * discard internet protocol block 222: * wake up any sleepers 223: */ 224: struct tcpcb * 225: tcp_close(tp) 226: register struct tcpcb *tp; 227: { 228: register struct tcpiphdr *t; 229: struct inpcb *inp = tp->t_inpcb; 230: struct socket *so = inp->inp_socket; 231: register struct mbuf *m; 232: 233: t = tp->seg_next; 234: while (t != (struct tcpiphdr *)tp) { 235: t = (struct tcpiphdr *)t->ti_next; 236: m = dtom(t->ti_prev); 237: remque(t->ti_prev); 238: m_freem(m); 239: } 240: if (tp->t_template) 241: (void) m_free(dtom(tp->t_template)); 242: (void) m_free(dtom(tp)); 243: inp->inp_ppcb = 0; 244: soisdisconnected(so); 245: in_pcbdetach(inp); 246: tcpstat.tcps_closed++; 247: return ((struct tcpcb *)0); 248: } 249: 250: tcp_drain() 251: { 252: register struct inpcb *ip, *ipnxt; 253: register struct tcpcb *tp; 254: 255: /* 256: * Search through tcb's and look for TIME_WAIT states to liberate, 257: * these are due to go away soon anyhow and we're short of space or 258: * we wouldn't be here... 259: */ 260: ip = tcb.inp_next; 261: if (ip == 0) 262: return; 263: for (; ip != &tcb; ip = ipnxt) { 264: ipnxt = ip->inp_next; 265: tp = intotcpcb(ip); 266: if (tp == 0) 267: continue; 268: if (tp->t_state == TCPS_TIME_WAIT) 269: tcp_close(tp); 270: } 271: } 272: 273: /* 274: * Notify a tcp user of an asynchronous error; 275: * just wake up so that he can collect error status. 276: */ 277: tcp_notify(inp, error) 278: register struct inpcb *inp; 279: int error; 280: { 281: 282: inp->inp_socket->so_error = error; 283: WAKEUP((caddr_t) &inp->inp_socket->so_timeo); 284: sorwakeup(inp->inp_socket); 285: sowwakeup(inp->inp_socket); 286: } 287: 288: tcp_ctlinput(cmd, sa, ip) 289: register int cmd; 290: struct sockaddr *sa; 291: register struct ip *ip; 292: { 293: register struct tcphdr *th; 294: extern struct in_addr zeroin_addr; 295: extern u_char inetctlerrmap[]; 296: int (*notify)() = tcp_notify, tcp_quench(); 297: 298: if (cmd == PRC_QUENCH) 299: notify = tcp_quench; 300: else if ((unsigned)cmd > PRC_NCMDS || inetctlerrmap[cmd] == 0) 301: return; 302: if (ip) { 303: th = (struct tcphdr *)((caddr_t)ip + (ip->ip_hl << 2)); 304: in_pcbnotify(&tcb, sa, th->th_dport, ip->ip_src, th->th_sport, 305: cmd, notify); 306: } else 307: in_pcbnotify(&tcb, sa, 0, zeroin_addr, 0, cmd, notify); 308: } 309: 310: /* 311: * When a source quench is received, close congestion window 312: * to one segment. We will gradually open it again as we proceed. 313: */ 314: tcp_quench(inp) 315: struct inpcb *inp; 316: { 317: struct tcpcb *tp = intotcpcb(inp); 318: 319: if (tp) 320: tp->snd_cwnd = tp->t_maxseg; 321: }