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