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