xref: /trueos/sys/netipx/spx_usrreq.c (revision b972b67ed72b5687a023c92602aaef64163b2f59)
1 /*-
2  * Copyright (c) 1984, 1985, 1986, 1987, 1993
3  *	The Regents of the University of California.
4  * Copyright (c) 2004-2009 Robert N. M. Watson
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 4. Neither the name of the University nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  *
31  * Copyright (c) 1995, Mike Mitchell
32  * All rights reserved.
33  *
34  * Redistribution and use in source and binary forms, with or without
35  * modification, are permitted provided that the following conditions
36  * are met:
37  * 1. Redistributions of source code must retain the above copyright
38  *    notice, this list of conditions and the following disclaimer.
39  * 2. Redistributions in binary form must reproduce the above copyright
40  *    notice, this list of conditions and the following disclaimer in the
41  *    documentation and/or other materials provided with the distribution.
42  * 3. All advertising materials mentioning features or use of this software
43  *    must display the following acknowledgement:
44  *	This product includes software developed by the University of
45  *	California, Berkeley and its contributors.
46  * 4. Neither the name of the University nor the names of its contributors
47  *    may be used to endorse or promote products derived from this software
48  *    without specific prior written permission.
49  *
50  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
51  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
52  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
53  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
54  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
55  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
56  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
57  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
58  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
59  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
60  * SUCH DAMAGE.
61  *
62  *	@(#)spx_usrreq.h
63  */
64 
65 #include <sys/cdefs.h>
66 __FBSDID("$FreeBSD$");
67 
68 #include <sys/param.h>
69 #include <sys/lock.h>
70 #include <sys/malloc.h>
71 #include <sys/mbuf.h>
72 #include <sys/mutex.h>
73 #include <sys/proc.h>
74 #include <sys/protosw.h>
75 #include <sys/signalvar.h>
76 #include <sys/socket.h>
77 #include <sys/socketvar.h>
78 #include <sys/sx.h>
79 #include <sys/systm.h>
80 
81 #include <net/route.h>
82 #include <netinet/tcp_fsm.h>
83 
84 #include <netipx/ipx.h>
85 #include <netipx/ipx_pcb.h>
86 #include <netipx/ipx_var.h>
87 #include <netipx/spx.h>
88 #include <netipx/spx_debug.h>
89 #include <netipx/spx_timer.h>
90 #include <netipx/spx_var.h>
91 
92 #include <security/mac/mac_framework.h>
93 
94 /*
95  * SPX protocol implementation.
96  */
97 static struct	mtx spx_mtx;			/* Protects only spx_iss. */
98 static u_short 	spx_iss;
99 u_short		spx_newchecks[50];
100 static int	spx_hardnosed;
101 static int	traceallspxs = 0;
102 struct	spx_istat spx_istat;
103 
104 #define	SPX_LOCK_INIT()	mtx_init(&spx_mtx, "spx_mtx", NULL, MTX_DEF)
105 #define	SPX_LOCK()	mtx_lock(&spx_mtx)
106 #define	SPX_UNLOCK()	mtx_unlock(&spx_mtx)
107 
108 static const int spx_backoff[SPX_MAXRXTSHIFT+1] =
109     { 1, 2, 4, 8, 16, 32, 64, 64, 64, 64, 64, 64, 64 };
110 
111 static	void spx_close(struct spxpcb *cb);
112 static	void spx_disconnect(struct spxpcb *cb);
113 static	void spx_drop(struct spxpcb *cb, int errno);
114 static	void spx_setpersist(struct spxpcb *cb);
115 static	void spx_template(struct spxpcb *cb);
116 static	void spx_timers(struct spxpcb *cb, int timer);
117 static	void spx_usrclosed(struct spxpcb *cb);
118 
119 static	void spx_usr_abort(struct socket *so);
120 static	int spx_accept(struct socket *so, struct sockaddr **nam);
121 static	int spx_attach(struct socket *so, int proto, struct thread *td);
122 static	int spx_bind(struct socket *so, struct sockaddr *nam, struct thread *td);
123 static	void spx_usr_close(struct socket *so);
124 static	int spx_connect(struct socket *so, struct sockaddr *nam,
125 			struct thread *td);
126 static	void spx_detach(struct socket *so);
127 static	void spx_pcbdetach(struct ipxpcb *ipxp);
128 static	int spx_usr_disconnect(struct socket *so);
129 static	int spx_listen(struct socket *so, int backlog, struct thread *td);
130 static	int spx_rcvd(struct socket *so, int flags);
131 static	int spx_rcvoob(struct socket *so, struct mbuf *m, int flags);
132 static	int spx_send(struct socket *so, int flags, struct mbuf *m,
133 		     struct sockaddr *addr, struct mbuf *control,
134 		     struct thread *td);
135 static	int spx_shutdown(struct socket *so);
136 static	int spx_sp_attach(struct socket *so, int proto, struct thread *td);
137 
138 struct	pr_usrreqs spx_usrreqs = {
139 	.pru_abort =		spx_usr_abort,
140 	.pru_accept =		spx_accept,
141 	.pru_attach =		spx_attach,
142 	.pru_bind =		spx_bind,
143 	.pru_connect =		spx_connect,
144 	.pru_control =		ipx_control,
145 	.pru_detach =		spx_detach,
146 	.pru_disconnect =	spx_usr_disconnect,
147 	.pru_listen =		spx_listen,
148 	.pru_peeraddr =		ipx_peeraddr,
149 	.pru_rcvd =		spx_rcvd,
150 	.pru_rcvoob =		spx_rcvoob,
151 	.pru_send =		spx_send,
152 	.pru_shutdown =		spx_shutdown,
153 	.pru_sockaddr =		ipx_sockaddr,
154 	.pru_close =		spx_usr_close,
155 };
156 
157 struct	pr_usrreqs spx_usrreq_sps = {
158 	.pru_abort =		spx_usr_abort,
159 	.pru_accept =		spx_accept,
160 	.pru_attach =		spx_sp_attach,
161 	.pru_bind =		spx_bind,
162 	.pru_connect =		spx_connect,
163 	.pru_control =		ipx_control,
164 	.pru_detach =		spx_detach,
165 	.pru_disconnect =	spx_usr_disconnect,
166 	.pru_listen =		spx_listen,
167 	.pru_peeraddr =		ipx_peeraddr,
168 	.pru_rcvd =		spx_rcvd,
169 	.pru_rcvoob =		spx_rcvoob,
170 	.pru_send =		spx_send,
171 	.pru_shutdown =		spx_shutdown,
172 	.pru_sockaddr =		ipx_sockaddr,
173 	.pru_close =		spx_usr_close,
174 };
175 
176 void
spx_init(void)177 spx_init(void)
178 {
179 
180 	SPX_LOCK_INIT();
181 	spx_iss = 1; /* WRONG !! should fish it out of TODR */
182 }
183 
184 void
spx_input(struct mbuf * m,struct ipxpcb * ipxp)185 spx_input(struct mbuf *m, struct ipxpcb *ipxp)
186 {
187 	struct spxpcb *cb;
188 	struct spx *si = mtod(m, struct spx *);
189 	struct socket *so;
190 	struct spx spx_savesi;
191 	int dropsocket = 0;
192 	short ostate = 0;
193 
194 	spxstat.spxs_rcvtotal++;
195 	KASSERT(ipxp != NULL, ("spx_input: ipxpcb == NULL"));
196 
197 	/*
198 	 * spx_input() assumes that the caller will hold both the pcb list
199 	 * lock and also the ipxp lock.  spx_input() will release both before
200 	 * returning, and may in fact trade in the ipxp lock for another pcb
201 	 * lock following sonewconn().
202 	 */
203 	IPX_LIST_LOCK_ASSERT();
204 	IPX_LOCK_ASSERT(ipxp);
205 
206 	cb = ipxtospxpcb(ipxp);
207 	KASSERT(cb != NULL, ("spx_input: cb == NULL"));
208 
209 	if (ipxp->ipxp_flags & IPXP_DROPPED)
210 		goto drop;
211 
212 	if (m->m_len < sizeof(*si)) {
213 		if ((m = m_pullup(m, sizeof(*si))) == NULL) {
214 			IPX_UNLOCK(ipxp);
215 			IPX_LIST_UNLOCK();
216 			spxstat.spxs_rcvshort++;
217 			return;
218 		}
219 		si = mtod(m, struct spx *);
220 	}
221 	si->si_seq = ntohs(si->si_seq);
222 	si->si_ack = ntohs(si->si_ack);
223 	si->si_alo = ntohs(si->si_alo);
224 
225 	so = ipxp->ipxp_socket;
226 	KASSERT(so != NULL, ("spx_input: so == NULL"));
227 
228 #ifdef MAC
229 	if (mac_socket_check_deliver(so, m) != 0)
230 		goto drop;
231 #endif
232 
233 	if (so->so_options & SO_DEBUG || traceallspxs) {
234 		ostate = cb->s_state;
235 		spx_savesi = *si;
236 	}
237 	if (so->so_options & SO_ACCEPTCONN) {
238 		struct spxpcb *ocb = cb;
239 
240 		so = sonewconn(so, 0);
241 		if (so == NULL)
242 			goto drop;
243 
244 		/*
245 		 * This is ugly, but ....
246 		 *
247 		 * Mark socket as temporary until we're committed to keeping
248 		 * it.  The code at ``drop'' and ``dropwithreset'' check the
249 		 * flag dropsocket to see if the temporary socket created
250 		 * here should be discarded.  We mark the socket as
251 		 * discardable until we're committed to it below in
252 		 * TCPS_LISTEN.
253 		 *
254 		 * XXXRW: In the new world order of real kernel parallelism,
255 		 * temporarily allocating the socket when we're "not sure"
256 		 * seems like a bad idea, as we might race to remove it if
257 		 * the listen socket is closed...?
258 		 *
259 		 * We drop the lock of the listen socket ipxp, and acquire
260 		 * the lock of the new socket ippx.
261 		 */
262 		dropsocket++;
263 		IPX_UNLOCK(ipxp);
264 		ipxp = (struct ipxpcb *)so->so_pcb;
265 		IPX_LOCK(ipxp);
266 		ipxp->ipxp_laddr = si->si_dna;
267 		cb = ipxtospxpcb(ipxp);
268 		cb->s_mtu = ocb->s_mtu;		/* preserve sockopts */
269 		cb->s_flags = ocb->s_flags;	/* preserve sockopts */
270 		cb->s_flags2 = ocb->s_flags2;	/* preserve sockopts */
271 		cb->s_state = TCPS_LISTEN;
272 	}
273 	IPX_LOCK_ASSERT(ipxp);
274 
275 	/*
276 	 * Packet received on connection.  Reset idle time and keep-alive
277 	 * timer.
278 	 */
279 	cb->s_idle = 0;
280 	cb->s_timer[SPXT_KEEP] = SPXTV_KEEP;
281 
282 	switch (cb->s_state) {
283 	case TCPS_LISTEN:{
284 		struct sockaddr_ipx *sipx, ssipx;
285 		struct ipx_addr laddr;
286 
287 		/*
288 		 * If somebody here was carying on a conversation and went
289 		 * away, and his pen pal thinks he can still talk, we get the
290 		 * misdirected packet.
291 		 */
292 		if (spx_hardnosed && (si->si_did != 0 || si->si_seq != 0)) {
293 			spx_istat.gonawy++;
294 			goto dropwithreset;
295 		}
296 		sipx = &ssipx;
297 		bzero(sipx, sizeof *sipx);
298 		sipx->sipx_len = sizeof(*sipx);
299 		sipx->sipx_family = AF_IPX;
300 		sipx->sipx_addr = si->si_sna;
301 		laddr = ipxp->ipxp_laddr;
302 		if (ipx_nullhost(laddr))
303 			ipxp->ipxp_laddr = si->si_dna;
304 		if (ipx_pcbconnect(ipxp, (struct sockaddr *)sipx, &thread0)) {
305 			ipxp->ipxp_laddr = laddr;
306 			spx_istat.noconn++;
307 			goto drop;
308 		}
309 		spx_template(cb);
310 		dropsocket = 0;		/* committed to socket */
311 		cb->s_did = si->si_sid;
312 		cb->s_rack = si->si_ack;
313 		cb->s_ralo = si->si_alo;
314 #define THREEWAYSHAKE
315 #ifdef THREEWAYSHAKE
316 		cb->s_state = TCPS_SYN_RECEIVED;
317 		cb->s_force = 1 + SPXT_KEEP;
318 		spxstat.spxs_accepts++;
319 		cb->s_timer[SPXT_KEEP] = SPXTV_KEEP;
320 		}
321 		break;
322 
323 	 case TCPS_SYN_RECEIVED: {
324 		/*
325 		 * This state means that we have heard a response to our
326 		 * acceptance of their connection.  It is probably logically
327 		 * unnecessary in this implementation.
328 		 */
329 		if (si->si_did != cb->s_sid) {
330 			spx_istat.wrncon++;
331 			goto drop;
332 		}
333 #endif
334 		ipxp->ipxp_fport =  si->si_sport;
335 		cb->s_timer[SPXT_REXMT] = 0;
336 		cb->s_timer[SPXT_KEEP] = SPXTV_KEEP;
337 		soisconnected(so);
338 		cb->s_state = TCPS_ESTABLISHED;
339 		spxstat.spxs_accepts++;
340 		}
341 		break;
342 
343 	case TCPS_SYN_SENT:
344 		/*
345 		 * This state means that we have gotten a response to our
346 		 * attempt to establish a connection.  We fill in the data
347 		 * from the other side, telling us which port to respond to,
348 		 * instead of the well-known one we might have sent to in the
349 		 * first place.  We also require that this is a response to
350 		 * our connection id.
351 		 */
352 		if (si->si_did != cb->s_sid) {
353 			spx_istat.notme++;
354 			goto drop;
355 		}
356 		spxstat.spxs_connects++;
357 		cb->s_did = si->si_sid;
358 		cb->s_rack = si->si_ack;
359 		cb->s_ralo = si->si_alo;
360 		cb->s_dport = ipxp->ipxp_fport =  si->si_sport;
361 		cb->s_timer[SPXT_REXMT] = 0;
362 		cb->s_flags |= SF_ACKNOW;
363 		soisconnected(so);
364 		cb->s_state = TCPS_ESTABLISHED;
365 
366 		/*
367 		 * Use roundtrip time of connection request for initial rtt.
368 		 */
369 		if (cb->s_rtt) {
370 			cb->s_srtt = cb->s_rtt << 3;
371 			cb->s_rttvar = cb->s_rtt << 1;
372 			SPXT_RANGESET(cb->s_rxtcur,
373 			    ((cb->s_srtt >> 2) + cb->s_rttvar) >> 1,
374 			    SPXTV_MIN, SPXTV_REXMTMAX);
375 			    cb->s_rtt = 0;
376 		}
377 	}
378 
379 	if (so->so_options & SO_DEBUG || traceallspxs)
380 		spx_trace(SA_INPUT, (u_char)ostate, cb, &spx_savesi, 0);
381 
382 	m->m_len -= sizeof(struct ipx);
383 	m->m_pkthdr.len -= sizeof(struct ipx);
384 	m->m_data += sizeof(struct ipx);
385 
386 	if (spx_reass(cb, m, si))
387 		m_freem(m);
388 	if (cb->s_force || (cb->s_flags & (SF_ACKNOW|SF_WIN|SF_RXT)))
389 		spx_output(cb, NULL);
390 	cb->s_flags &= ~(SF_WIN|SF_RXT);
391 	IPX_UNLOCK(ipxp);
392 	IPX_LIST_UNLOCK();
393 	return;
394 
395 dropwithreset:
396 	IPX_LOCK_ASSERT(ipxp);
397 	if (cb == NULL || (cb->s_ipxpcb->ipxp_socket->so_options & SO_DEBUG ||
398 	    traceallspxs))
399 		spx_trace(SA_DROP, (u_char)ostate, cb, &spx_savesi, 0);
400 	IPX_UNLOCK(ipxp);
401 	if (dropsocket) {
402 		struct socket *head;
403 		ACCEPT_LOCK();
404 		KASSERT((so->so_qstate & SQ_INCOMP) != 0,
405 		    ("spx_input: nascent socket not SQ_INCOMP on soabort()"));
406 		head = so->so_head;
407 		TAILQ_REMOVE(&head->so_incomp, so, so_list);
408 		head->so_incqlen--;
409 		so->so_qstate &= ~SQ_INCOMP;
410 		so->so_head = NULL;
411 		ACCEPT_UNLOCK();
412 		soabort(so);
413 	}
414 	IPX_LIST_UNLOCK();
415 	m_freem(m);
416 	return;
417 
418 drop:
419 	IPX_LOCK_ASSERT(ipxp);
420 	if (cb->s_ipxpcb->ipxp_socket->so_options & SO_DEBUG || traceallspxs)
421 		spx_trace(SA_DROP, (u_char)ostate, cb, &spx_savesi, 0);
422 	IPX_UNLOCK(ipxp);
423 	IPX_LIST_UNLOCK();
424 	m_freem(m);
425 }
426 
427 void
spx_ctlinput(int cmd,struct sockaddr * arg_as_sa,void * dummy)428 spx_ctlinput(int cmd, struct sockaddr *arg_as_sa, void *dummy)
429 {
430 
431 	/* Currently, nothing. */
432 }
433 
434 int
spx_output(struct spxpcb * cb,struct mbuf * m0)435 spx_output(struct spxpcb *cb, struct mbuf *m0)
436 {
437 	struct socket *so = cb->s_ipxpcb->ipxp_socket;
438 	struct mbuf *m = NULL;
439 	struct spx *si = NULL;
440 	struct sockbuf *sb = &so->so_snd;
441 	int len = 0, win, rcv_win;
442 	short span, off, recordp = 0;
443 	u_short alo;
444 	int error = 0, sendalot;
445 #ifdef notdef
446 	int idle;
447 #endif
448 	struct mbuf *mprev;
449 
450 	IPX_LOCK_ASSERT(cb->s_ipxpcb);
451 
452 	if (m0 != NULL) {
453 		int mtu = cb->s_mtu;
454 		int datalen;
455 
456 		/*
457 		 * Make sure that packet isn't too big.
458 		 */
459 		for (m = m0; m != NULL; m = m->m_next) {
460 			mprev = m;
461 			len += m->m_len;
462 			if (m->m_flags & M_EOR)
463 				recordp = 1;
464 		}
465 		datalen = (cb->s_flags & SF_HO) ?
466 				len - sizeof(struct spxhdr) : len;
467 		if (datalen > mtu) {
468 			if (cb->s_flags & SF_PI) {
469 				m_freem(m0);
470 				return (EMSGSIZE);
471 			} else {
472 				int oldEM = cb->s_cc & SPX_EM;
473 
474 				cb->s_cc &= ~SPX_EM;
475 				while (len > mtu) {
476 					m = m_copym(m0, 0, mtu, M_NOWAIT);
477 					if (m == NULL) {
478 					    cb->s_cc |= oldEM;
479 					    m_freem(m0);
480 					    return (ENOBUFS);
481 					}
482 					if (cb->s_flags & SF_NEWCALL) {
483 					    struct mbuf *mm = m;
484 					    spx_newchecks[7]++;
485 					    while (mm != NULL) {
486 						mm->m_flags &= ~M_EOR;
487 						mm = mm->m_next;
488 					    }
489 					}
490 					error = spx_output(cb, m);
491 					if (error) {
492 						cb->s_cc |= oldEM;
493 						m_freem(m0);
494 						return (error);
495 					}
496 					m_adj(m0, mtu);
497 					len -= mtu;
498 				}
499 				cb->s_cc |= oldEM;
500 			}
501 		}
502 
503 		/*
504 		 * Force length even, by adding a "garbage byte" if
505 		 * necessary.
506 		 */
507 		if (len & 1) {
508 			m = mprev;
509 			if (M_TRAILINGSPACE(m) >= 1)
510 				m->m_len++;
511 			else {
512 				struct mbuf *m1 = m_get(M_NOWAIT, MT_DATA);
513 
514 				if (m1 == NULL) {
515 					m_freem(m0);
516 					return (ENOBUFS);
517 				}
518 				m1->m_len = 1;
519 				*(mtod(m1, u_char *)) = 0;
520 				m->m_next = m1;
521 			}
522 		}
523 		m = m_gethdr(M_NOWAIT, MT_DATA);
524 		if (m == NULL) {
525 			m_freem(m0);
526 			return (ENOBUFS);
527 		}
528 
529 		/*
530 		 * Fill in mbuf with extended SP header and addresses and
531 		 * length put into network format.
532 		 */
533 		MH_ALIGN(m, sizeof(struct spx));
534 		m->m_len = sizeof(struct spx);
535 		m->m_next = m0;
536 		si = mtod(m, struct spx *);
537 		si->si_i = cb->s_ipx;
538 		si->si_s = cb->s_shdr;
539 		if ((cb->s_flags & SF_PI) && (cb->s_flags & SF_HO)) {
540 			struct spxhdr *sh;
541 			if (m0->m_len < sizeof(*sh)) {
542 				if((m0 = m_pullup(m0, sizeof(*sh))) == NULL) {
543 					m_free(m);
544 					m_freem(m0);
545 					return (EINVAL);
546 				}
547 				m->m_next = m0;
548 			}
549 			sh = mtod(m0, struct spxhdr *);
550 			si->si_dt = sh->spx_dt;
551 			si->si_cc |= sh->spx_cc & SPX_EM;
552 			m0->m_len -= sizeof(*sh);
553 			m0->m_data += sizeof(*sh);
554 			len -= sizeof(*sh);
555 		}
556 		len += sizeof(*si);
557 		if ((cb->s_flags2 & SF_NEWCALL) && recordp) {
558 			si->si_cc |= SPX_EM;
559 			spx_newchecks[8]++;
560 		}
561 		if (cb->s_oobflags & SF_SOOB) {
562 			/*
563 			 * Per jqj@cornell: Make sure OB packets convey
564 			 * exactly 1 byte.  If the packet is 1 byte or
565 			 * larger, we have already guaranted there to be at
566 			 * least one garbage byte for the checksum, and extra
567 			 * bytes shouldn't hurt!
568 			 */
569 			if (len > sizeof(*si)) {
570 				si->si_cc |= SPX_OB;
571 				len = (1 + sizeof(*si));
572 			}
573 		}
574 		si->si_len = htons((u_short)len);
575 		m->m_pkthdr.len = ((len - 1) | 1) + 1;
576 
577 		/*
578 		 * Queue stuff up for output.
579 		 */
580 		sbappendrecord(sb, m);
581 		cb->s_seq++;
582 	}
583 #ifdef notdef
584 	idle = (cb->s_smax == (cb->s_rack - 1));
585 #endif
586 again:
587 	sendalot = 0;
588 	off = cb->s_snxt - cb->s_rack;
589 	win = min(cb->s_swnd, (cb->s_cwnd / CUNIT));
590 
591 	/*
592 	 * If in persist timeout with window of 0, send a probe.  Otherwise,
593 	 * if window is small but non-zero and timer expired, send what we
594 	 * can and go into transmit state.
595 	 */
596 	if (cb->s_force == 1 + SPXT_PERSIST) {
597 		if (win != 0) {
598 			cb->s_timer[SPXT_PERSIST] = 0;
599 			cb->s_rxtshift = 0;
600 		}
601 	}
602 	span = cb->s_seq - cb->s_rack;
603 	len = min(span, win) - off;
604 
605 	if (len < 0) {
606 		/*
607 		 * Window shrank after we went into it.  If window shrank to
608 		 * 0, cancel pending restransmission and pull s_snxt back to
609 		 * (closed) window.  We will enter persist state below.  If
610 		 * the widndow didn't close completely, just wait for an ACK.
611 		 */
612 		len = 0;
613 		if (win == 0) {
614 			cb->s_timer[SPXT_REXMT] = 0;
615 			cb->s_snxt = cb->s_rack;
616 		}
617 	}
618 	if (len > 1)
619 		sendalot = 1;
620 	rcv_win = sbspace(&so->so_rcv);
621 
622 	/*
623 	 * Send if we owe peer an ACK.
624 	 */
625 	if (cb->s_oobflags & SF_SOOB) {
626 		/*
627 		 * Must transmit this out of band packet.
628 		 */
629 		cb->s_oobflags &= ~ SF_SOOB;
630 		sendalot = 1;
631 		spxstat.spxs_sndurg++;
632 		goto found;
633 	}
634 	if (cb->s_flags & SF_ACKNOW)
635 		goto send;
636 	if (cb->s_state < TCPS_ESTABLISHED)
637 		goto send;
638 
639 	/*
640 	 * Silly window can't happen in spx.  Code from TCP deleted.
641 	 */
642 	if (len)
643 		goto send;
644 
645 	/*
646 	 * Compare available window to amount of window known to peer (as
647 	 * advertised window less next expected input.)  If the difference is
648 	 * at least two packets or at least 35% of the mximum possible
649 	 * window, then want to send a window update to peer.
650 	 */
651 	if (rcv_win > 0) {
652 		u_short delta =  1 + cb->s_alo - cb->s_ack;
653 		int adv = rcv_win - (delta * cb->s_mtu);
654 
655 		if ((so->so_rcv.sb_cc == 0 && adv >= (2 * cb->s_mtu)) ||
656 		    (100 * adv / so->so_rcv.sb_hiwat >= 35)) {
657 			spxstat.spxs_sndwinup++;
658 			cb->s_flags |= SF_ACKNOW;
659 			goto send;
660 		}
661 
662 	}
663 
664 	/*
665 	 * Many comments from tcp_output.c are appropriate here including ...
666 	 * If send window is too small, there is data to transmit, and no
667 	 * retransmit or persist is pending, then go to persist state.  If
668 	 * nothing happens soon, send when timer expires: if window is
669 	 * non-zero, transmit what we can, otherwise send a probe.
670 	 */
671 	if (so->so_snd.sb_cc && cb->s_timer[SPXT_REXMT] == 0 &&
672 	    cb->s_timer[SPXT_PERSIST] == 0) {
673 		cb->s_rxtshift = 0;
674 		spx_setpersist(cb);
675 	}
676 
677 	/*
678 	 * No reason to send a packet, just return.
679 	 */
680 	cb->s_outx = 1;
681 	return (0);
682 
683 send:
684 	/*
685 	 * Find requested packet.
686 	 */
687 	si = NULL;
688 	m = NULL;
689 	if (len > 0) {
690 		cb->s_want = cb->s_snxt;
691 		for (m = sb->sb_mb; m != NULL; m = m->m_nextpkt) {
692 			si = mtod(m, struct spx *);
693 			if (SSEQ_LEQ(cb->s_snxt, si->si_seq))
694 				break;
695 		}
696 	found:
697 		if (si != NULL) {
698 			if (si->si_seq != cb->s_snxt) {
699 				spxstat.spxs_sndvoid++;
700 				si = NULL;
701 				m = NULL;
702 			} else
703 				cb->s_snxt++;
704 		}
705 	}
706 
707 	/*
708 	 * Update window.
709 	 */
710 	if (rcv_win < 0)
711 		rcv_win = 0;
712 	alo = cb->s_ack - 1 + (rcv_win / ((short)cb->s_mtu));
713 	if (SSEQ_LT(alo, cb->s_alo))
714 		alo = cb->s_alo;
715 
716 	if (m != NULL) {
717 		/*
718 		 * Must make a copy of this packet for ipx_output to monkey
719 		 * with.
720 		 */
721 		m = m_copy(m, 0, M_COPYALL);
722 		if (m == NULL)
723 			return (ENOBUFS);
724 		si = mtod(m, struct spx *);
725 		if (SSEQ_LT(si->si_seq, cb->s_smax))
726 			spxstat.spxs_sndrexmitpack++;
727 		else
728 			spxstat.spxs_sndpack++;
729 	} else if (cb->s_force || cb->s_flags & SF_ACKNOW) {
730 		/*
731 		 * Must send an acknowledgement or a probe.
732 		 */
733 		if (cb->s_force)
734 			spxstat.spxs_sndprobe++;
735 		if (cb->s_flags & SF_ACKNOW)
736 			spxstat.spxs_sndacks++;
737 		m = m_gethdr(M_NOWAIT, MT_DATA);
738 		if (m == NULL)
739 			return (ENOBUFS);
740 
741 		/*
742 		 * Fill in mbuf with extended SP header and addresses and
743 		 * length put into network format.
744 		 */
745 		MH_ALIGN(m, sizeof(struct spx));
746 		m->m_len = sizeof(*si);
747 		m->m_pkthdr.len = sizeof(*si);
748 		si = mtod(m, struct spx *);
749 		si->si_i = cb->s_ipx;
750 		si->si_s = cb->s_shdr;
751 		si->si_seq = cb->s_smax + 1;
752 		si->si_len = htons(sizeof(*si));
753 		si->si_cc |= SPX_SP;
754 	} else {
755 		cb->s_outx = 3;
756 		if (so->so_options & SO_DEBUG || traceallspxs)
757 			spx_trace(SA_OUTPUT, cb->s_state, cb, si, 0);
758 		return (0);
759 	}
760 
761 	/*
762 	 * Stuff checksum and output datagram.
763 	 */
764 	if ((si->si_cc & SPX_SP) == 0) {
765 		if (cb->s_force != (1 + SPXT_PERSIST) ||
766 		    cb->s_timer[SPXT_PERSIST] == 0) {
767 			/*
768 			 * If this is a new packet and we are not currently
769 			 * timing anything, time this one.
770 			 */
771 			if (SSEQ_LT(cb->s_smax, si->si_seq)) {
772 				cb->s_smax = si->si_seq;
773 				if (cb->s_rtt == 0) {
774 					spxstat.spxs_segstimed++;
775 					cb->s_rtseq = si->si_seq;
776 					cb->s_rtt = 1;
777 				}
778 			}
779 
780 			/*
781 			 * Set rexmt timer if not currently set, initial
782 			 * value for retransmit timer is smoothed round-trip
783 			 * time + 2 * round-trip time variance.  Initialize
784 			 * shift counter which is used for backoff of
785 			 * retransmit time.
786 			 */
787 			if (cb->s_timer[SPXT_REXMT] == 0 &&
788 			    cb->s_snxt != cb->s_rack) {
789 				cb->s_timer[SPXT_REXMT] = cb->s_rxtcur;
790 				if (cb->s_timer[SPXT_PERSIST]) {
791 					cb->s_timer[SPXT_PERSIST] = 0;
792 					cb->s_rxtshift = 0;
793 				}
794 			}
795 		} else if (SSEQ_LT(cb->s_smax, si->si_seq))
796 			cb->s_smax = si->si_seq;
797 	} else if (cb->s_state < TCPS_ESTABLISHED) {
798 		if (cb->s_rtt == 0)
799 			cb->s_rtt = 1; /* Time initial handshake */
800 		if (cb->s_timer[SPXT_REXMT] == 0)
801 			cb->s_timer[SPXT_REXMT] = cb->s_rxtcur;
802 	}
803 
804 	/*
805 	 * Do not request acks when we ack their data packets or when we do a
806 	 * gratuitous window update.
807 	 */
808 	if (((si->si_cc & SPX_SP) == 0) || cb->s_force)
809 		si->si_cc |= SPX_SA;
810 	si->si_seq = htons(si->si_seq);
811 	si->si_alo = htons(alo);
812 	si->si_ack = htons(cb->s_ack);
813 
814 	if (ipxcksum)
815 		si->si_sum = ipx_cksum(m, ntohs(si->si_len));
816 	else
817 		si->si_sum = 0xffff;
818 
819 	cb->s_outx = 4;
820 	if (so->so_options & SO_DEBUG || traceallspxs)
821 		spx_trace(SA_OUTPUT, cb->s_state, cb, si, 0);
822 
823 #ifdef MAC
824 	mac_socket_create_mbuf(so, m);
825 #endif
826 
827 	if (so->so_options & SO_DONTROUTE)
828 		error = ipx_outputfl(m, NULL, IPX_ROUTETOIF);
829 	else
830 		error = ipx_outputfl(m, &cb->s_ipxpcb->ipxp_route, 0);
831 	if (error)
832 		return (error);
833 	spxstat.spxs_sndtotal++;
834 
835 	/*
836 	 * Data sent (as far as we can tell).  If this advertises a larger
837 	 * window than any other segment, then remember the size of the
838 	 * advertized window.  Any pending ACK has now been sent.
839 	 */
840 	cb->s_force = 0;
841 	cb->s_flags &= ~(SF_ACKNOW|SF_DELACK);
842 	if (SSEQ_GT(alo, cb->s_alo))
843 		cb->s_alo = alo;
844 	if (sendalot)
845 		goto again;
846 	cb->s_outx = 5;
847 	return (0);
848 }
849 
850 static int spx_do_persist_panics = 0;
851 
852 static void
spx_setpersist(struct spxpcb * cb)853 spx_setpersist(struct spxpcb *cb)
854 {
855 	int t = ((cb->s_srtt >> 2) + cb->s_rttvar) >> 1;
856 
857 	IPX_LOCK_ASSERT(cb->s_ipxpcb);
858 
859 	if (cb->s_timer[SPXT_REXMT] && spx_do_persist_panics)
860 		panic("spx_output REXMT");
861 
862 	/*
863 	 * Start/restart persistance timer.
864 	 */
865 	SPXT_RANGESET(cb->s_timer[SPXT_PERSIST],
866 	    t*spx_backoff[cb->s_rxtshift],
867 	    SPXTV_PERSMIN, SPXTV_PERSMAX);
868 	if (cb->s_rxtshift < SPX_MAXRXTSHIFT)
869 		cb->s_rxtshift++;
870 }
871 
872 int
spx_ctloutput(struct socket * so,struct sockopt * sopt)873 spx_ctloutput(struct socket *so, struct sockopt *sopt)
874 {
875 	struct spxhdr spxhdr;
876 	struct ipxpcb *ipxp;
877 	struct spxpcb *cb;
878 	int mask, error;
879 	short soptval;
880 	u_short usoptval;
881 	int optval;
882 
883 	ipxp = sotoipxpcb(so);
884 	KASSERT(ipxp != NULL, ("spx_ctloutput: ipxp == NULL"));
885 
886 	/*
887 	 * This will have to be changed when we do more general stacking of
888 	 * protocols.
889 	 */
890 	if (sopt->sopt_level != IPXPROTO_SPX)
891 		return (ipx_ctloutput(so, sopt));
892 
893 	IPX_LOCK(ipxp);
894 	if (ipxp->ipxp_flags & IPXP_DROPPED) {
895 		IPX_UNLOCK(ipxp);
896 		return (ECONNRESET);
897 	}
898 
899 	IPX_LOCK(ipxp);
900 	cb = ipxtospxpcb(ipxp);
901 	KASSERT(cb != NULL, ("spx_ctloutput: cb == NULL"));
902 
903 	error = 0;
904 	switch (sopt->sopt_dir) {
905 	case SOPT_GET:
906 		switch (sopt->sopt_name) {
907 		case SO_HEADERS_ON_INPUT:
908 			mask = SF_HI;
909 			goto get_flags;
910 
911 		case SO_HEADERS_ON_OUTPUT:
912 			mask = SF_HO;
913 		get_flags:
914 			soptval = cb->s_flags & mask;
915 			IPX_UNLOCK(ipxp);
916 			error = sooptcopyout(sopt, &soptval,
917 			    sizeof(soptval));
918 			break;
919 
920 		case SO_MTU:
921 			usoptval = cb->s_mtu;
922 			IPX_UNLOCK(ipxp);
923 			error = sooptcopyout(sopt, &usoptval,
924 			    sizeof(usoptval));
925 			break;
926 
927 		case SO_LAST_HEADER:
928 			spxhdr = cb->s_rhdr;
929 			IPX_UNLOCK(ipxp);
930 			error = sooptcopyout(sopt, &spxhdr, sizeof(spxhdr));
931 			break;
932 
933 		case SO_DEFAULT_HEADERS:
934 			spxhdr = cb->s_shdr;
935 			IPX_UNLOCK(ipxp);
936 			error = sooptcopyout(sopt, &spxhdr, sizeof(spxhdr));
937 			break;
938 
939 		default:
940 			IPX_UNLOCK(ipxp);
941 			error = ENOPROTOOPT;
942 		}
943 		break;
944 
945 	case SOPT_SET:
946 		/*
947 		 * XXX Why are these shorts on get and ints on set?  That
948 		 * doesn't make any sense...
949 		 *
950 		 * XXXRW: Note, when we re-acquire the ipxp lock, we should
951 		 * re-check that it's not dropped.
952 		 */
953 		IPX_UNLOCK(ipxp);
954 		switch (sopt->sopt_name) {
955 		case SO_HEADERS_ON_INPUT:
956 			mask = SF_HI;
957 			goto set_head;
958 
959 		case SO_HEADERS_ON_OUTPUT:
960 			mask = SF_HO;
961 		set_head:
962 			error = sooptcopyin(sopt, &optval, sizeof optval,
963 					    sizeof optval);
964 			if (error)
965 				break;
966 
967 			IPX_LOCK(ipxp);
968 			if (cb->s_flags & SF_PI) {
969 				if (optval)
970 					cb->s_flags |= mask;
971 				else
972 					cb->s_flags &= ~mask;
973 			} else error = EINVAL;
974 			IPX_UNLOCK(ipxp);
975 			break;
976 
977 		case SO_MTU:
978 			error = sooptcopyin(sopt, &usoptval, sizeof usoptval,
979 					    sizeof usoptval);
980 			if (error)
981 				break;
982 			/* Unlocked write. */
983 			cb->s_mtu = usoptval;
984 			break;
985 
986 #ifdef SF_NEWCALL
987 		case SO_NEWCALL:
988 			error = sooptcopyin(sopt, &optval, sizeof optval,
989 					    sizeof optval);
990 			if (error)
991 				break;
992 			IPX_LOCK(ipxp);
993 			if (optval) {
994 				cb->s_flags2 |= SF_NEWCALL;
995 				spx_newchecks[5]++;
996 			} else {
997 				cb->s_flags2 &= ~SF_NEWCALL;
998 				spx_newchecks[6]++;
999 			}
1000 			IPX_UNLOCK(ipxp);
1001 			break;
1002 #endif
1003 
1004 		case SO_DEFAULT_HEADERS:
1005 			{
1006 				struct spxhdr sp;
1007 
1008 				error = sooptcopyin(sopt, &sp, sizeof sp,
1009 						    sizeof sp);
1010 				if (error)
1011 					break;
1012 				IPX_LOCK(ipxp);
1013 				cb->s_dt = sp.spx_dt;
1014 				cb->s_cc = sp.spx_cc & SPX_EM;
1015 				IPX_UNLOCK(ipxp);
1016 			}
1017 			break;
1018 
1019 		default:
1020 			error = ENOPROTOOPT;
1021 		}
1022 		break;
1023 
1024 	default:
1025 		panic("spx_ctloutput: bad socket option direction");
1026 	}
1027 	return (error);
1028 }
1029 
1030 static void
spx_usr_abort(struct socket * so)1031 spx_usr_abort(struct socket *so)
1032 {
1033 	struct ipxpcb *ipxp;
1034 	struct spxpcb *cb;
1035 
1036 	ipxp = sotoipxpcb(so);
1037 	KASSERT(ipxp != NULL, ("spx_usr_abort: ipxp == NULL"));
1038 
1039 	cb = ipxtospxpcb(ipxp);
1040 	KASSERT(cb != NULL, ("spx_usr_abort: cb == NULL"));
1041 
1042 	IPX_LIST_LOCK();
1043 	IPX_LOCK(ipxp);
1044 	spx_drop(cb, ECONNABORTED);
1045 	IPX_UNLOCK(ipxp);
1046 	IPX_LIST_UNLOCK();
1047 }
1048 
1049 /*
1050  * Accept a connection.  Essentially all the work is done at higher levels;
1051  * just return the address of the peer, storing through addr.
1052  */
1053 static int
spx_accept(struct socket * so,struct sockaddr ** nam)1054 spx_accept(struct socket *so, struct sockaddr **nam)
1055 {
1056 	struct ipxpcb *ipxp;
1057 	struct sockaddr_ipx *sipx, ssipx;
1058 
1059 	ipxp = sotoipxpcb(so);
1060 	KASSERT(ipxp != NULL, ("spx_accept: ipxp == NULL"));
1061 
1062 	sipx = &ssipx;
1063 	bzero(sipx, sizeof *sipx);
1064 	sipx->sipx_len = sizeof *sipx;
1065 	sipx->sipx_family = AF_IPX;
1066 	IPX_LOCK(ipxp);
1067 	sipx->sipx_addr = ipxp->ipxp_faddr;
1068 	IPX_UNLOCK(ipxp);
1069 	*nam = sodupsockaddr((struct sockaddr *)sipx, M_WAITOK);
1070 	return (0);
1071 }
1072 
1073 static int
spx_attach(struct socket * so,int proto,struct thread * td)1074 spx_attach(struct socket *so, int proto, struct thread *td)
1075 {
1076 	struct ipxpcb *ipxp;
1077 	struct spxpcb *cb;
1078 	struct mbuf *mm;
1079 	struct sockbuf *sb;
1080 	int error;
1081 
1082 	ipxp = sotoipxpcb(so);
1083 	KASSERT(ipxp == NULL, ("spx_attach: ipxp != NULL"));
1084 
1085 	if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
1086 		error = soreserve(so, (u_long) 3072, (u_long) 3072);
1087 		if (error)
1088 			return (error);
1089 	}
1090 
1091 	cb = malloc(sizeof *cb, M_PCB, M_NOWAIT | M_ZERO);
1092 	if (cb == NULL)
1093 		return (ENOBUFS);
1094 	mm = m_getclr(M_NOWAIT, MT_DATA);
1095 	if (mm == NULL) {
1096 		free(cb, M_PCB);
1097 		return (ENOBUFS);
1098 	}
1099 
1100 	IPX_LIST_LOCK();
1101 	error = ipx_pcballoc(so, &ipxpcb_list, td);
1102 	if (error) {
1103 		IPX_LIST_UNLOCK();
1104 		m_free(mm);
1105 		free(cb, M_PCB);
1106 		return (error);
1107 	}
1108 	ipxp = sotoipxpcb(so);
1109 	ipxp->ipxp_flags |= IPXP_SPX;
1110 
1111 	cb->s_state = TCPS_LISTEN;
1112 	cb->s_smax = -1;
1113 	cb->s_swl1 = -1;
1114 	spx_reass_init(cb);
1115 	cb->s_ipxpcb = ipxp;
1116 	cb->s_mtu = 576 - sizeof(struct spx);
1117 	sb = &so->so_snd;
1118 	cb->s_cwnd = sbspace(sb) * CUNIT / cb->s_mtu;
1119 	cb->s_ssthresh = cb->s_cwnd;
1120 	cb->s_cwmx = sbspace(sb) * CUNIT / (2 * sizeof(struct spx));
1121 
1122 	/*
1123 	 * Above is recomputed when connecting to account for changed
1124 	 * buffering or mtu's.
1125 	 */
1126 	cb->s_rtt = SPXTV_SRTTBASE;
1127 	cb->s_rttvar = SPXTV_SRTTDFLT << 2;
1128 	SPXT_RANGESET(cb->s_rxtcur,
1129 	    ((SPXTV_SRTTBASE >> 2) + (SPXTV_SRTTDFLT << 2)) >> 1,
1130 	    SPXTV_MIN, SPXTV_REXMTMAX);
1131 	ipxp->ipxp_pcb = (caddr_t)cb;
1132 	IPX_LIST_UNLOCK();
1133 	return (0);
1134 }
1135 
1136 static void
spx_pcbdetach(struct ipxpcb * ipxp)1137 spx_pcbdetach(struct ipxpcb *ipxp)
1138 {
1139 	struct spxpcb *cb;
1140 
1141 	IPX_LOCK_ASSERT(ipxp);
1142 
1143 	cb = ipxtospxpcb(ipxp);
1144 	KASSERT(cb != NULL, ("spx_pcbdetach: cb == NULL"));
1145 
1146 	spx_reass_flush(cb);
1147 	free(cb, M_PCB);
1148 	ipxp->ipxp_pcb = NULL;
1149 }
1150 
1151 static int
spx_bind(struct socket * so,struct sockaddr * nam,struct thread * td)1152 spx_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
1153 {
1154 	struct ipxpcb *ipxp;
1155 	int error;
1156 
1157 	ipxp = sotoipxpcb(so);
1158 	KASSERT(ipxp != NULL, ("spx_bind: ipxp == NULL"));
1159 
1160 	IPX_LIST_LOCK();
1161 	IPX_LOCK(ipxp);
1162 	if (ipxp->ipxp_flags & IPXP_DROPPED) {
1163 		error = EINVAL;
1164 		goto out;
1165 	}
1166 	error = ipx_pcbbind(ipxp, nam, td);
1167 out:
1168 	IPX_UNLOCK(ipxp);
1169 	IPX_LIST_UNLOCK();
1170 	return (error);
1171 }
1172 
1173 static void
spx_usr_close(struct socket * so)1174 spx_usr_close(struct socket *so)
1175 {
1176 	struct ipxpcb *ipxp;
1177 	struct spxpcb *cb;
1178 
1179 	ipxp = sotoipxpcb(so);
1180 	KASSERT(ipxp != NULL, ("spx_usr_close: ipxp == NULL"));
1181 
1182 	cb = ipxtospxpcb(ipxp);
1183 	KASSERT(cb != NULL, ("spx_usr_close: cb == NULL"));
1184 
1185 	IPX_LIST_LOCK();
1186 	IPX_LOCK(ipxp);
1187 	if (cb->s_state > TCPS_LISTEN)
1188 		spx_disconnect(cb);
1189 	else
1190 		spx_close(cb);
1191 	IPX_UNLOCK(ipxp);
1192 	IPX_LIST_UNLOCK();
1193 }
1194 
1195 /*
1196  * Initiate connection to peer.  Enter SYN_SENT state, and mark socket as
1197  * connecting.  Start keep-alive timer, setup prototype header, send initial
1198  * system packet requesting connection.
1199  */
1200 static int
spx_connect(struct socket * so,struct sockaddr * nam,struct thread * td)1201 spx_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
1202 {
1203 	struct ipxpcb *ipxp;
1204 	struct spxpcb *cb;
1205 	int error;
1206 
1207 	ipxp = sotoipxpcb(so);
1208 	KASSERT(ipxp != NULL, ("spx_connect: ipxp == NULL"));
1209 
1210 	cb = ipxtospxpcb(ipxp);
1211 	KASSERT(cb != NULL, ("spx_connect: cb == NULL"));
1212 
1213 	IPX_LIST_LOCK();
1214 	IPX_LOCK(ipxp);
1215 	if (ipxp->ipxp_flags & IPXP_DROPPED) {
1216 		error = EINVAL;
1217 		goto spx_connect_end;
1218 	}
1219 	if (ipxp->ipxp_lport == 0) {
1220 		error = ipx_pcbbind(ipxp, NULL, td);
1221 		if (error)
1222 			goto spx_connect_end;
1223 	}
1224 	error = ipx_pcbconnect(ipxp, nam, td);
1225 	if (error)
1226 		goto spx_connect_end;
1227 	soisconnecting(so);
1228 	spxstat.spxs_connattempt++;
1229 	cb->s_state = TCPS_SYN_SENT;
1230 	cb->s_did = 0;
1231 	spx_template(cb);
1232 	cb->s_timer[SPXT_KEEP] = SPXTV_KEEP;
1233 	cb->s_force = 1 + SPXTV_KEEP;
1234 
1235 	/*
1236 	 * Other party is required to respond to the port I send from, but he
1237 	 * is not required to answer from where I am sending to, so allow
1238 	 * wildcarding.  Original port I am sending to is still saved in
1239 	 * cb->s_dport.
1240 	 */
1241 	ipxp->ipxp_fport = 0;
1242 	error = spx_output(cb, NULL);
1243 spx_connect_end:
1244 	IPX_UNLOCK(ipxp);
1245 	IPX_LIST_UNLOCK();
1246 	return (error);
1247 }
1248 
1249 static void
spx_detach(struct socket * so)1250 spx_detach(struct socket *so)
1251 {
1252 	struct ipxpcb *ipxp;
1253 	struct spxpcb *cb;
1254 
1255 	/*
1256 	 * XXXRW: Should assert appropriately detached.
1257 	 */
1258 	ipxp = sotoipxpcb(so);
1259 	KASSERT(ipxp != NULL, ("spx_detach: ipxp == NULL"));
1260 
1261 	cb = ipxtospxpcb(ipxp);
1262 	KASSERT(cb != NULL, ("spx_detach: cb == NULL"));
1263 
1264 	IPX_LIST_LOCK();
1265 	IPX_LOCK(ipxp);
1266 	spx_pcbdetach(ipxp);
1267 	ipx_pcbdetach(ipxp);
1268 	ipx_pcbfree(ipxp);
1269 	IPX_LIST_UNLOCK();
1270 }
1271 
1272 /*
1273  * We may decide later to implement connection closing handshaking at the spx
1274  * level optionally.  Here is the hook to do it:
1275  */
1276 static int
spx_usr_disconnect(struct socket * so)1277 spx_usr_disconnect(struct socket *so)
1278 {
1279 	struct ipxpcb *ipxp;
1280 	struct spxpcb *cb;
1281 	int error;
1282 
1283 	ipxp = sotoipxpcb(so);
1284 	KASSERT(ipxp != NULL, ("spx_usr_disconnect: ipxp == NULL"));
1285 
1286 	cb = ipxtospxpcb(ipxp);
1287 	KASSERT(cb != NULL, ("spx_usr_disconnect: cb == NULL"));
1288 
1289 	IPX_LIST_LOCK();
1290 	IPX_LOCK(ipxp);
1291 	if (ipxp->ipxp_flags & IPXP_DROPPED) {
1292 		error = EINVAL;
1293 		goto out;
1294 	}
1295 	spx_disconnect(cb);
1296 	error = 0;
1297 out:
1298 	IPX_UNLOCK(ipxp);
1299 	IPX_LIST_UNLOCK();
1300 	return (error);
1301 }
1302 
1303 static int
spx_listen(struct socket * so,int backlog,struct thread * td)1304 spx_listen(struct socket *so, int backlog, struct thread *td)
1305 {
1306 	int error;
1307 	struct ipxpcb *ipxp;
1308 	struct spxpcb *cb;
1309 
1310 	error = 0;
1311 	ipxp = sotoipxpcb(so);
1312 	KASSERT(ipxp != NULL, ("spx_listen: ipxp == NULL"));
1313 
1314 	cb = ipxtospxpcb(ipxp);
1315 	KASSERT(cb != NULL, ("spx_listen: cb == NULL"));
1316 
1317 	IPX_LIST_LOCK();
1318 	IPX_LOCK(ipxp);
1319 	if (ipxp->ipxp_flags & IPXP_DROPPED) {
1320 		error = EINVAL;
1321 		goto out;
1322 	}
1323 	SOCK_LOCK(so);
1324 	error = solisten_proto_check(so);
1325 	if (error == 0 && ipxp->ipxp_lport == 0)
1326 		error = ipx_pcbbind(ipxp, NULL, td);
1327 	if (error == 0) {
1328 		cb->s_state = TCPS_LISTEN;
1329 		solisten_proto(so, backlog);
1330 	}
1331 	SOCK_UNLOCK(so);
1332 out:
1333 	IPX_UNLOCK(ipxp);
1334 	IPX_LIST_UNLOCK();
1335 	return (error);
1336 }
1337 
1338 /*
1339  * After a receive, possibly send acknowledgment updating allocation.
1340  */
1341 static int
spx_rcvd(struct socket * so,int flags)1342 spx_rcvd(struct socket *so, int flags)
1343 {
1344 	struct ipxpcb *ipxp;
1345 	struct spxpcb *cb;
1346 	int error;
1347 
1348 	ipxp = sotoipxpcb(so);
1349 	KASSERT(ipxp != NULL, ("spx_rcvd: ipxp == NULL"));
1350 
1351 	cb = ipxtospxpcb(ipxp);
1352 	KASSERT(cb != NULL, ("spx_rcvd: cb == NULL"));
1353 
1354 	IPX_LOCK(ipxp);
1355 	if (ipxp->ipxp_flags & IPXP_DROPPED) {
1356 		error = EINVAL;
1357 		goto out;
1358 	}
1359 	cb->s_flags |= SF_RVD;
1360 	spx_output(cb, NULL);
1361 	cb->s_flags &= ~SF_RVD;
1362 	error = 0;
1363 out:
1364 	IPX_UNLOCK(ipxp);
1365 	return (error);
1366 }
1367 
1368 static int
spx_rcvoob(struct socket * so,struct mbuf * m,int flags)1369 spx_rcvoob(struct socket *so, struct mbuf *m, int flags)
1370 {
1371 	struct ipxpcb *ipxp;
1372 	struct spxpcb *cb;
1373 	int error;
1374 
1375 	ipxp = sotoipxpcb(so);
1376 	KASSERT(ipxp != NULL, ("spx_rcvoob: ipxp == NULL"));
1377 
1378 	cb = ipxtospxpcb(ipxp);
1379 	KASSERT(cb != NULL, ("spx_rcvoob: cb == NULL"));
1380 
1381 	IPX_LOCK(ipxp);
1382 	if (ipxp->ipxp_flags & IPXP_DROPPED) {
1383 		error = EINVAL;
1384 		goto out;
1385 	}
1386 	SOCKBUF_LOCK(&so->so_rcv);
1387 	if ((cb->s_oobflags & SF_IOOB) || so->so_oobmark ||
1388 	    (so->so_rcv.sb_state & SBS_RCVATMARK)) {
1389 		SOCKBUF_UNLOCK(&so->so_rcv);
1390 		m->m_len = 1;
1391 		*mtod(m, caddr_t) = cb->s_iobc;
1392 		error = 0;
1393 		goto out;
1394 	}
1395 	SOCKBUF_UNLOCK(&so->so_rcv);
1396 	error = EINVAL;
1397 out:
1398 	IPX_UNLOCK(ipxp);
1399 	return (error);
1400 }
1401 
1402 static int
spx_send(struct socket * so,int flags,struct mbuf * m,struct sockaddr * addr,struct mbuf * controlp,struct thread * td)1403 spx_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
1404     struct mbuf *controlp, struct thread *td)
1405 {
1406 	struct ipxpcb *ipxp;
1407 	struct spxpcb *cb;
1408 	int error;
1409 
1410 	ipxp = sotoipxpcb(so);
1411 	KASSERT(ipxp != NULL, ("spx_send: ipxp == NULL"));
1412 
1413 	cb = ipxtospxpcb(ipxp);
1414 	KASSERT(cb != NULL, ("spx_send: cb == NULL"));
1415 
1416 	error = 0;
1417 	IPX_LOCK(ipxp);
1418 	if (ipxp->ipxp_flags & IPXP_DROPPED) {
1419 		error = ECONNRESET;
1420 		goto spx_send_end;
1421 	}
1422 	if (flags & PRUS_OOB) {
1423 		if (sbspace(&so->so_snd) < -512) {
1424 			error = ENOBUFS;
1425 			goto spx_send_end;
1426 		}
1427 		cb->s_oobflags |= SF_SOOB;
1428 	}
1429 	if (controlp != NULL) {
1430 		u_short *p = mtod(controlp, u_short *);
1431 		spx_newchecks[2]++;
1432 		if ((p[0] == 5) && (p[1] == 1)) { /* XXXX, for testing */
1433 			cb->s_shdr.spx_dt = *(u_char *)(&p[2]);
1434 			spx_newchecks[3]++;
1435 		}
1436 		m_freem(controlp);
1437 	}
1438 	controlp = NULL;
1439 	error = spx_output(cb, m);
1440 	m = NULL;
1441 spx_send_end:
1442 	IPX_UNLOCK(ipxp);
1443 	if (controlp != NULL)
1444 		m_freem(controlp);
1445 	if (m != NULL)
1446 		m_freem(m);
1447 	return (error);
1448 }
1449 
1450 static int
spx_shutdown(struct socket * so)1451 spx_shutdown(struct socket *so)
1452 {
1453 	struct ipxpcb *ipxp;
1454 	struct spxpcb *cb;
1455 	int error;
1456 
1457 	ipxp = sotoipxpcb(so);
1458 	KASSERT(ipxp != NULL, ("spx_shutdown: ipxp == NULL"));
1459 
1460 	cb = ipxtospxpcb(ipxp);
1461 	KASSERT(cb != NULL, ("spx_shutdown: cb == NULL"));
1462 
1463 	socantsendmore(so);
1464 	IPX_LIST_LOCK();
1465 	IPX_LOCK(ipxp);
1466 	if (ipxp->ipxp_flags & IPXP_DROPPED) {
1467 		error = EINVAL;
1468 		goto out;
1469 	}
1470 	spx_usrclosed(cb);
1471 	error = 0;
1472 out:
1473 	IPX_UNLOCK(ipxp);
1474 	IPX_LIST_UNLOCK();
1475 	return (error);
1476 }
1477 
1478 static int
spx_sp_attach(struct socket * so,int proto,struct thread * td)1479 spx_sp_attach(struct socket *so, int proto, struct thread *td)
1480 {
1481 	struct ipxpcb *ipxp;
1482 	struct spxpcb *cb;
1483 	int error;
1484 
1485 	KASSERT(so->so_pcb == NULL, ("spx_sp_attach: so_pcb != NULL"));
1486 
1487 	error = spx_attach(so, proto, td);
1488 	if (error)
1489 		return (error);
1490 
1491 	ipxp = sotoipxpcb(so);
1492 	KASSERT(ipxp != NULL, ("spx_sp_attach: ipxp == NULL"));
1493 
1494 	cb = ipxtospxpcb(ipxp);
1495 	KASSERT(cb != NULL, ("spx_sp_attach: cb == NULL"));
1496 
1497 	IPX_LOCK(ipxp);
1498 	cb->s_flags |= (SF_HI | SF_HO | SF_PI);
1499 	IPX_UNLOCK(ipxp);
1500 	return (0);
1501 }
1502 
1503 /*
1504  * Create template to be used to send spx packets on a connection.  Called
1505  * after host entry created, fills in a skeletal spx header (choosing
1506  * connection id), minimizing the amount of work necessary when the
1507  * connection is used.
1508  */
1509 static void
spx_template(struct spxpcb * cb)1510 spx_template(struct spxpcb *cb)
1511 {
1512 	struct ipxpcb *ipxp = cb->s_ipxpcb;
1513 	struct sockbuf *sb = &(ipxp->ipxp_socket->so_snd);
1514 
1515 	IPX_LOCK_ASSERT(ipxp);
1516 
1517 	cb->s_ipx.ipx_pt = IPXPROTO_SPX;
1518 	cb->s_ipx.ipx_sna = ipxp->ipxp_laddr;
1519 	cb->s_ipx.ipx_dna = ipxp->ipxp_faddr;
1520 	SPX_LOCK();
1521 	cb->s_sid = htons(spx_iss);
1522 	spx_iss += SPX_ISSINCR/2;
1523 	SPX_UNLOCK();
1524 	cb->s_alo = 1;
1525 	cb->s_cwnd = (sbspace(sb) * CUNIT) / cb->s_mtu;
1526 
1527 	/*
1528 	 * Try to expand fast to full complement of large packets.
1529 	 */
1530 	cb->s_ssthresh = cb->s_cwnd;
1531 	cb->s_cwmx = (sbspace(sb) * CUNIT) / (2 * sizeof(struct spx));
1532 
1533 	/*
1534 	 * But allow for lots of little packets as well.
1535 	 */
1536 	cb->s_cwmx = max(cb->s_cwmx, cb->s_cwnd);
1537 }
1538 
1539 /*
1540  * Close a SPIP control block.  Wake up any sleepers.  We used to free any
1541  * queued packets, but now we defer that until the pcb is discarded.
1542  */
1543 void
spx_close(struct spxpcb * cb)1544 spx_close(struct spxpcb *cb)
1545 {
1546 	struct ipxpcb *ipxp = cb->s_ipxpcb;
1547 	struct socket *so = ipxp->ipxp_socket;
1548 
1549 	KASSERT(ipxp != NULL, ("spx_close: ipxp == NULL"));
1550 	IPX_LIST_LOCK_ASSERT();
1551 	IPX_LOCK_ASSERT(ipxp);
1552 
1553 	ipxp->ipxp_flags |= IPXP_DROPPED;
1554 	soisdisconnected(so);
1555 	spxstat.spxs_closed++;
1556 }
1557 
1558 /*
1559  * Someday we may do level 3 handshaking to close a connection or send a
1560  * xerox style error.  For now, just close.  cb will always be invalid after
1561  * this call.
1562  */
1563 static void
spx_usrclosed(struct spxpcb * cb)1564 spx_usrclosed(struct spxpcb *cb)
1565 {
1566 
1567 	IPX_LIST_LOCK_ASSERT();
1568 	IPX_LOCK_ASSERT(cb->s_ipxpcb);
1569 
1570 	spx_close(cb);
1571 }
1572 
1573 /*
1574  * cb will always be invalid after this call.
1575  */
1576 static void
spx_disconnect(struct spxpcb * cb)1577 spx_disconnect(struct spxpcb *cb)
1578 {
1579 
1580 	IPX_LIST_LOCK_ASSERT();
1581 	IPX_LOCK_ASSERT(cb->s_ipxpcb);
1582 
1583 	spx_close(cb);
1584 }
1585 
1586 /*
1587  * Drop connection, reporting the specified error.  cb will always be invalid
1588  * after this call.
1589  */
1590 static void
spx_drop(struct spxpcb * cb,int errno)1591 spx_drop(struct spxpcb *cb, int errno)
1592 {
1593 	struct socket *so = cb->s_ipxpcb->ipxp_socket;
1594 
1595 	IPX_LIST_LOCK_ASSERT();
1596 	IPX_LOCK_ASSERT(cb->s_ipxpcb);
1597 
1598 	/*
1599 	 * Someday, in the xerox world we will generate error protocol
1600 	 * packets announcing that the socket has gone away.
1601 	 */
1602 	if (TCPS_HAVERCVDSYN(cb->s_state)) {
1603 		spxstat.spxs_drops++;
1604 		cb->s_state = TCPS_CLOSED;
1605 		/*tcp_output(cb);*/
1606 	} else
1607 		spxstat.spxs_conndrops++;
1608 	so->so_error = errno;
1609 	spx_close(cb);
1610 }
1611 
1612 /*
1613  * Fast timeout routine for processing delayed acks.
1614  */
1615 void
spx_fasttimo(void)1616 spx_fasttimo(void)
1617 {
1618 	struct ipxpcb *ipxp;
1619 	struct spxpcb *cb;
1620 
1621 	IPX_LIST_LOCK();
1622 	LIST_FOREACH(ipxp, &ipxpcb_list, ipxp_list) {
1623 		IPX_LOCK(ipxp);
1624 		if (!(ipxp->ipxp_flags & IPXP_SPX) ||
1625 		    (ipxp->ipxp_flags & IPXP_DROPPED)) {
1626 			IPX_UNLOCK(ipxp);
1627 			continue;
1628 		}
1629 		cb = ipxtospxpcb(ipxp);
1630 		if (cb->s_flags & SF_DELACK) {
1631 			cb->s_flags &= ~SF_DELACK;
1632 			cb->s_flags |= SF_ACKNOW;
1633 			spxstat.spxs_delack++;
1634 			spx_output(cb, NULL);
1635 		}
1636 		IPX_UNLOCK(ipxp);
1637 	}
1638 	IPX_LIST_UNLOCK();
1639 }
1640 
1641 /*
1642  * spx protocol timeout routine called every 500 ms.  Updates the timers in
1643  * all active pcb's and causes finite state machine actions if timers expire.
1644  */
1645 void
spx_slowtimo(void)1646 spx_slowtimo(void)
1647 {
1648 	struct ipxpcb *ipxp;
1649 	struct spxpcb *cb;
1650 	int i;
1651 
1652 	/*
1653 	 * Search through tcb's and update active timers.  Once, timers could
1654 	 * free ipxp's, but now we do that only when detaching a socket.
1655 	 */
1656 	IPX_LIST_LOCK();
1657 	LIST_FOREACH(ipxp, &ipxpcb_list, ipxp_list) {
1658 		IPX_LOCK(ipxp);
1659 		if (!(ipxp->ipxp_flags & IPXP_SPX) ||
1660 		    (ipxp->ipxp_flags & IPXP_DROPPED)) {
1661 			IPX_UNLOCK(ipxp);
1662 			continue;
1663 		}
1664 
1665 		cb = (struct spxpcb *)ipxp->ipxp_pcb;
1666 		KASSERT(cb != NULL, ("spx_slowtimo: cb == NULL"));
1667 		for (i = 0; i < SPXT_NTIMERS; i++) {
1668 			if (cb->s_timer[i] && --cb->s_timer[i] == 0) {
1669 				spx_timers(cb, i);
1670 				if (ipxp->ipxp_flags & IPXP_DROPPED)
1671 					break;
1672 			}
1673 		}
1674 		if (!(ipxp->ipxp_flags & IPXP_DROPPED)) {
1675 			cb->s_idle++;
1676 			if (cb->s_rtt)
1677 				cb->s_rtt++;
1678 		}
1679 		IPX_UNLOCK(ipxp);
1680 	}
1681 	IPX_LIST_UNLOCK();
1682 	SPX_LOCK();
1683 	spx_iss += SPX_ISSINCR/PR_SLOWHZ;		/* increment iss */
1684 	SPX_UNLOCK();
1685 }
1686 
1687 /*
1688  * SPX timer processing.
1689  */
1690 static void
spx_timers(struct spxpcb * cb,int timer)1691 spx_timers(struct spxpcb *cb, int timer)
1692 {
1693 	long rexmt;
1694 	int win;
1695 
1696 	IPX_LIST_LOCK_ASSERT();
1697 	IPX_LOCK_ASSERT(cb->s_ipxpcb);
1698 
1699 	cb->s_force = 1 + timer;
1700 	switch (timer) {
1701 	case SPXT_2MSL:
1702 		/*
1703 		 * 2 MSL timeout in shutdown went off.  TCP deletes
1704 		 * connection control block.
1705 		 */
1706 		printf("spx: SPXT_2MSL went off for no reason\n");
1707 		cb->s_timer[timer] = 0;
1708 		break;
1709 
1710 	case SPXT_REXMT:
1711 		/*
1712 		 * Retransmission timer went off.  Message has not been acked
1713 		 * within retransmit interval.  Back off to a longer
1714 		 * retransmit interval and retransmit one packet.
1715 		 */
1716 		if (++cb->s_rxtshift > SPX_MAXRXTSHIFT) {
1717 			cb->s_rxtshift = SPX_MAXRXTSHIFT;
1718 			spxstat.spxs_timeoutdrop++;
1719 			spx_drop(cb, ETIMEDOUT);
1720 			break;
1721 		}
1722 		spxstat.spxs_rexmttimeo++;
1723 		rexmt = ((cb->s_srtt >> 2) + cb->s_rttvar) >> 1;
1724 		rexmt *= spx_backoff[cb->s_rxtshift];
1725 		SPXT_RANGESET(cb->s_rxtcur, rexmt, SPXTV_MIN, SPXTV_REXMTMAX);
1726 		cb->s_timer[SPXT_REXMT] = cb->s_rxtcur;
1727 
1728 		/*
1729 		 * If we have backed off fairly far, our srtt estimate is
1730 		 * probably bogus.  Clobber it so we'll take the next rtt
1731 		 * measurement as our srtt; move the current srtt into rttvar
1732 		 * to keep the current retransmit times until then.
1733 		 */
1734 		if (cb->s_rxtshift > SPX_MAXRXTSHIFT / 4 ) {
1735 			cb->s_rttvar += (cb->s_srtt >> 2);
1736 			cb->s_srtt = 0;
1737 		}
1738 		cb->s_snxt = cb->s_rack;
1739 
1740 		/*
1741 		 * If timing a packet, stop the timer.
1742 		 */
1743 		cb->s_rtt = 0;
1744 
1745 		/*
1746 		 * See very long discussion in tcp_timer.c about congestion
1747 		 * window and sstrhesh.
1748 		 */
1749 		win = min(cb->s_swnd, (cb->s_cwnd/CUNIT)) / 2;
1750 		if (win < 2)
1751 			win = 2;
1752 		cb->s_cwnd = CUNIT;
1753 		cb->s_ssthresh = win * CUNIT;
1754 		spx_output(cb, NULL);
1755 		break;
1756 
1757 	case SPXT_PERSIST:
1758 		/*
1759 		 * Persistance timer into zero window.  Force a probe to be
1760 		 * sent.
1761 		 */
1762 		spxstat.spxs_persisttimeo++;
1763 		spx_setpersist(cb);
1764 		spx_output(cb, NULL);
1765 		break;
1766 
1767 	case SPXT_KEEP:
1768 		/*
1769 		 * Keep-alive timer went off; send something or drop
1770 		 * connection if idle for too long.
1771 		 */
1772 		spxstat.spxs_keeptimeo++;
1773 		if (cb->s_state < TCPS_ESTABLISHED)
1774 			goto dropit;
1775 		if (cb->s_ipxpcb->ipxp_socket->so_options & SO_KEEPALIVE) {
1776 		    	if (cb->s_idle >= SPXTV_MAXIDLE)
1777 				goto dropit;
1778 			spxstat.spxs_keepprobe++;
1779 			spx_output(cb, NULL);
1780 		} else
1781 			cb->s_idle = 0;
1782 		cb->s_timer[SPXT_KEEP] = SPXTV_KEEP;
1783 		break;
1784 
1785 	dropit:
1786 		spxstat.spxs_keepdrops++;
1787 		spx_drop(cb, ETIMEDOUT);
1788 		break;
1789 
1790 	default:
1791 		panic("spx_timers: unknown timer %d", timer);
1792 	}
1793 }
1794