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: }

Defined functions

tcp_ctlinput defined in line 233; used 2 times
tcp_drain defined in line 228; used 2 times
tcp_init defined in line 36; used 2 times
tcp_quench defined in line 275; used 2 times

Defined macros

xchg defined in line 128; used 3 times
Last modified: 1986-06-05
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 1446
Valid CSS Valid XHTML 1.0 Strict