1: /* 2: * Copyright (c) 1982, 1986 Regents of the University of California. 3: * All rights reserved. The Berkeley software License Agreement 4: * specifies the terms and conditions for redistribution. 5: * 6: * @(#)tcp_subr.c 7.1 (Berkeley) 6/5/86 7: */ 8: 9: #include "param.h" 10: #include "systm.h" 11: #include "mbuf.h" 12: #include "socket.h" 13: #include "socketvar.h" 14: #include "protosw.h" 15: #include "errno.h" 16: 17: #include "../net/route.h" 18: #include "../net/if.h" 19: 20: #include "in.h" 21: #include "in_pcb.h" 22: #include "in_systm.h" 23: #include "ip.h" 24: #include "ip_var.h" 25: #include "ip_icmp.h" 26: #include "tcp.h" 27: #include "tcp_fsm.h" 28: #include "tcp_seq.h" 29: #include "tcp_timer.h" 30: #include "tcp_var.h" 31: #include "tcpip.h" 32: 33: /* 34: * Tcp initialization 35: */ 36: tcp_init() 37: { 38: 39: tcp_iss = 1; /* wrong */ 40: tcb.inp_next = tcb.inp_prev = &tcb; 41: tcp_alpha = TCP_ALPHA; 42: tcp_beta = TCP_BETA; 43: } 44: 45: /* 46: * Create template to be used to send tcp packets on a connection. 47: * Call after host entry created, allocates an mbuf and fills 48: * in a skeletal tcp/ip header, minimizing the amount of work 49: * necessary when the connection is used. 50: */ 51: struct tcpiphdr * 52: tcp_template(tp) 53: struct tcpcb *tp; 54: { 55: register struct inpcb *inp = tp->t_inpcb; 56: register struct mbuf *m; 57: register struct tcpiphdr *n; 58: 59: if ((n = tp->t_template) == 0) { 60: m = m_get(M_WAIT, MT_HEADER); 61: if (m == NULL) 62: return (0); 63: m->m_off = MMAXOFF - sizeof (struct tcpiphdr); 64: m->m_len = sizeof (struct tcpiphdr); 65: n = mtod(m, struct tcpiphdr *); 66: } 67: n->ti_next = n->ti_prev = 0; 68: n->ti_x1 = 0; 69: n->ti_pr = IPPROTO_TCP; 70: n->ti_len = htons(sizeof (struct tcpiphdr) - sizeof (struct ip)); 71: n->ti_src = inp->inp_laddr; 72: n->ti_dst = inp->inp_faddr; 73: n->ti_sport = inp->inp_lport; 74: n->ti_dport = inp->inp_fport; 75: n->ti_seq = 0; 76: n->ti_ack = 0; 77: n->ti_x2 = 0; 78: n->ti_off = 5; 79: n->ti_flags = 0; 80: n->ti_win = 0; 81: n->ti_sum = 0; 82: n->ti_urp = 0; 83: return (n); 84: } 85: 86: /* 87: * Send a single message to the TCP at address specified by 88: * the given TCP/IP header. If flags==0, then we make a copy 89: * of the tcpiphdr at ti and send directly to the addressed host. 90: * This is used to force keep alive messages out using the TCP 91: * template for a connection tp->t_template. If flags are given 92: * then we send a message back to the TCP which originated the 93: * segment ti, and discard the mbuf containing it and any other 94: * attached mbufs. 95: * 96: * In any case the ack and sequence number of the transmitted 97: * segment are as specified by the parameters. 98: */ 99: tcp_respond(tp, ti, ack, seq, flags) 100: struct tcpcb *tp; 101: register struct tcpiphdr *ti; 102: tcp_seq ack, seq; 103: int flags; 104: { 105: struct mbuf *m; 106: int win = 0, tlen; 107: struct route *ro = 0; 108: 109: if (tp) { 110: win = sbspace(&tp->t_inpcb->inp_socket->so_rcv); 111: ro = &tp->t_inpcb->inp_route; 112: } 113: if (flags == 0) { 114: m = m_get(M_DONTWAIT, MT_HEADER); 115: if (m == NULL) 116: return; 117: m->m_len = sizeof (struct tcpiphdr) + 1; 118: *mtod(m, struct tcpiphdr *) = *ti; 119: ti = mtod(m, struct tcpiphdr *); 120: flags = TH_ACK; 121: tlen = 1; 122: } else { 123: m = dtom(ti); 124: m_freem(m->m_next); 125: m->m_next = 0; 126: m->m_off = (int)ti - (int)m; 127: m->m_len = sizeof (struct tcpiphdr); 128: #define xchg(a,b,type) { type t; t=a; a=b; b=t; } 129: xchg(ti->ti_dst.s_addr, ti->ti_src.s_addr, u_long); 130: xchg(ti->ti_dport, ti->ti_sport, u_short); 131: #undef xchg 132: tlen = 0; 133: } 134: ti->ti_next = ti->ti_prev = 0; 135: ti->ti_x1 = 0; 136: ti->ti_len = htons((u_short)(sizeof (struct tcphdr) + tlen)); 137: ti->ti_seq = htonl(seq); 138: ti->ti_ack = htonl(ack); 139: ti->ti_x2 = 0; 140: ti->ti_off = sizeof (struct tcphdr) >> 2; 141: ti->ti_flags = flags; 142: ti->ti_win = htons((u_short)win); 143: ti->ti_urp = 0; 144: ti->ti_sum = in_cksum(m, sizeof (struct tcpiphdr) + tlen); 145: ((struct ip *)ti)->ip_len = sizeof (struct tcpiphdr) + tlen; 146: ((struct ip *)ti)->ip_ttl = TCP_TTL; 147: (void) ip_output(m, (struct mbuf *)0, ro, 0); 148: } 149: 150: /* 151: * Create a new TCP control block, making an 152: * empty reassembly queue and hooking it to the argument 153: * protocol control block. 154: */ 155: struct tcpcb * 156: tcp_newtcpcb(inp) 157: struct inpcb *inp; 158: { 159: struct mbuf *m = m_getclr(M_DONTWAIT, MT_PCB); 160: register struct tcpcb *tp; 161: 162: if (m == NULL) 163: return ((struct tcpcb *)0); 164: tp = mtod(m, struct tcpcb *); 165: tp->seg_next = tp->seg_prev = (struct tcpiphdr *)tp; 166: tp->t_maxseg = TCP_MSS; 167: tp->t_flags = 0; /* sends options! */ 168: tp->t_inpcb = inp; 169: tp->t_srtt = TCPTV_SRTTBASE; 170: tp->snd_cwnd = sbspace(&inp->inp_socket->so_snd); 171: inp->inp_ppcb = (caddr_t)tp; 172: return (tp); 173: } 174: 175: /* 176: * Drop a TCP connection, reporting 177: * the specified error. If connection is synchronized, 178: * then send a RST to peer. 179: */ 180: struct tcpcb * 181: tcp_drop(tp, errno) 182: register struct tcpcb *tp; 183: int errno; 184: { 185: struct socket *so = tp->t_inpcb->inp_socket; 186: 187: if (TCPS_HAVERCVDSYN(tp->t_state)) { 188: tp->t_state = TCPS_CLOSED; 189: (void) tcp_output(tp); 190: } 191: so->so_error = errno; 192: return (tcp_close(tp)); 193: } 194: 195: /* 196: * Close a TCP control block: 197: * discard all space held by the tcp 198: * discard internet protocol block 199: * wake up any sleepers 200: */ 201: struct tcpcb * 202: tcp_close(tp) 203: register struct tcpcb *tp; 204: { 205: register struct tcpiphdr *t; 206: struct inpcb *inp = tp->t_inpcb; 207: struct socket *so = inp->inp_socket; 208: register struct mbuf *m; 209: 210: t = tp->seg_next; 211: while (t != (struct tcpiphdr *)tp) { 212: t = (struct tcpiphdr *)t->ti_next; 213: m = dtom(t->ti_prev); 214: remque(t->ti_prev); 215: m_freem(m); 216: } 217: if (tp->t_template) 218: (void) m_free(dtom(tp->t_template)); 219: if (tp->t_tcpopt) 220: (void) m_free(dtom(tp->t_tcpopt)); 221: (void) m_free(dtom(tp)); 222: inp->inp_ppcb = 0; 223: soisdisconnected(so); 224: in_pcbdetach(inp); 225: return ((struct tcpcb *)0); 226: } 227: 228: tcp_drain() 229: { 230: 231: } 232: 233: tcp_ctlinput(cmd, sa) 234: int cmd; 235: struct sockaddr *sa; 236: { 237: extern u_char inetctlerrmap[]; 238: struct sockaddr_in *sin; 239: int tcp_quench(), in_rtchange(); 240: 241: if ((unsigned)cmd > PRC_NCMDS) 242: return; 243: if (sa->sa_family != AF_INET && sa->sa_family != AF_IMPLINK) 244: return; 245: sin = (struct sockaddr_in *)sa; 246: if (sin->sin_addr.s_addr == INADDR_ANY) 247: return; 248: 249: switch (cmd) { 250: 251: case PRC_QUENCH: 252: in_pcbnotify(&tcb, &sin->sin_addr, 0, tcp_quench); 253: break; 254: 255: case PRC_ROUTEDEAD: 256: case PRC_REDIRECT_NET: 257: case PRC_REDIRECT_HOST: 258: case PRC_REDIRECT_TOSNET: 259: case PRC_REDIRECT_TOSHOST: 260: in_pcbnotify(&tcb, &sin->sin_addr, 0, in_rtchange); 261: break; 262: 263: default: 264: if (inetctlerrmap[cmd] == 0) 265: return; /* XXX */ 266: in_pcbnotify(&tcb, &sin->sin_addr, (int)inetctlerrmap[cmd], 267: (int (*)())0); 268: } 269: } 270: 271: /* 272: * When a source quench is received, close congestion window 273: * to 80% of the outstanding data (but not less than one segment). 274: */ 275: tcp_quench(inp) 276: struct inpcb *inp; 277: { 278: struct tcpcb *tp = intotcpcb(inp); 279: 280: if (tp) 281: tp->snd_cwnd = MAX(8 * (tp->snd_nxt - tp->snd_una) / 10, 282: tp->t_maxseg); 283: }