|
|
1.1 root 1: /*
2: * Copyright (c) 1982, 1986, 1988, 1990 Regents of the University of California.
3: * All rights reserved.
4: *
5: * Redistribution and use in source and binary forms, with or without
6: * modification, are permitted provided that the following conditions
7: * are met:
8: * 1. Redistributions of source code must retain the above copyright
9: * notice, this list of conditions and the following disclaimer.
10: * 2. Redistributions in binary form must reproduce the above copyright
11: * notice, this list of conditions and the following disclaimer in the
12: * documentation and/or other materials provided with the distribution.
13: * 3. All advertising materials mentioning features or use of this software
14: * must display the following acknowledgement:
15: * This product includes software developed by the University of
16: * California, Berkeley and its contributors.
17: * 4. Neither the name of the University nor the names of its contributors
18: * may be used to endorse or promote products derived from this software
19: * without specific prior written permission.
20: *
21: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31: * SUCH DAMAGE.
32: *
33: * @(#)tcp_subr.c 7.20 (Berkeley) 12/1/90
34: */
35:
36: #include "param.h"
37: #include "systm.h"
38: #include "malloc.h"
39: #include "mbuf.h"
40: #include "socket.h"
41: #include "socketvar.h"
42: #include "protosw.h"
43: #include "errno.h"
44:
45: #include "../net/route.h"
46: #include "../net/if.h"
47:
48: #include "in.h"
49: #include "in_systm.h"
50: #include "ip.h"
51: #include "in_pcb.h"
52: #include "ip_var.h"
53: #include "ip_icmp.h"
54: #include "tcp.h"
55: #include "tcp_fsm.h"
56: #include "tcp_seq.h"
57: #include "tcp_timer.h"
58: #include "tcp_var.h"
59: #include "tcpip.h"
60:
61: /* patchable/settable parameters for tcp */
62: int tcp_ttl = TCP_TTL;
63: int tcp_mssdflt = TCP_MSS;
64: int tcp_rttdflt = TCPTV_SRTTDFLT / PR_SLOWHZ;
65:
66: extern struct inpcb *tcp_last_inpcb;
67:
68: /*
69: * Tcp initialization
70: */
71: tcp_init()
72: {
73:
74: tcp_iss = 1; /* wrong */
75: tcb.inp_next = tcb.inp_prev = &tcb;
76: if (max_protohdr < sizeof(struct tcpiphdr))
77: max_protohdr = sizeof(struct tcpiphdr);
78: if (max_linkhdr + sizeof(struct tcpiphdr) > MHLEN)
79: panic("tcp_init");
80: }
81:
82: /*
83: * Create template to be used to send tcp packets on a connection.
84: * Call after host entry created, allocates an mbuf and fills
85: * in a skeletal tcp/ip header, minimizing the amount of work
86: * necessary when the connection is used.
87: */
88: struct tcpiphdr *
89: tcp_template(tp)
90: struct tcpcb *tp;
91: {
92: register struct inpcb *inp = tp->t_inpcb;
93: register struct mbuf *m;
94: register struct tcpiphdr *n;
95:
96: if ((n = tp->t_template) == 0) {
97: m = m_get(M_DONTWAIT, MT_HEADER);
98: if (m == NULL)
99: return (0);
100: m->m_len = sizeof (struct tcpiphdr);
101: n = mtod(m, struct tcpiphdr *);
102: }
103: n->ti_next = n->ti_prev = 0;
104: n->ti_x1 = 0;
105: n->ti_pr = IPPROTO_TCP;
106: n->ti_len = htons(sizeof (struct tcpiphdr) - sizeof (struct ip));
107: n->ti_src = inp->inp_laddr;
108: n->ti_dst = inp->inp_faddr;
109: n->ti_sport = inp->inp_lport;
110: n->ti_dport = inp->inp_fport;
111: n->ti_seq = 0;
112: n->ti_ack = 0;
113: n->ti_x2 = 0;
114: n->ti_off = 5;
115: n->ti_flags = 0;
116: n->ti_win = 0;
117: n->ti_sum = 0;
118: n->ti_urp = 0;
119: return (n);
120: }
121:
122: /*
123: * Send a single message to the TCP at address specified by
124: * the given TCP/IP header. If m == 0, then we make a copy
125: * of the tcpiphdr at ti and send directly to the addressed host.
126: * This is used to force keep alive messages out using the TCP
127: * template for a connection tp->t_template. If flags are given
128: * then we send a message back to the TCP which originated the
129: * segment ti, and discard the mbuf containing it and any other
130: * attached mbufs.
131: *
132: * In any case the ack and sequence number of the transmitted
133: * segment are as specified by the parameters.
134: */
135: tcp_respond(tp, ti, m, ack, seq, flags)
136: struct tcpcb *tp;
137: register struct tcpiphdr *ti;
138: register struct mbuf *m;
139: tcp_seq ack, seq;
140: int flags;
141: {
142: register int tlen;
143: int win = 0;
144: struct route *ro = 0;
145:
146: if (tp) {
147: win = sbspace(&tp->t_inpcb->inp_socket->so_rcv);
148: ro = &tp->t_inpcb->inp_route;
149: }
150: if (m == 0) {
151: m = m_gethdr(M_DONTWAIT, MT_HEADER);
152: if (m == NULL)
153: return;
154: #ifdef TCP_COMPAT_42
155: tlen = 1;
156: #else
157: tlen = 0;
158: #endif
159: m->m_data += max_linkhdr;
160: *mtod(m, struct tcpiphdr *) = *ti;
161: ti = mtod(m, struct tcpiphdr *);
162: flags = TH_ACK;
163: } else {
164: m_freem(m->m_next);
165: m->m_next = 0;
166: m->m_data = (caddr_t)ti;
167: m->m_len = sizeof (struct tcpiphdr);
168: tlen = 0;
169: #define xchg(a,b,type) { type t; t=a; a=b; b=t; }
170: xchg(ti->ti_dst.s_addr, ti->ti_src.s_addr, u_long);
171: xchg(ti->ti_dport, ti->ti_sport, u_short);
172: #undef xchg
173: }
174: ti->ti_len = htons((u_short)(sizeof (struct tcphdr) + tlen));
175: tlen += sizeof (struct tcpiphdr);
176: m->m_len = tlen;
177: m->m_pkthdr.len = tlen;
178: m->m_pkthdr.rcvif = (struct ifnet *) 0;
179: ti->ti_next = ti->ti_prev = 0;
180: ti->ti_x1 = 0;
181: ti->ti_seq = htonl(seq);
182: ti->ti_ack = htonl(ack);
183: ti->ti_x2 = 0;
184: ti->ti_off = sizeof (struct tcphdr) >> 2;
185: ti->ti_flags = flags;
186: ti->ti_win = htons((u_short)win);
187: ti->ti_urp = 0;
188: ti->ti_sum = in_cksum(m, tlen);
189: ((struct ip *)ti)->ip_len = tlen;
190: ((struct ip *)ti)->ip_ttl = tcp_ttl;
191: (void) ip_output(m, (struct mbuf *)0, ro, 0);
192: }
193:
194: /*
195: * Create a new TCP control block, making an
196: * empty reassembly queue and hooking it to the argument
197: * protocol control block.
198: */
199: struct tcpcb *
200: tcp_newtcpcb(inp)
201: struct inpcb *inp;
202: {
203: struct mbuf *m = m_getclr(M_DONTWAIT, MT_PCB);
204: register struct tcpcb *tp;
205:
206: if (m == NULL)
207: return ((struct tcpcb *)0);
208: tp = mtod(m, struct tcpcb *);
209: tp->seg_next = tp->seg_prev = (struct tcpiphdr *)tp;
210: tp->t_maxseg = tcp_mssdflt;
211:
212: tp->t_flags = 0; /* sends options! */
213: tp->t_inpcb = inp;
214: /*
215: * Init srtt to TCPTV_SRTTBASE (0), so we can tell that we have no
216: * rtt estimate. Set rttvar so that srtt + 2 * rttvar gives
217: * reasonable initial retransmit time.
218: */
219: tp->t_srtt = TCPTV_SRTTBASE;
220: tp->t_rttvar = tcp_rttdflt * PR_SLOWHZ << 2;
221: tp->t_rttmin = TCPTV_MIN;
222: TCPT_RANGESET(tp->t_rxtcur,
223: ((TCPTV_SRTTBASE >> 2) + (TCPTV_SRTTDFLT << 2)) >> 1,
224: TCPTV_MIN, TCPTV_REXMTMAX);
225: tp->snd_cwnd = TCP_MAXWIN;
226: tp->snd_ssthresh = TCP_MAXWIN;
227: inp->inp_ip.ip_ttl = tcp_ttl;
228: inp->inp_ppcb = (caddr_t)tp;
229: return (tp);
230: }
231:
232: /*
233: * Drop a TCP connection, reporting
234: * the specified error. If connection is synchronized,
235: * then send a RST to peer.
236: */
237: struct tcpcb *
238: tcp_drop(tp, errno)
239: register struct tcpcb *tp;
240: int errno;
241: {
242: struct socket *so = tp->t_inpcb->inp_socket;
243:
244: if (TCPS_HAVERCVDSYN(tp->t_state)) {
245: tp->t_state = TCPS_CLOSED;
246: (void) tcp_output(tp);
247: tcpstat.tcps_drops++;
248: } else
249: tcpstat.tcps_conndrops++;
250: if (errno == ETIMEDOUT && tp->t_softerror)
251: errno = tp->t_softerror;
252: so->so_error = errno;
253: return (tcp_close(tp));
254: }
255:
256: /*
257: * Close a TCP control block:
258: * discard all space held by the tcp
259: * discard internet protocol block
260: * wake up any sleepers
261: */
262: struct tcpcb *
263: tcp_close(tp)
264: register struct tcpcb *tp;
265: {
266: register struct tcpiphdr *t;
267: struct inpcb *inp = tp->t_inpcb;
268: struct socket *so = inp->inp_socket;
269: register struct mbuf *m;
270: #ifdef RTV_RTT
271: register struct rtentry *rt;
272:
273: /*
274: * If we sent enough data to get some meaningful characteristics,
275: * save them in the routing entry. 'Enough' is arbitrarily
276: * defined as the sendpipesize (default 4K) * 16. This would
277: * give us 16 rtt samples assuming we only get one sample per
278: * window (the usual case on a long haul net). 16 samples is
279: * enough for the srtt filter to converge to within 5% of the correct
280: * value; fewer samples and we could save a very bogus rtt.
281: *
282: * Don't update the default route's characteristics and don't
283: * update anything that the user "locked".
284: */
285: if (SEQ_LT(tp->iss + so->so_snd.sb_hiwat * 16, tp->snd_max) &&
286: (rt = inp->inp_route.ro_rt) &&
287: ((struct sockaddr_in *)rt_key(rt))->sin_addr.s_addr != INADDR_ANY) {
288: register u_long i;
289:
290: if ((rt->rt_rmx.rmx_locks & RTV_RTT) == 0) {
291: i = tp->t_srtt *
292: (RTM_RTTUNIT / (PR_SLOWHZ * TCP_RTT_SCALE));
293: if (rt->rt_rmx.rmx_rtt && i)
294: /*
295: * filter this update to half the old & half
296: * the new values, converting scale.
297: * See route.h and tcp_var.h for a
298: * description of the scaling constants.
299: */
300: rt->rt_rmx.rmx_rtt =
301: (rt->rt_rmx.rmx_rtt + i) / 2;
302: else
303: rt->rt_rmx.rmx_rtt = i;
304: }
305: if ((rt->rt_rmx.rmx_locks & RTV_RTTVAR) == 0) {
306: i = tp->t_rttvar *
307: (RTM_RTTUNIT / (PR_SLOWHZ * TCP_RTTVAR_SCALE));
308: if (rt->rt_rmx.rmx_rttvar && i)
309: rt->rt_rmx.rmx_rttvar =
310: (rt->rt_rmx.rmx_rttvar + i) / 2;
311: else
312: rt->rt_rmx.rmx_rttvar = i;
313: }
314: /*
315: * update the pipelimit (ssthresh) if it has been updated
316: * already or if a pipesize was specified & the threshhold
317: * got below half the pipesize. I.e., wait for bad news
318: * before we start updating, then update on both good
319: * and bad news.
320: */
321: if ((rt->rt_rmx.rmx_locks & RTV_SSTHRESH) == 0 &&
322: (i = tp->snd_ssthresh) && rt->rt_rmx.rmx_ssthresh ||
323: i < (rt->rt_rmx.rmx_sendpipe / 2)) {
324: /*
325: * convert the limit from user data bytes to
326: * packets then to packet data bytes.
327: */
328: i = (i + tp->t_maxseg / 2) / tp->t_maxseg;
329: if (i < 2)
330: i = 2;
331: i *= (u_long)(tp->t_maxseg + sizeof (struct tcpiphdr));
332: if (rt->rt_rmx.rmx_ssthresh)
333: rt->rt_rmx.rmx_ssthresh =
334: (rt->rt_rmx.rmx_ssthresh + i) / 2;
335: else
336: rt->rt_rmx.rmx_ssthresh = i;
337: }
338: }
339: #endif RTV_RTT
340: /* free the reassembly queue, if any */
341: t = tp->seg_next;
342: while (t != (struct tcpiphdr *)tp) {
343: t = (struct tcpiphdr *)t->ti_next;
344: m = REASS_MBUF((struct tcpiphdr *)t->ti_prev);
345: remque(t->ti_prev);
346: m_freem(m);
347: }
348: if (tp->t_template)
349: (void) m_free(dtom(tp->t_template));
350: (void) m_free(dtom(tp));
351: inp->inp_ppcb = 0;
352: soisdisconnected(so);
353: /* clobber input pcb cache if we're closing the cached connection */
354: if (inp == tcp_last_inpcb)
355: tcp_last_inpcb = &tcb;
356: in_pcbdetach(inp);
357: tcpstat.tcps_closed++;
358: return ((struct tcpcb *)0);
359: }
360:
361: tcp_drain()
362: {
363:
364: }
365:
366: /*
367: * Notify a tcp user of an asynchronous error;
368: * store error as soft error, but wake up user
369: * (for now, won't do anything until can select for soft error).
370: */
371: tcp_notify(inp, error)
372: register struct inpcb *inp;
373: int error;
374: {
375:
376: ((struct tcpcb *)inp->inp_ppcb)->t_softerror = error;
377: wakeup((caddr_t) &inp->inp_socket->so_timeo);
378: sorwakeup(inp->inp_socket);
379: sowwakeup(inp->inp_socket);
380: }
381:
382: tcp_ctlinput(cmd, sa, ip)
383: int cmd;
384: struct sockaddr *sa;
385: register struct ip *ip;
386: {
387: register struct tcphdr *th;
388: extern struct in_addr zeroin_addr;
389: extern u_char inetctlerrmap[];
390: int (*notify)() = tcp_notify, tcp_quench();
391:
392: if (cmd == PRC_QUENCH)
393: notify = tcp_quench;
394: else if ((unsigned)cmd > PRC_NCMDS || inetctlerrmap[cmd] == 0)
395: return;
396: if (ip) {
397: th = (struct tcphdr *)((caddr_t)ip + (ip->ip_hl << 2));
398: in_pcbnotify(&tcb, sa, th->th_dport, ip->ip_src, th->th_sport,
399: cmd, notify);
400: } else
401: in_pcbnotify(&tcb, sa, 0, zeroin_addr, 0, cmd, notify);
402: }
403:
404: /*
405: * When a source quench is received, close congestion window
406: * to one segment. We will gradually open it again as we proceed.
407: */
408: tcp_quench(inp)
409: struct inpcb *inp;
410: {
411: struct tcpcb *tp = intotcpcb(inp);
412:
413: if (tp)
414: tp->snd_cwnd = tp->t_maxseg;
415: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.