Commit | Line | Data |
---|---|---|
252398a6 | 1 | /* tcp_subr.c 4.10 81/12/20 */ |
ecaa4e6f BJ |
2 | |
3 | #include "../h/param.h" | |
4 | #include "../h/systm.h" | |
5 | #include "../h/mbuf.h" | |
6 | #include "../h/socket.h" | |
7 | #include "../h/socketvar.h" | |
8 | #include "../h/protosw.h" | |
0974b45c BJ |
9 | #include "../net/in.h" |
10 | #include "../net/in_pcb.h" | |
11 | #include "../net/in_systm.h" | |
ecaa4e6f | 12 | #include "../net/if.h" |
ecaa4e6f BJ |
13 | #include "../net/ip.h" |
14 | #include "../net/ip_var.h" | |
15 | #include "../net/tcp.h" | |
ecaa4e6f | 16 | #include "../net/tcp_fsm.h" |
0974b45c BJ |
17 | #include "../net/tcp_seq.h" |
18 | #include "../net/tcp_timer.h" | |
ecaa4e6f | 19 | #include "../net/tcp_var.h" |
0974b45c | 20 | #include "../net/tcpip.h" |
f1b2fa5b | 21 | #include "../errno.h" |
ecaa4e6f BJ |
22 | |
23 | /* | |
24 | * Tcp initialization | |
25 | */ | |
26 | tcp_init() | |
27 | { | |
28 | ||
0974b45c | 29 | COUNT(TCP_INIT); |
ecaa4e6f BJ |
30 | tcp_iss = 1; /* wrong */ |
31 | tcb.inp_next = tcb.inp_prev = &tcb; | |
405c9168 BJ |
32 | tcp_alpha = TCP_ALPHA; |
33 | tcp_beta = TCP_BETA; | |
ecaa4e6f BJ |
34 | } |
35 | ||
36 | /* | |
37 | * Create template to be used to send tcp packets on a connection. | |
38 | * Call after host entry created, allocates an mbuf and fills | |
39 | * in a skeletal tcp/ip header, minimizing the amount of work | |
40 | * necessary when the connection is used. | |
41 | */ | |
42 | struct tcpiphdr * | |
43 | tcp_template(tp) | |
44 | struct tcpcb *tp; | |
45 | { | |
46 | register struct inpcb *inp = tp->t_inpcb; | |
47 | register struct mbuf *m; | |
48 | register struct tcpiphdr *n; | |
49 | ||
50 | COUNT(TCP_TEMPLATE); | |
51 | m = m_get(1); | |
52 | if (m == 0) | |
53 | return (0); | |
54 | m->m_off = MMAXOFF - sizeof (struct tcpiphdr); | |
55 | m->m_len = sizeof (struct tcpiphdr); | |
56 | n = mtod(m, struct tcpiphdr *); | |
57 | n->ti_next = n->ti_prev = 0; | |
58 | n->ti_x1 = 0; | |
59 | n->ti_pr = IPPROTO_TCP; | |
60 | n->ti_len = htons(sizeof (struct tcpiphdr) - sizeof (struct ip)); | |
61 | n->ti_src = inp->inp_laddr; | |
62 | n->ti_dst = inp->inp_faddr; | |
63 | n->ti_sport = inp->inp_lport; | |
64 | n->ti_dport = inp->inp_fport; | |
65 | n->ti_seq = 0; | |
0974b45c | 66 | n->ti_ack = 0; |
ecaa4e6f BJ |
67 | n->ti_x2 = 0; |
68 | n->ti_off = 5; | |
69 | n->ti_flags = 0; | |
70 | n->ti_win = 0; | |
71 | n->ti_sum = 0; | |
72 | n->ti_urp = 0; | |
73 | return (n); | |
74 | } | |
75 | ||
76 | /* | |
405c9168 BJ |
77 | * Send a single message to the TCP at address specified by |
78 | * the given TCP/IP header. If flags==0, then we make a copy | |
79 | * of the tcpiphdr at ti and send directly to the addressed host. | |
80 | * This is used to force keep alive messages out using the TCP | |
81 | * template for a connection tp->t_template. If flags are given | |
82 | * then we send a message back to the TCP which originated the | |
83 | * segment ti, and discard the mbuf containing it and any other | |
84 | * attached mbufs. | |
85 | * | |
86 | * In any case the ack and sequence number of the transmitted | |
87 | * segment are as specified by the parameters. | |
ecaa4e6f | 88 | */ |
0974b45c | 89 | tcp_respond(ti, ack, seq, flags) |
ecaa4e6f | 90 | register struct tcpiphdr *ti; |
0974b45c | 91 | tcp_seq ack, seq; |
ecaa4e6f BJ |
92 | int flags; |
93 | { | |
405c9168 | 94 | struct mbuf *m; |
ecaa4e6f | 95 | |
0974b45c | 96 | COUNT(TCP_RESPOND); |
405c9168 BJ |
97 | if (flags == 0) { |
98 | m = m_get(0); | |
99 | if (m == 0) | |
100 | return; | |
101 | m->m_off = MMINOFF; | |
102 | m->m_len = sizeof (struct tcpiphdr); | |
103 | *mtod(m, struct tcpiphdr *) = *ti; | |
104 | ti = mtod(m, struct tcpiphdr *); | |
105 | flags = TH_ACK; | |
106 | } else { | |
4aed14e3 | 107 | m = dtom(ti); |
405c9168 BJ |
108 | m_freem(m->m_next); |
109 | m->m_next = 0; | |
110 | m->m_len = sizeof (struct tcpiphdr); | |
0974b45c | 111 | #define xchg(a,b,type) { type t; t=a; a=b; b=t; } |
405c9168 BJ |
112 | xchg(ti->ti_dst.s_addr, ti->ti_src.s_addr, u_long); |
113 | xchg(ti->ti_dport, ti->ti_sport, u_short); | |
ecaa4e6f | 114 | #undef xchg |
405c9168 | 115 | } |
0974b45c BJ |
116 | ti->ti_next = ti->ti_prev = 0; |
117 | ti->ti_x1 = 0; | |
4aed14e3 BJ |
118 | ti->ti_len = sizeof (struct tcphdr); |
119 | ti->ti_seq = seq; | |
120 | ti->ti_ack = ack; | |
121 | #if vax | |
122 | ti->ti_len = htons(ti->ti_len); | |
123 | ti->ti_seq = htonl(ti->ti_seq); | |
124 | ti->ti_ack = htonl(ti->ti_ack); | |
125 | #endif | |
0974b45c BJ |
126 | ti->ti_x2 = 0; |
127 | ti->ti_off = sizeof (struct tcphdr) >> 2; | |
ecaa4e6f | 128 | ti->ti_flags = flags; |
0974b45c BJ |
129 | ti->ti_win = ti->ti_urp = 0; |
130 | ti->ti_sum = in_cksum(m, sizeof(struct tcpiphdr)); | |
ecaa4e6f | 131 | ((struct ip *)ti)->ip_len = sizeof(struct tcpiphdr); |
0974b45c | 132 | ((struct ip *)ti)->ip_ttl = TCP_TTL; |
f1b2fa5b | 133 | (void) ip_output(m, (struct mbuf *)0); |
ecaa4e6f | 134 | } |
a6503abf | 135 | |
0974b45c BJ |
136 | /* |
137 | * Create a new TCP control block, making an | |
138 | * empty reassembly queue and hooking it to the argument | |
139 | * protocol control block. | |
140 | */ | |
a6503abf BJ |
141 | struct tcpcb * |
142 | tcp_newtcpcb(inp) | |
143 | struct inpcb *inp; | |
144 | { | |
145 | struct mbuf *m = m_getclr(0); | |
146 | register struct tcpcb *tp; | |
147 | COUNT(TCP_NEWTCPCB); | |
148 | ||
149 | if (m == 0) | |
150 | return (0); | |
151 | tp = mtod(m, struct tcpcb *); | |
a6503abf | 152 | tp->seg_next = tp->seg_prev = (struct tcpiphdr *)tp; |
0974b45c | 153 | tp->t_maxseg = 1024; |
a6503abf BJ |
154 | tp->t_inpcb = inp; |
155 | inp->inp_ppcb = (caddr_t)tp; | |
156 | return (tp); | |
157 | } | |
158 | ||
0974b45c BJ |
159 | /* |
160 | * Drop a TCP connection, reporting | |
161 | * the specified error. If connection is synchronized, | |
162 | * then send a RST to peer. | |
163 | */ | |
a6503abf BJ |
164 | tcp_drop(tp, errno) |
165 | struct tcpcb *tp; | |
166 | int errno; | |
167 | { | |
168 | struct socket *so = tp->t_inpcb->inp_socket; | |
169 | ||
170 | COUNT(TCP_DROP); | |
171 | if (TCPS_HAVERCVDSYN(tp->t_state) && | |
0974b45c | 172 | TCPS_OURFINNOTACKED(tp->t_state)) { |
a6503abf BJ |
173 | tp->t_state = TCPS_CLOSED; |
174 | tcp_output(tp); | |
175 | } | |
176 | so->so_error = errno; | |
a6503abf BJ |
177 | tcp_close(tp); |
178 | } | |
179 | ||
0974b45c BJ |
180 | /* |
181 | * Close a TCP control block: | |
182 | * discard all space held by the tcp | |
183 | * discard internet protocol block | |
184 | * wake up any sleepers | |
185 | */ | |
a6503abf BJ |
186 | tcp_close(tp) |
187 | register struct tcpcb *tp; | |
188 | { | |
189 | register struct tcpiphdr *t; | |
364801f5 BJ |
190 | struct inpcb *inp = tp->t_inpcb; |
191 | struct socket *so = inp->inp_socket; | |
a6503abf BJ |
192 | |
193 | COUNT(TCP_CLOSE); | |
a6503abf BJ |
194 | t = tp->seg_next; |
195 | for (; t != (struct tcpiphdr *)tp; t = (struct tcpiphdr *)t->ti_next) | |
196 | m_freem(dtom(t)); | |
0974b45c | 197 | if (tp->t_template) |
a6503abf | 198 | (void) m_free(dtom(tp->t_template)); |
0974b45c BJ |
199 | if (tp->t_tcpopt) |
200 | (void) m_free(dtom(tp->t_tcpopt)); | |
201 | if (tp->t_ipopt) | |
202 | (void) m_free(dtom(tp->t_ipopt)); | |
a6503abf | 203 | (void) m_free(dtom(tp)); |
364801f5 | 204 | inp->inp_ppcb = 0; |
252398a6 | 205 | in_pcbdetach(inp); |
4aed14e3 | 206 | soisdisconnected(so); |
a6503abf BJ |
207 | } |
208 | ||
a6503abf BJ |
209 | tcp_drain() |
210 | { | |
a6503abf BJ |
211 | |
212 | COUNT(TCP_DRAIN); | |
213 | } | |
214 | ||
215 | tcp_ctlinput(m) | |
216 | struct mbuf *m; | |
217 | { | |
218 | ||
219 | COUNT(TCP_CTLINPUT); | |
220 | m_freem(m); | |
221 | } |