|
|
1.1 ! root 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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.