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