Change mbug allocation flags from M_ to MB_ to avoid confusion with malloc
[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.9 2004/06/02 14:43:03 eirikn 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(MB_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(MB_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, MB_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(MB_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(MB_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(MB_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(MB_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 #warning "spp_usrreq not converted to FreeBSD usrreq style! watch out!"
1270 /*ARGSUSED*/
1271 int
1272 spp_usrreq(so, req, m, nam, controlp)
1273         struct socket *so;
1274         int req;
1275         struct mbuf *m, *nam, *controlp;
1276 {
1277         int error = 0;
1278 #ifdef OBSOLETE         /* not converted to FreeBSD usrreq style XXX */
1279         struct nspcb *nsp = sotonspcb(so);
1280         struct sppcb *cb = NULL;
1281         int s = splnet();
1282         int ostate;
1283         struct mbuf *mm;
1284         struct sockbuf *sb;
1285
1286         if (req == PRU_CONTROL)
1287                 return (ns_control(so, (int)m, (caddr_t)nam,
1288                         (struct ifnet *)controlp));
1289         if (nsp == NULL) {
1290                 if (req != PRU_ATTACH) {
1291                         error = EINVAL;
1292                         goto release;
1293                 }
1294         } else
1295                 cb = nstosppcb(nsp);
1296
1297         ostate = cb ? cb->s_state : 0;
1298
1299         switch (req) {
1300
1301         case PRU_ATTACH:
1302                 if (nsp != NULL) {
1303                         error = EISCONN;
1304                         break;
1305                 }
1306                 error = ns_pcballoc(so, &nspcb);
1307                 if (error)
1308                         break;
1309                 if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
1310                         error = soreserve(so, (u_long) 3072, (u_long) 3072);
1311                         if (error)
1312                                 break;
1313                 }
1314                 nsp = sotonspcb(so);
1315
1316                 /* private PCB */
1317                 mm = m_getclr(MB_DONTWAIT, MT_CONTROL);
1318                 sb = &so->so_snd;
1319
1320                 if (mm == NULL) {
1321                         error = ENOBUFS;
1322                         break;
1323                 }
1324                 cb = mtod(mm, struct sppcb *);
1325                 mm = m_getclr(MB_DONTWAIT, MT_HEADER);
1326                 if (mm == NULL) {
1327                         (void) m_free(dtom(m));
1328                         error = ENOBUFS;
1329                         break;
1330                 }
1331                 cb->s_idp = mtod(mm, struct idp *);
1332                 cb->s_state = TCPS_LISTEN;
1333                 cb->s_smax = -1;
1334                 cb->s_swl1 = -1;
1335                 cb->s_q.si_next = cb->s_q.si_prev = &cb->s_q;
1336                 cb->s_nspcb = nsp;
1337                 cb->s_mtu = 576 - sizeof (struct spidp);
1338                 cb->s_cwnd = sbspace(sb) * CUNIT / cb->s_mtu;
1339                 cb->s_ssthresh = cb->s_cwnd;
1340                 cb->s_cwmx = sbspace(sb) * CUNIT /
1341                                 (2 * sizeof (struct spidp));
1342                 /* Above is recomputed when connecting to account
1343                    for changed buffering or mtu's */
1344                 cb->s_rtt = SPPTV_SRTTBASE;
1345                 cb->s_rttvar = SPPTV_SRTTDFLT << 2;
1346                 SPPT_RANGESET(cb->s_rxtcur,
1347                     ((SPPTV_SRTTBASE >> 2) + (SPPTV_SRTTDFLT << 2)) >> 1,
1348                     SPPTV_MIN, SPPTV_REXMTMAX);
1349                 nsp->nsp_pcb = (caddr_t) cb;
1350                 break;
1351
1352         case PRU_DETACH:
1353                 if (nsp == NULL) {
1354                         error = ENOTCONN;
1355                         break;
1356                 }
1357                 if (cb->s_state > TCPS_LISTEN)
1358                         cb = spp_disconnect(cb);
1359                 else
1360                         cb = spp_close(cb);
1361                 break;
1362
1363         case PRU_BIND:
1364                 error = ns_pcbbind(nsp, nam);
1365                 break;
1366
1367         case PRU_LISTEN:
1368                 if (nsp->nsp_lport == 0)
1369                         error = ns_pcbbind(nsp, (struct mbuf *)0);
1370                 if (error == 0)
1371                         cb->s_state = TCPS_LISTEN;
1372                 break;
1373
1374         /*
1375          * Initiate connection to peer.
1376          * Enter SYN_SENT state, and mark socket as connecting.
1377          * Start keep-alive timer, setup prototype header,
1378          * Send initial system packet requesting connection.
1379          */
1380         case PRU_CONNECT:
1381                 if (nsp->nsp_lport == 0) {
1382                         error = ns_pcbbind(nsp, (struct mbuf *)0);
1383                         if (error)
1384                                 break;
1385                 }
1386                 error = ns_pcbconnect(nsp, nam);
1387                 if (error)
1388                         break;
1389                 soisconnecting(so);
1390                 sppstat.spps_connattempt++;
1391                 cb->s_state = TCPS_SYN_SENT;
1392                 cb->s_did = 0;
1393                 spp_template(cb);
1394                 cb->s_timer[SPPT_KEEP] = SPPTV_KEEP;
1395                 cb->s_force = 1 + SPPTV_KEEP;
1396                 /*
1397                  * Other party is required to respond to
1398                  * the port I send from, but he is not
1399                  * required to answer from where I am sending to,
1400                  * so allow wildcarding.
1401                  * original port I am sending to is still saved in
1402                  * cb->s_dport.
1403                  */
1404                 nsp->nsp_fport = 0;
1405                 error = spp_output(cb, (struct mbuf *) 0);
1406                 break;
1407
1408         case PRU_CONNECT2:
1409                 error = EOPNOTSUPP;
1410                 break;
1411
1412         /*
1413          * We may decide later to implement connection closing
1414          * handshaking at the spp level optionally.
1415          * here is the hook to do it:
1416          */
1417         case PRU_DISCONNECT:
1418                 cb = spp_disconnect(cb);
1419                 break;
1420
1421         /*
1422          * Accept a connection.  Essentially all the work is
1423          * done at higher levels; just return the address
1424          * of the peer, storing through addr.
1425          */
1426         case PRU_ACCEPT: {
1427                 struct sockaddr_ns *sns = mtod(nam, struct sockaddr_ns *);
1428
1429                 nam->m_len = sizeof (struct sockaddr_ns);
1430                 sns->sns_family = AF_NS;
1431                 sns->sns_addr = nsp->nsp_faddr;
1432                 break;
1433                 }
1434
1435         case PRU_SHUTDOWN:
1436                 socantsendmore(so);
1437                 cb = spp_usrclosed(cb);
1438                 if (cb)
1439                         error = spp_output(cb, (struct mbuf *) 0);
1440                 break;
1441
1442         /*
1443          * After a receive, possibly send acknowledgment
1444          * updating allocation.
1445          */
1446         case PRU_RCVD:
1447                 cb->s_flags |= SF_RVD;
1448                 (void) spp_output(cb, (struct mbuf *) 0);
1449                 cb->s_flags &= ~SF_RVD;
1450                 break;
1451
1452         case PRU_ABORT:
1453                 (void) spp_drop(cb, ECONNABORTED);
1454                 break;
1455
1456         case PRU_SENSE:
1457         case PRU_CONTROL:
1458                 m = NULL;
1459                 error = EOPNOTSUPP;
1460                 break;
1461
1462         case PRU_RCVOOB:
1463                 if ((cb->s_oobflags & SF_IOOB) || so->so_oobmark ||
1464                     (so->so_state & SS_RCVATMARK)) {
1465                         m->m_len = 1;
1466                         *mtod(m, caddr_t) = cb->s_iobc;
1467                         break;
1468                 }
1469                 error = EINVAL;
1470                 break;
1471
1472         case PRU_SENDOOB:
1473                 if (sbspace(&so->so_snd) < -512) {
1474                         error = ENOBUFS;
1475                         break;
1476                 }
1477                 cb->s_oobflags |= SF_SOOB;
1478                 /* fall into */
1479         case PRU_SEND:
1480                 if (controlp) {
1481                         u_short *p = mtod(controlp, u_short *);
1482                         spp_newchecks[2]++;
1483                         if ((p[0] == 5) && p[1] == 1) { /* XXXX, for testing */
1484                                 cb->s_shdr.sp_dt = *(u_char *)(&p[2]);
1485                                 spp_newchecks[3]++;
1486                         }
1487                         m_freem(controlp);
1488                 }
1489                 controlp = NULL;
1490                 error = spp_output(cb, m);
1491                 m = NULL;
1492                 break;
1493
1494         case PRU_SOCKADDR:
1495                 ns_setsockaddr(nsp, nam);
1496                 break;
1497
1498         case PRU_PEERADDR:
1499                 ns_setpeeraddr(nsp, nam);
1500                 break;
1501
1502         case PRU_SLOWTIMO:
1503                 cb = spp_timers(cb, (int)nam);
1504                 req |= ((int)nam) << 8;
1505                 break;
1506
1507         case PRU_FASTTIMO:
1508         case PRU_PROTORCV:
1509         case PRU_PROTOSEND:
1510                 error =  EOPNOTSUPP;
1511                 break;
1512
1513         default:
1514                 panic("sp_usrreq");
1515         }
1516         if (cb && (so->so_options & SO_DEBUG || traceallspps))
1517                 spp_trace(SA_USER, (u_char)ostate, cb, (struct spidp *)0, req);
1518 release:
1519         if (controlp != NULL)
1520                 m_freem(controlp);
1521         if (m != NULL)
1522                 m_freem(m);
1523         splx(s);
1524 #endif
1525         return (error);
1526 }
1527
1528 int
1529 spp_usrreq_sp(so, req, m, nam, controlp)
1530         struct socket *so;
1531         int req;
1532         struct mbuf *m, *nam, *controlp;
1533 {
1534         int error = spp_usrreq(so, req, m, nam, controlp);
1535
1536         if (req == PRU_ATTACH && error == 0) {
1537                 struct nspcb *nsp = sotonspcb(so);
1538                 ((struct sppcb *)nsp->nsp_pcb)->s_flags |=
1539                                         (SF_HI | SF_HO | SF_PI);
1540         }
1541         return (error);
1542 }
1543
1544 /*
1545  * Create template to be used to send spp packets on a connection.
1546  * Called after host entry created, fills
1547  * in a skeletal spp header (choosing connection id),
1548  * minimizing the amount of work necessary when the connection is used.
1549  */
1550 void
1551 spp_template(cb)
1552         struct sppcb *cb;
1553 {
1554         struct nspcb *nsp = cb->s_nspcb;
1555         struct idp *idp = cb->s_idp;
1556         struct sockbuf *sb = &(nsp->nsp_socket->so_snd);
1557
1558         idp->idp_pt = NSPROTO_SPP;
1559         idp->idp_sna = nsp->nsp_laddr;
1560         idp->idp_dna = nsp->nsp_faddr;
1561         cb->s_sid = htons(spp_iss);
1562         spp_iss += SPP_ISSINCR/2;
1563         cb->s_alo = 1;
1564         cb->s_cwnd = (sbspace(sb) * CUNIT) / cb->s_mtu;
1565         cb->s_ssthresh = cb->s_cwnd; /* Try to expand fast to full complement
1566                                         of large packets */
1567         cb->s_cwmx = (sbspace(sb) * CUNIT) / (2 * sizeof(struct spidp));
1568         cb->s_cwmx = max(cb->s_cwmx, cb->s_cwnd);
1569                 /* But allow for lots of little packets as well */
1570 }
1571
1572 /*
1573  * Close a SPIP control block:
1574  *      discard spp control block itself
1575  *      discard ns protocol control block
1576  *      wake up any sleepers
1577  */
1578 struct sppcb *
1579 spp_close(cb)
1580         struct sppcb *cb;
1581 {
1582         struct spidp_q *s;
1583         struct nspcb *nsp = cb->s_nspcb;
1584         struct socket *so = nsp->nsp_socket;
1585         struct mbuf *m;
1586
1587         s = cb->s_q.si_next;
1588         while (s != &(cb->s_q)) {
1589                 s = s->si_next;
1590                 m = dtom(s->si_prev);
1591                 remque(s->si_prev);
1592                 m_freem(m);
1593         }
1594         (void) m_free(dtom(cb->s_idp));
1595         (void) m_free(dtom(cb));
1596         nsp->nsp_pcb = 0;
1597         soisdisconnected(so);
1598         ns_pcbdetach(nsp);
1599         sppstat.spps_closed++;
1600         return ((struct sppcb *)0);
1601 }
1602 /*
1603  *      Someday we may do level 3 handshaking
1604  *      to close a connection or send a xerox style error.
1605  *      For now, just close.
1606  */
1607 struct sppcb *
1608 spp_usrclosed(cb)
1609         struct sppcb *cb;
1610 {
1611         return (spp_close(cb));
1612 }
1613 struct sppcb *
1614 spp_disconnect(cb)
1615         struct sppcb *cb;
1616 {
1617         return (spp_close(cb));
1618 }
1619 /*
1620  * Drop connection, reporting
1621  * the specified error.
1622  */
1623 struct sppcb *
1624 spp_drop(cb, errno)
1625         struct sppcb *cb;
1626         int errno;
1627 {
1628         struct socket *so = cb->s_nspcb->nsp_socket;
1629
1630         /*
1631          * someday, in the xerox world
1632          * we will generate error protocol packets
1633          * announcing that the socket has gone away.
1634          */
1635         if (TCPS_HAVERCVDSYN(cb->s_state)) {
1636                 sppstat.spps_drops++;
1637                 cb->s_state = TCPS_CLOSED;
1638                 /*(void) tcp_output(cb);*/
1639         } else
1640                 sppstat.spps_conndrops++;
1641         so->so_error = errno;
1642         return (spp_close(cb));
1643 }
1644
1645 void
1646 spp_abort(nsp)
1647         struct nspcb *nsp;
1648 {
1649
1650         (void) spp_close((struct sppcb *)nsp->nsp_pcb);
1651 }
1652
1653 /*
1654  * Fast timeout routine for processing delayed acks
1655  */
1656 void
1657 spp_fasttimo()
1658 {
1659         struct nspcb *nsp;
1660         struct sppcb *cb;
1661         int s = splnet();
1662
1663         nsp = nspcb.nsp_next;
1664         if (nsp)
1665         for (; nsp != &nspcb; nsp = nsp->nsp_next)
1666                 if ((cb = (struct sppcb *)nsp->nsp_pcb) &&
1667                     (cb->s_flags & SF_DELACK)) {
1668                         cb->s_flags &= ~SF_DELACK;
1669                         cb->s_flags |= SF_ACKNOW;
1670                         sppstat.spps_delack++;
1671                         (void) spp_output(cb, (struct mbuf *) 0);
1672                 }
1673         splx(s);
1674 }
1675
1676 /*
1677  * spp protocol timeout routine called every 500 ms.
1678  * Updates the timers in all active pcb's and
1679  * causes finite state machine actions if timers expire.
1680  */
1681 void
1682 spp_slowtimo()
1683 {
1684         struct nspcb *ip, *ipnxt;
1685         struct sppcb *cb;
1686         int s = splnet();
1687         int i;
1688
1689         /*
1690          * Search through tcb's and update active timers.
1691          */
1692         ip = nspcb.nsp_next;
1693         if (ip == 0) {
1694                 splx(s);
1695                 return;
1696         }
1697         while (ip != &nspcb) {
1698                 cb = nstosppcb(ip);
1699                 ipnxt = ip->nsp_next;
1700                 if (cb == 0)
1701                         goto tpgone;
1702                 for (i = 0; i < SPPT_NTIMERS; i++) {
1703                         if (cb->s_timer[i] && --cb->s_timer[i] == 0) {
1704                         (void) spp_usrreq(cb->s_nspcb->nsp_socket,
1705                                     PRU_SLOWTIMO, (struct mbuf *)0,
1706                                     (struct mbuf *)i, (struct mbuf *)0);
1707                                 if (ipnxt->nsp_prev != ip)
1708                                         goto tpgone;
1709                         }
1710                 }
1711                 cb->s_idle++;
1712                 if (cb->s_rtt)
1713                         cb->s_rtt++;
1714 tpgone:
1715                 ip = ipnxt;
1716         }
1717         spp_iss += SPP_ISSINCR/PR_SLOWHZ;               /* increment iss */
1718         splx(s);
1719 }
1720 /*
1721  * SPP timer processing.
1722  */
1723 struct sppcb *
1724 spp_timers(cb, timer)
1725         struct sppcb *cb;
1726         int timer;
1727 {
1728         long rexmt;
1729         int win;
1730
1731         cb->s_force = 1 + timer;
1732         switch (timer) {
1733
1734         /*
1735          * 2 MSL timeout in shutdown went off.  TCP deletes connection
1736          * control block.
1737          */
1738         case SPPT_2MSL:
1739                 printf("spp: SPPT_2MSL went off for no reason\n");
1740                 cb->s_timer[timer] = 0;
1741                 break;
1742
1743         /*
1744          * Retransmission timer went off.  Message has not
1745          * been acked within retransmit interval.  Back off
1746          * to a longer retransmit interval and retransmit one packet.
1747          */
1748         case SPPT_REXMT:
1749                 if (++cb->s_rxtshift > SPP_MAXRXTSHIFT) {
1750                         cb->s_rxtshift = SPP_MAXRXTSHIFT;
1751                         sppstat.spps_timeoutdrop++;
1752                         cb = spp_drop(cb, ETIMEDOUT);
1753                         break;
1754                 }
1755                 sppstat.spps_rexmttimeo++;
1756                 rexmt = ((cb->s_srtt >> 2) + cb->s_rttvar) >> 1;
1757                 rexmt *= spp_backoff[cb->s_rxtshift];
1758                 SPPT_RANGESET(cb->s_rxtcur, rexmt, SPPTV_MIN, SPPTV_REXMTMAX);
1759                 cb->s_timer[SPPT_REXMT] = cb->s_rxtcur;
1760                 /*
1761                  * If we have backed off fairly far, our srtt
1762                  * estimate is probably bogus.  Clobber it
1763                  * so we'll take the next rtt measurement as our srtt;
1764                  * move the current srtt into rttvar to keep the current
1765                  * retransmit times until then.
1766                  */
1767                 if (cb->s_rxtshift > SPP_MAXRXTSHIFT / 4 ) {
1768                         cb->s_rttvar += (cb->s_srtt >> 2);
1769                         cb->s_srtt = 0;
1770                 }
1771                 cb->s_snxt = cb->s_rack;
1772                 /*
1773                  * If timing a packet, stop the timer.
1774                  */
1775                 cb->s_rtt = 0;
1776                 /*
1777                  * See very long discussion in tcp_timer.c about congestion
1778                  * window and sstrhesh
1779                  */
1780                 win = min(cb->s_swnd, (cb->s_cwnd/CUNIT)) / 2;
1781                 if (win < 2)
1782                         win = 2;
1783                 cb->s_cwnd = CUNIT;
1784                 cb->s_ssthresh = win * CUNIT;
1785                 (void) spp_output(cb, (struct mbuf *) 0);
1786                 break;
1787
1788         /*
1789          * Persistance timer into zero window.
1790          * Force a probe to be sent.
1791          */
1792         case SPPT_PERSIST:
1793                 sppstat.spps_persisttimeo++;
1794                 spp_setpersist(cb);
1795                 (void) spp_output(cb, (struct mbuf *) 0);
1796                 break;
1797
1798         /*
1799          * Keep-alive timer went off; send something
1800          * or drop connection if idle for too long.
1801          */
1802         case SPPT_KEEP:
1803                 sppstat.spps_keeptimeo++;
1804                 if (cb->s_state < TCPS_ESTABLISHED)
1805                         goto dropit;
1806                 if (cb->s_nspcb->nsp_socket->so_options & SO_KEEPALIVE) {
1807                         if (cb->s_idle >= SPPTV_MAXIDLE)
1808                                 goto dropit;
1809                         sppstat.spps_keepprobe++;
1810                         (void) spp_output(cb, (struct mbuf *) 0);
1811                 } else
1812                         cb->s_idle = 0;
1813                 cb->s_timer[SPPT_KEEP] = SPPTV_KEEP;
1814                 break;
1815         dropit:
1816                 sppstat.spps_keepdrops++;
1817                 cb = spp_drop(cb, ETIMEDOUT);
1818                 break;
1819         }
1820         return (cb);
1821 }
1822 #ifndef lint
1823 int SppcbSize = sizeof (struct sppcb);
1824 int NspcbSize = sizeof (struct nspcb);
1825 #endif /* lint */