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