1 /*
2 * Copyright (c) 1992, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * %sccs.include.redist.c%
6 *
7 * @(#)tuba_subr.c 8.1 (Berkeley) 06/10/93
8 */
9
10 #include <sys/param.h>
11 #include <sys/proc.h>
12 #include <sys/systm.h>
13 #include <sys/malloc.h>
14 #include <sys/mbuf.h>
15 #include <sys/socket.h>
16 #include <sys/socketvar.h>
17 #include <sys/protosw.h>
18 #include <sys/errno.h>
19
20 #include <net/route.h>
21 #include <net/if.h>
22
23 #include <netinet/in.h>
24 #include <netinet/in_systm.h>
25 #include <netinet/ip.h>
26 #include <netinet/in_pcb.h>
27 #include <netinet/ip_var.h>
28 #include <netinet/ip_icmp.h>
29 #include <netinet/tcp.h>
30 #include <netinet/tcp_fsm.h>
31 #include <netinet/tcp_seq.h>
32 #include <netinet/tcp_timer.h>
33 #include <netinet/tcp_var.h>
34 #include <netinet/tcpip.h>
35 #include <netinet/tcp_debug.h>
36
37 #include <netiso/argo_debug.h>
38 #include <netiso/iso.h>
39 #include <netiso/clnp.h>
40 #include <netiso/iso_pcb.h>
41 #include <netiso/iso_var.h>
42 #include <netiso/tuba_table.h>
43
44 static struct sockaddr_iso null_siso = { sizeof(null_siso), AF_ISO, };
45 extern int tuba_table_size, tcp_keepidle, tcp_keepintvl, tcp_maxidle;
46 extern int tcppcbcachemiss, tcppredack, tcppreddat, tcprexmtthresh;
47 extern struct tcpiphdr tcp_saveti;
48 struct inpcb tuba_inpcb;
49 struct inpcb *tuba_last_inpcb = &tuba_inpcb;
50 struct isopcb tuba_isopcb;
51 /*
52 * Tuba initialization
53 */
tuba_init()54 tuba_init()
55 {
56 #define TUBAHDRSIZE (3 /*LLC*/ + 9 /*CLNP Fixed*/ + 42 /*Addresses*/ \
57 + 6 /*CLNP Segment*/ + 20 /*TCP*/)
58
59 tuba_inpcb.inp_next = tuba_inpcb.inp_prev = &tuba_inpcb;
60 tuba_isopcb.isop_next = tuba_isopcb.isop_prev = &tuba_isopcb;
61 tuba_isopcb.isop_faddr = &tuba_isopcb.isop_sfaddr;
62 tuba_isopcb.isop_laddr = &tuba_isopcb.isop_sladdr;
63 if (max_protohdr < TUBAHDRSIZE)
64 max_protohdr = TUBAHDRSIZE;
65 if (max_linkhdr + TUBAHDRSIZE > MHLEN)
66 panic("tuba_init");
67 }
68
69 struct addr_arg {
70 int error;
71 int offset;
72 u_long sum;
73 };
74
75 /*
76 * Calculate contribution to fudge factor for TCP checksum,
77 * and coincidentally set pointer for convenience of clnp_output
78 * if we are are responding when there is no isopcb around.
79 */
80 static void
tuba_getaddr(arg,siso,index)81 tuba_getaddr(arg, siso, index)
82 register struct addr_arg *arg;
83 struct sockaddr_iso **siso;
84 u_long index;
85 {
86 register struct tuba_cache *tc;
87 if (index <= tuba_table_size && (tc = tuba_table[index])) {
88 if (siso)
89 *siso = &tc->tc_siso;
90 arg->sum += (arg->offset & 1 ? tc->tc_ssum : tc->tc_sum)
91 + (0xffff ^ index);
92 arg->offset += tc->tc_siso.siso_nlen + 1;
93 } else
94 arg->error = 1;
95 }
96
tuba_output(m,tp)97 tuba_output(m, tp)
98 register struct mbuf *m;
99 struct tcpcb *tp;
100 {
101 register struct tcpiphdr *n;
102 struct isopcb *isop;
103 struct addr_arg arg;
104
105 if (tp == 0 || (n = tp->t_template) == 0 ||
106 (isop = (struct isopcb *)tp->t_tuba_pcb) == 0) {
107 isop = &tuba_isopcb;
108 n = mtod(m, struct tcpiphdr *);
109 arg.error = arg.sum = arg.offset = 0;
110 tuba_getaddr(&arg, &tuba_isopcb.isop_faddr, n->ti_dst.s_addr);
111 tuba_getaddr(&arg, &tuba_isopcb.isop_laddr, n->ti_src.s_addr);
112 REDUCE(arg.sum, arg.sum);
113 goto adjust;
114 }
115 if (n->ti_sum == 0) {
116 arg.error = arg.sum = arg.offset = 0;
117 tuba_getaddr(&arg, (struct sockaddr_iso **)0, n->ti_dst.s_addr);
118 tuba_getaddr(&arg, (struct sockaddr_iso **)0, n->ti_src.s_addr);
119 REDUCE(arg.sum, arg.sum);
120 n->ti_sum = arg.sum;
121 n = mtod(m, struct tcpiphdr *);
122 adjust:
123 if (arg.error) {
124 m_freem(m);
125 return (EADDRNOTAVAIL);
126 }
127 REDUCE(n->ti_sum, n->ti_sum + (0xffff ^ arg.sum));
128 }
129 m->m_len -= sizeof (struct ip);
130 m->m_pkthdr.len -= sizeof (struct ip);
131 m->m_data += sizeof (struct ip);
132 return (clnp_output(m, isop, m->m_pkthdr.len, 0));
133 }
134
135 tuba_refcnt(isop, delta)
136 struct isopcb *isop;
137 {
138 register struct tuba_cache *tc;
139 unsigned index, sum;
140
141 if (delta != 1)
142 delta = -1;
143 if (isop == 0 || isop->isop_faddr == 0 || isop->isop_laddr == 0 ||
144 (delta == -1 && isop->isop_tuba_cached == 0) ||
145 (delta == 1 && isop->isop_tuba_cached != 0))
146 return;
147 isop->isop_tuba_cached = (delta == 1);
148 if ((index = tuba_lookup(isop->isop_faddr, M_DONTWAIT)) != 0 &&
149 (tc = tuba_table[index]) != 0 && (delta == 1 || tc->tc_refcnt > 0))
150 tc->tc_refcnt += delta;
151 if ((index = tuba_lookup(isop->isop_laddr, M_DONTWAIT)) != 0 &&
152 (tc = tuba_table[index]) != 0 && (delta == 1 || tc->tc_refcnt > 0))
153 tc->tc_refcnt += delta;
154 }
155
156 tuba_pcbdetach(isop)
157 struct isopcb *isop;
158 {
159 if (isop == 0)
160 return;
161 tuba_refcnt(isop, -1);
162 isop->isop_socket = 0;
163 iso_pcbdetach(isop);
164 }
165
166 /*
167 * Avoid in_pcbconnect in faked out tcp_input()
168 */
tuba_pcbconnect(inp,nam)169 tuba_pcbconnect(inp, nam)
170 register struct inpcb *inp;
171 struct mbuf *nam;
172 {
173 register struct sockaddr_iso *siso;
174 struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);
175 struct tcpcb *tp = intotcpcb(inp);
176 struct isopcb *isop = (struct isopcb *)tp->t_tuba_pcb;
177 int error;
178
179 /* hardwire iso_pcbbind() here */
180 siso = isop->isop_laddr = &isop->isop_sladdr;
181 *siso = tuba_table[inp->inp_laddr.s_addr]->tc_siso;
182 siso->siso_tlen = sizeof(inp->inp_lport);
183 bcopy((caddr_t)&inp->inp_lport, TSEL(siso), sizeof(inp->inp_lport));
184
185 /* hardwire in_pcbconnect() here without assigning route */
186 inp->inp_fport = sin->sin_port;
187 inp->inp_faddr = sin->sin_addr;
188
189 /* reuse nam argument to call iso_pcbconnect() */
190 nam->m_len = sizeof(*siso);
191 siso = mtod(nam, struct sockaddr_iso *);
192 *siso = tuba_table[inp->inp_faddr.s_addr]->tc_siso;
193 siso->siso_tlen = sizeof(inp->inp_fport);
194 bcopy((caddr_t)&inp->inp_fport, TSEL(siso), sizeof(inp->inp_fport));
195
196 if ((error = iso_pcbconnect(isop, nam)) == 0)
197 tuba_refcnt(isop, 1);
198 return (error);
199 }
200
201 /*
202 * CALLED FROM:
203 * clnp's input routine, indirectly through the protosw.
204 * FUNCTION and ARGUMENTS:
205 * Take a packet (m) from clnp, strip off the clnp header
206 * and do tcp input processing.
207 * No return value.
208 */
tuba_tcpinput(m,src,dst)209 tuba_tcpinput(m, src, dst)
210 register struct mbuf *m;
211 struct sockaddr_iso *src, *dst;
212 {
213 unsigned long sum, lindex, findex;
214 register struct tcpiphdr *ti;
215 register struct inpcb *inp;
216 caddr_t optp = NULL;
217 int optlen;
218 int len, tlen, off;
219 register struct tcpcb *tp = 0;
220 int tiflags;
221 struct socket *so;
222 int todrop, acked, ourfinisacked, needoutput = 0;
223 short ostate;
224 struct in_addr laddr;
225 int dropsocket = 0, iss = 0;
226 u_long tiwin, ts_val, ts_ecr;
227 int ts_present = 0;
228
229 if ((m->m_flags & M_PKTHDR) == 0)
230 panic("tuba_tcpinput");
231 /*
232 * Do some housekeeping looking up CLNP addresses.
233 * If we are out of space might as well drop the packet now.
234 */
235 tcpstat.tcps_rcvtotal++;
236 lindex = tuba_lookup(dst, M_DONTWAIT);
237 findex = tuba_lookup(src, M_DONTWAIT);
238 if (lindex == 0 || findex == 0)
239 goto drop;
240 /*
241 * CLNP gave us an mbuf chain WITH the clnp header pulled up,
242 * but the data pointer pushed past it.
243 */
244 len = m->m_len;
245 tlen = m->m_pkthdr.len;
246 m->m_data -= sizeof(struct ip);
247 m->m_len += sizeof(struct ip);
248 m->m_pkthdr.len += sizeof(struct ip);
249 m->m_flags &= ~(M_MCAST|M_BCAST); /* XXX should do this in clnp_input */
250 /*
251 * The reassembly code assumes it will be overwriting a useless
252 * part of the packet, which is why we need to have it point
253 * into the packet itself.
254 *
255 * Check to see if the data is properly alligned
256 * so that we can save copying the tcp header.
257 * This code knows way too much about the structure of mbufs!
258 */
259 off = ((sizeof (long) - 1) & ((m->m_flags & M_EXT) ?
260 (m->m_data - m->m_ext.ext_buf) : (m->m_data - m->m_pktdat)));
261 if (off || len < sizeof(struct tcphdr)) {
262 struct mbuf *m0 = m;
263
264 MGETHDR(m, M_DONTWAIT, MT_DATA);
265 if (m == 0) {
266 m = m0;
267 goto drop;
268 }
269 m->m_next = m0;
270 m->m_data += max_linkhdr;
271 m->m_pkthdr = m0->m_pkthdr;
272 m->m_flags = m0->m_flags & M_COPYFLAGS;
273 if (len < sizeof(struct tcphdr)) {
274 m->m_len = 0;
275 if ((m = m_pullup(m, sizeof(struct tcpiphdr))) == 0) {
276 tcpstat.tcps_rcvshort++;
277 return;
278 }
279 } else {
280 bcopy(mtod(m0, caddr_t) + sizeof(struct ip),
281 mtod(m, caddr_t) + sizeof(struct ip),
282 sizeof(struct tcphdr));
283 m0->m_len -= sizeof(struct tcpiphdr);
284 m0->m_data += sizeof(struct tcpiphdr);
285 m->m_len = sizeof(struct tcpiphdr);
286 }
287 }
288 /*
289 * Calculate checksum of extended TCP header and data,
290 * replacing what would have been IP addresses by
291 * the IP checksum of the CLNP addresses.
292 */
293 ti = mtod(m, struct tcpiphdr *);
294 ti->ti_dst.s_addr = tuba_table[lindex]->tc_sum;
295 if (dst->siso_nlen & 1)
296 ti->ti_src.s_addr = tuba_table[findex]->tc_sum;
297 else
298 ti->ti_src.s_addr = tuba_table[findex]->tc_ssum;
299 ti->ti_prev = ti->ti_next = 0;
300 ti->ti_x1 = 0; ti->ti_pr = ISOPROTO_TCP;
301 ti->ti_len = htons((u_short)tlen);
302 if (ti->ti_sum = in_cksum(m, m->m_pkthdr.len)) {
303 tcpstat.tcps_rcvbadsum++;
304 goto drop;
305 }
306 ti->ti_src.s_addr = findex;
307 ti->ti_dst.s_addr = lindex;
308 /*
309 * Now include the rest of TCP input
310 */
311 #define TUBA_INCLUDE
312 #define in_pcbconnect tuba_pcbconnect
313 #define tcb tuba_inpcb
314 #define tcp_last_inpcb tuba_last_inpcb
315
316 #include <netinet/tcp_input.c>
317 }
318
319 #define tcp_slowtimo tuba_slowtimo
320 #define tcp_fasttimo tuba_fasttimo
321
322 #include <netinet/tcp_timer.c>
323