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