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