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

Defined functions

tcp_close defined in line 224; used 2 times
tcp_ctlinput defined in line 288; never used
tcp_drain defined in line 250; never used
tcp_drop defined in line 201; never used
tcp_init defined in line 43; never used
tcp_newtcpcb defined in line 166; never used
tcp_notify defined in line 277; used 1 times
tcp_quench defined in line 314; used 2 times
tcp_respond defined in line 105; never used
tcp_template defined in line 56; never used

Defined macros

xchg defined in line 139; used 3 times
Last modified: 1995-10-11
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 4501
Valid CSS Valid XHTML 1.0 Strict