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