xref: /csrg-svn/sys/netiso/tuba_subr.c (revision 56685)
1 /*
2  * Copyright (c) 1992 Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  *
7  *	@(#)tuba_subr.c	7.6 (Berkeley) 11/05/92
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 struct	isopcb tuba_isopcb;
46 extern int	tuba_table_size;
47 extern int	tcppcbcachemiss, tcppredack, tcppreddat, tcprexmtthresh;
48 extern struct 	inpcb *tcp_last_inpcb;
49 extern struct	tcpiphdr tcp_saveti;
50 /*
51  * Tuba initialization
52  */
53 tuba_init()
54 {
55 #define TUBAHDRSIZE (3 /*LLC*/ + 9 /*CLNP Fixed*/ + 42 /*Addresses*/ \
56 		     + 6 /*CLNP Segment*/ + 20 /*TCP*/)
57 
58 	tuba_isopcb.isop_next = tuba_isopcb.isop_prev = &tuba_isopcb;
59 	tuba_isopcb.isop_faddr = &tuba_isopcb.isop_sfaddr;
60 	tuba_isopcb.isop_laddr = &tuba_isopcb.isop_sladdr;
61 	if (max_protohdr < TUBAHDRSIZE)
62 		max_protohdr = TUBAHDRSIZE;
63 	if (max_linkhdr + TUBAHDRSIZE > MHLEN)
64 		panic("tuba_init");
65 }
66 
67 static void
68 tuba_getaddr(error, sum, siso, index)
69 	int *error;
70 	register u_long *sum;
71 	struct sockaddr_iso *siso;
72 	u_long index;
73 {
74 	register struct tuba_cache *tc;
75 	if (index <= tuba_table_size && (tc = tuba_table[index])) {
76 		if (siso) {
77 			*siso = null_siso;
78 			siso->siso_addr = tc->tc_addr;
79 		}
80 		REDUCE(*sum, *sum + tc->tc_sum_out);
81 	} else
82 		*error = 1;
83 }
84 int tuba_noisy = 1;
85 
86 tuba_output(m, tp)
87 	register struct mbuf *m;
88 	struct tcpcb *tp;
89 {
90 	struct isopcb *isop;
91 	register struct tcpiphdr *n, *h;
92 	struct mbuf *p = m_gethdr(M_DONTWAIT, MT_DATA);
93 	u_long sum = 0, i = 0, k1, k2, k3, k4, k5, lindex, findex, len;
94 
95 	if ((m->m_flags & M_PKTHDR) == 0)
96 		panic("tuba_output");
97 	if (p == 0)
98 		panic("tuba_output 2");
99 	m = m_pullup(m, 40);
100 	if (m == 0) {
101 		printf("heisenberg hit us\n");
102 		(void)m_free(p);
103 		return (ENOBUFS);
104 	}
105 	n = mtod(m, struct tcpiphdr *);
106 	h = mtod(p, struct tcpiphdr *);
107 	lindex = n->ti_src.s_addr;
108 	findex = n->ti_dst.s_addr;
109 	len = m->m_pkthdr.len;
110 	bzero((caddr_t)h, sizeof(*h));
111 	h->ti_pr = ISOPROTO_TCP;
112 	h->ti_dst.s_addr = findex;
113 	h->ti_src.s_addr = lindex;
114 	h->ti_len = htons((u_short)len - 20);
115 	m->m_data += 20;
116 	m->m_len -= 20;
117 	k1 = in_cksum(m, len - 20);
118 	p->m_len = 20;
119 	p->m_next = m;
120 	k2 = in_cksum(p, 20);
121 	k3 = in_cksum(p, len);
122 	m->m_data -= 20;
123 	m->m_len += 20;
124 
125 	if (tuba_noisy) {
126 		printf("old ti_sum is 0x%x\n", n->ti_sum);
127 		printf("in_cksum for old TCP part is 0x%x\n", k1);
128 		printf("in_cksum for ph(idx) is 0x%x\n", k2);
129 		printf("in_cksum for ph + TCP is 0x%x\n", k3);
130 	}
131 	if (tp == 0 || (n = tp->t_template) == 0 ||
132 	    (isop = (struct isopcb *)tp->t_tuba_pcb) == 0) {
133 		isop = &tuba_isopcb;
134 		n = mtod(m, struct tcpiphdr *);
135 		tuba_getaddr(&i, &sum, tuba_isopcb.isop_faddr, findex);
136 		tuba_getaddr(&i, &sum, tuba_isopcb.isop_laddr, lindex);
137 		goto adjust;
138 	}
139 	if (n->ti_sum == 0) {
140 		tuba_getaddr(&i, &sum, (struct sockaddr_iso *)0, findex);
141 		tuba_getaddr(&i, &sum, (struct sockaddr_iso *)0, lindex);
142 		n->ti_sum = sum;
143 		n = mtod(m, struct tcpiphdr *);
144 	adjust:
145 		if (i) {
146 			m_freem(m);
147 			(void)m_free(p);
148 			return (EADDRNOTAVAIL);
149 		}
150 		REDUCE(n->ti_sum, n->ti_sum + (0xffff ^ sum));
151 	}
152 	h->ti_dst.s_addr = tuba_table[findex]->tc_sum_in;
153 	h->ti_src.s_addr = tuba_table[lindex]->tc_sum_in;
154 	m->m_len -= sizeof (struct ip);
155 	m->m_pkthdr.len -= sizeof (struct ip);
156 	m->m_data += sizeof (struct ip);
157 	k1 = in_cksum(m, len - 20);
158 	k2 = in_cksum(p, 20);
159 	k3 = in_cksum(p, len);
160 	REDUCE(k4, h->ti_dst.s_addr + h->ti_src.s_addr + h->ti_len
161 			+ ntohs((u_short)ISOPROTO_TCP) + (0xffff ^ k1));
162 	k4 = 0xffff ^ k4;
163 	if (tuba_noisy) {
164 		printf("new ti_sum is 0x%x\n", n->ti_sum);
165 		printf("adjustment is 0x%x\n", sum);
166 		printf("in_cksum for new TCP part is 0x%x\n", k1);
167 		printf("in_cksum for ph(EIDSUM) is 0x%x\n", k2);
168 		printf("in_cksum for ph + TCP is 0x%x\n", k3);
169 		printf("calculated in the funky way is 0x%x\n", k4);
170 	}
171 	(void)m_free(p);
172 	return (clnp_output(m, isop, m->m_pkthdr.len, 0));
173 }
174 
175 tuba_refcnt(isop, delta)
176 	struct isopcb *isop;
177 {
178 	register struct tuba_cache *tc;
179 	unsigned index, sum;
180 
181 	if (delta != 1)
182 		delta = -1;
183 	if (isop == 0 || isop->isop_faddr == 0 || isop->isop_laddr == 0 ||
184 	    (delta == -1 && isop->isop_tuba_cached == 0) ||
185 	    (delta == 1 && isop->isop_tuba_cached != 0))
186 		return;
187 	isop->isop_tuba_cached = (delta == 1);
188 	if ((index = tuba_lookup(&isop->isop_sfaddr.siso_addr, M_DONTWAIT)) != 0 &&
189 	    (tc = tuba_table[index]) != 0 && (delta == 1 || tc->tc_refcnt > 0))
190 		tc->tc_refcnt += delta;
191 	if ((index = tuba_lookup(&isop->isop_sladdr.siso_addr, M_DONTWAIT)) != 0 &&
192 	    (tc = tuba_table[index]) != 0 && (delta == 1 || tc->tc_refcnt > 0))
193 		tc->tc_refcnt += delta;
194 }
195 
196 tuba_pcbdetach(isop)
197 	struct isopcb *isop;
198 {
199 	if (isop == 0)
200 		return;
201 	tuba_refcnt(isop, -1);
202 	isop->isop_socket = 0;
203 	iso_pcbdetach(isop);
204 }
205 
206 /*
207  * Avoid  in_pcbconnect in faked out tcp_input()
208  */
209 tuba_pcbconnect(inp, nam)
210 	register struct inpcb *inp;
211 	struct mbuf *nam;
212 {
213 	register struct sockaddr_iso *siso = mtod(nam, struct sockaddr_iso *);
214 	struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);
215 	struct tcpcb *tp = intotcpcb(inp);
216 	unsigned index = sin->sin_addr.s_addr;
217 	struct tuba_cache *tc = tuba_table[index];
218 	struct isopcb *isop = (struct isopcb *)tp->t_tuba_pcb;
219 	int error;
220 
221 	inp->inp_faddr.s_addr = index;
222 	inp->inp_fport = sin->sin_port;
223 	*siso = null_siso;
224 	siso->siso_addr = tc->tc_addr;
225 	siso->siso_tlen = sizeof(inp->inp_fport);
226 	bcopy((caddr_t)&inp->inp_fport, TSEL(siso), sizeof(inp->inp_fport));
227 	nam->m_len = sizeof(*siso);
228 	if ((error = iso_pcbconnect(isop, nam)) == 0)
229 		tuba_refcnt(isop, 1);
230 	return (error);
231 }
232 
233 tuba_badcksum() {} /* XXX - to set breakpoints */
234 
235 /*
236  * CALLED FROM:
237  * 	clnp's input routine, indirectly through the protosw.
238  * FUNCTION and ARGUMENTS:
239  * Take a packet (m) from clnp, strip off the clnp header
240  * and do tcp input processing.
241  * No return value.
242  */
243 tuba_tcpinput(m, src, dst, clnp_len, ce_bit)
244 	register struct mbuf *m;
245 	struct sockaddr_iso *src, *dst;
246 	int clnp_len, ce_bit;
247 {
248 	int s = splnet();
249 	unsigned long sum, lindex, findex;
250 	register struct tcpiphdr *ti;
251 	register struct inpcb *inp;
252 	struct mbuf *om;
253 	int len, tlen, off;
254 	register struct tcpcb *tp = 0;
255 	int tiflags;
256 	struct socket *so;
257 	int todrop, acked, ourfinisacked, needoutput = 0;
258 	short ostate;
259 	struct in_addr laddr;
260 	int dropsocket = 0, iss = 0;
261 
262 	if ((m->m_flags & M_PKTHDR) == 0) {
263 		om = m_gethdr(M_DONTWAIT, MT_DATA);
264 		if (om == 0)
265 			goto drop;
266 		om->m_next = m;
267 		for (len = 0; m; m = m->m_next)
268 			len += m->m_len;
269 		m = om;
270 		m->m_pkthdr.len = len;
271 	}
272 	om = 0;
273 	/*
274 	 * Do some housekeeping looking up CLNP addresses.
275 	 * If we are out of space might as well drop the packet now.
276 	 */
277 	tcpstat.tcps_rcvtotal++;
278 	lindex = tuba_lookup(&dst->siso_addr, M_DONTWAIT);
279 	findex = tuba_lookup(&dst->siso_addr, M_DONTWAIT);
280 	if (lindex == 0 || findex == 0)
281 		goto drop;
282 	/*
283 	 * Get CLNP and TCP header together in first mbuf.
284 	 * CLNP gave us an mbuf chain WITH the clnp header pulled up,
285 	 * and the length of the clnp header.
286 	 */
287 	len = clnp_len + sizeof(struct tcphdr);
288 	if (m->m_len < len) {
289 		if ((m = m_pullup(m, len)) == 0) {
290 			tcpstat.tcps_rcvshort++;
291 			return;
292 		}
293 	}
294 	/*
295 	 * Calculate checksum of extended TCP header and data,
296 	 * by adjusting the checksum for missing parts of the header.
297 	 */
298 	m->m_data += clnp_len;
299 	m->m_len -= clnp_len;
300 	tlen = m->m_pkthdr.len -= clnp_len;
301 	m->m_data -= sizeof(struct ip);
302 	m->m_len += sizeof(struct ip);
303 	m->m_pkthdr.len += sizeof(struct ip);
304 	/*
305 	 * The reassembly code assumes it will be overwriting a useless
306 	 * part of the packet, which is why we need to have it point
307 	 * into the packet itself.
308 	 *
309 	 * Check to see if the data is properly alligned
310 	 * so that we can save copying the tcp header.
311 	 * This code knows way too much about the structure of mbufs!
312 	 */
313 	off = ((sizeof (long) - 1) & ((m->m_flags & M_EXT) ?
314 		(m->m_data - m->m_ext.ext_buf) :  (m->m_data - m->m_pktdat)));
315 	if (off) {
316 		struct mbuf *m0 = m_gethdr(M_DONTWAIT, MT_DATA);
317 		if (m0 == 0) {
318 			goto drop;
319 		}
320 		m0->m_data += max_linkhdr;
321 		bcopy(mtod(m, caddr_t) + sizeof(struct ip),
322 		      mtod(m0, caddr_t) + sizeof(struct ip),
323 		      sizeof(struct tcphdr));
324 		m->m_data += sizeof(struct tcpiphdr);
325 		m0->m_next = m;
326 		m0->m_pkthdr = m->m_pkthdr;
327 		m0->m_flags = m->m_flags & M_COPYFLAGS;
328 		m0->m_len = sizeof(struct tcpiphdr);
329 		m = m0;
330 	}
331 	ti = mtod(m, struct tcpiphdr *);
332 	ti->ti_src.s_addr = tuba_table[findex]->tc_sum_in;
333 	ti->ti_dst.s_addr = tuba_table[lindex]->tc_sum_in;
334 	ti->ti_prev = ti->ti_next = 0;
335 	ti->ti_x1 = 0; ti->ti_pr = ISOPROTO_TCP;
336 	ti->ti_len = htons((u_short)tlen);
337 	if (ti->ti_sum = in_cksum(m, m->m_pkthdr.len)) {
338 		tcpstat.tcps_rcvbadsum++;
339 		tuba_badcksum();
340 		goto drop;
341 	}
342 	if (tuba_noisy)
343 		printf("Hurray!\n");
344 	ti->ti_src.s_addr = findex;
345 	ti->ti_dst.s_addr = lindex;
346 	/*
347 	 * Now include the rest of TCP input
348 	 */
349 #define TUBA_INCLUDE
350 #define in_pcbconnect	tuba_pcbconnect
351 
352 #include <netinet/tcp_input.c>
353 }
354