changed my mind, need ip_stripoptions again
[unix-history] / usr / src / sys / netns / spp_usrreq.c
CommitLineData
8ae0e4b4
KM
1/*
2 * Copyright (c) 1982 Regents of the University of California.
3 * All rights reserved. The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
5 *
d8e9f818 6 * @(#)spp_usrreq.c 6.12 (Berkeley) %G%
8ae0e4b4 7 */
4258e601
KS
8
9#include "param.h"
10#include "dir.h"
11#include "user.h"
12#include "mbuf.h"
13#include "protosw.h"
14#include "socket.h"
15#include "socketvar.h"
16#include "errno.h"
17
18#include "../net/if.h"
19#include "../net/route.h"
20#include "../netinet/tcp_fsm.h"
21#include "../netinet/tcp_timer.h"
22
23#include "ns.h"
24#include "ns_pcb.h"
25#include "idp.h"
26#include "idp_var.h"
27#include "ns_error.h"
28#include "sp.h"
29#include "spidp.h"
30#include "spp_var.h"
31#include "spp_debug.h"
32
33/*
34 * SP protocol implementation.
35 */
36spp_init()
37{
38
39 spp_iss = 1; /* WRONG !! should fish it out of TODR */
40}
41struct spidp spp_savesi;
42int traceallspps = 0;
43extern int sppconsdebug;
4258e601 44int spp_hardnosed;
8e189bed
KS
45
46/*ARGSUSED*/
47spp_input(m, nsp, ifp)
4258e601 48 register struct mbuf *m;
fe594349 49 register struct nspcb *nsp;
8e189bed 50 struct ifnet *ifp;
e3c149da 51{
4258e601
KS
52 register struct sppcb *cb;
53 register struct spidp *si = mtod(m, struct spidp *);
54 register struct socket *so;
f97be0c9 55 short ostate;
4258e601
KS
56 int dropsocket = 0;
57
58
99e0091e 59 if (nsp == 0) {
e3c149da 60 panic("No nspcb in spp_input\n");
fe594349
KS
61 return;
62 }
4258e601
KS
63
64 cb = nstosppcb(nsp);
65 if (cb == 0) goto bad;
66
e3c149da 67 if (m->m_len < sizeof(*si)) {
99e0091e 68 if ((m = m_pullup(m, sizeof(*si))) == 0) {
e3c149da
KS
69 spp_istat.hdrops++;
70 return;
71 }
72 si = mtod(m, struct spidp *);
73 }
4258e601
KS
74 si->si_seq = ntohs(si->si_seq);
75 si->si_ack = ntohs(si->si_ack);
76 si->si_alo = ntohs(si->si_alo);
77
78 so = nsp->nsp_socket;
79 if (so->so_options & SO_DEBUG || traceallspps) {
80 ostate = cb->s_state;
81 spp_savesi = *si;
82 }
83 if (so->so_options & SO_ACCEPTCONN) {
84 so = sonewconn(so);
85 if (so == 0) {
86 spp_istat.nonucn++;
87 goto drop;
88 }
89 /*
90 * This is ugly, but ....
91 *
92 * Mark socket as temporary until we're
93 * committed to keeping it. The code at
94 * ``drop'' and ``dropwithreset'' check the
95 * flag dropsocket to see if the temporary
96 * socket created here should be discarded.
97 * We mark the socket as discardable until
98 * we're committed to it below in TCPS_LISTEN.
99 */
100 dropsocket++;
101 nsp = (struct nspcb *)so->so_pcb;
102 nsp->nsp_laddr = si->si_dna;
103 cb = nstosppcb(nsp);
104 cb->s_state = TCPS_LISTEN;
105 }
106
107 /*
108 * Packet received on connection.
109 * reset idle time and keep-alive timer;
110 */
111 cb->s_idle = 0;
112 cb->s_timer[TCPT_KEEP] = TCPTV_KEEP;
113
114 switch (cb->s_state) {
9ad31c34 115
4258e601
KS
116 case TCPS_LISTEN:{
117 struct mbuf *am;
118 register struct sockaddr_ns *sns;
119 struct ns_addr laddr;
120
121 /*
122 * If somebody here was carying on a conversation
123 * and went away, and his pen pal thinks he can
124 * still talk, we get the misdirected packet.
125 */
126 if (spp_hardnosed && (si->si_did != 0 || si->si_seq != 0)) {
127 spp_istat.gonawy++;
128 goto dropwithreset;
129 }
130 am = m_get(M_DONTWAIT, MT_SONAME);
131 if (am == NULL)
132 goto drop;
133 am->m_len = sizeof (struct sockaddr_ns);
134 sns = mtod(am, struct sockaddr_ns *);
135 sns->sns_family = AF_NS;
136 sns->sns_addr = si->si_sna;
137 laddr = nsp->nsp_laddr;
138 if (ns_nullhost(laddr))
139 nsp->nsp_laddr = si->si_dna;
140 if (ns_pcbconnect(nsp, am)) {
141 nsp->nsp_laddr = laddr;
142 (void) m_free(am);
143 spp_istat.noconn++;
144 goto drop;
145 }
146 (void) m_free(am);
4258e601 147 spp_template(cb);
d8e9f818 148 dropsocket = 0; /* committed to socket */
4258e601
KS
149 cb->s_did = si->si_sid;
150 cb->s_rack = si->si_ack;
151 cb->s_ralo = si->si_alo;
d8e9f818
KS
152#define THREEWAYSHAKE
153#ifdef THREEWAYSHAKE
154 cb->s_state = TCPS_SYN_RECEIVED;
155 cb->s_force = 1 + TCPT_REXMT;
156 cb->s_timer[TCPT_REXMT] = 2 * TCPTV_MIN;
4258e601
KS
157 }
158 break;
d8e9f818
KS
159 /*
160 * This state means that we have heard a response
161 * to our acceptance of their connection
162 * It is probably logically unnecessary in this
163 * implementation.
164 */
165 case TCPS_SYN_RECEIVED:
166 if (si->si_did!=cb->s_sid) {
167 spp_istat.wrncon++;
168 goto drop;
169 }
170#endif
171 nsp->nsp_fport = si->si_sport;
172 cb->s_timer[TCPT_REXMT] = 0;
173 cb->s_timer[TCPT_KEEP] = TCPTV_KEEP;
174 soisconnected(so);
175 cb->s_state = TCPS_ESTABLISHED;
176 break;
4258e601
KS
177
178 /*
179 * This state means that we have gotten a response
180 * to our attempt to establish a connection.
fe594349
KS
181 * We fill in the data from the other side,
182 * telling us which port to respond to, instead of the well-
183 * known one we might have sent to in the first place.
4258e601 184 * We also require that this is a response to our
fe594349 185 * connection id.
4258e601
KS
186 */
187 case TCPS_SYN_SENT:
188 if (si->si_did!=cb->s_sid) {
189 spp_istat.notme++;
190 goto drop;
191 }
192 cb->s_did = si->si_sid;
193 cb->s_rack = si->si_ack;
194 cb->s_ralo = si->si_alo;
195 cb->s_dport = nsp->nsp_fport = si->si_sport;
196 cb->s_timer[TCPT_REXMT] = 0;
197 cb->s_flags |= SF_AK;
198 soisconnected(so);
199 cb->s_state = TCPS_ESTABLISHED;
4258e601
KS
200 }
201 if (so->so_options & SO_DEBUG || traceallspps)
f97be0c9 202 spp_trace(SA_INPUT, (u_char)ostate, cb, &spp_savesi, 0);
4258e601
KS
203
204 m->m_len -= sizeof (struct idp);
205 m->m_off += sizeof (struct idp);
206
207 if (spp_reass(cb,si)) {
4258e601
KS
208 goto drop;
209 }
f97be0c9 210 (void) spp_output(cb,(struct mbuf *)0);
4258e601
KS
211 return;
212
213dropwithreset:
214 if (dropsocket)
215 (void) soabort(so);
216 si->si_seq = ntohs(si->si_seq);
217 si->si_ack = ntohs(si->si_ack);
218 si->si_alo = ntohs(si->si_alo);
219 ns_error(dtom(si), NS_ERR_NOSOCK, 0);
220 if (cb->s_nspcb->nsp_socket->so_options & SO_DEBUG || traceallspps)
f97be0c9 221 spp_trace(SA_DROP, (u_char)ostate, cb, &spp_savesi, 0);
4258e601
KS
222 return;
223
224drop:
225bad:
99e0091e 226 if (cb == 0 || cb->s_nspcb->nsp_socket->so_options & SO_DEBUG || traceallspps)
f97be0c9 227 spp_trace(SA_DROP, (u_char)ostate, cb, &spp_savesi, 0);
4258e601
KS
228 m_freem(m);
229}
230
231/*
232 * This is structurally similar to the tcp reassembly routine
233 * but its function is somewhat different: It merely queues
234 * packets up, and suppresses duplicates.
235 */
236spp_reass(cb,si)
237register struct sppcb *cb;
238register struct spidp *si;
239{
240 register struct spidp_q *q;
241 register struct mbuf *m;
242 struct socket *so = cb->s_nspcb->nsp_socket;
243 struct sockbuf *sb = & (so->so_rcv);
244 char packetp = cb->s_flags & SF_HI;
245 char wakeup = 0;
246
247
99e0091e 248 if (si == SI(0))
4258e601
KS
249 goto present;
250 /*
251 * Update our news from them.
252 */
253 if (si->si_cc & SP_SA)
254 cb->s_flags |= SF_DELACK;
255 if (SSEQ_GT(si->si_ack,cb->s_rack)) {
256 cb->s_rack = si->si_ack;
257 cb->s_timer[TCPT_REXMT] = 0;
258
259 /*
260 * If transmit timer is running and timed sequence
261 * number was acked, update smoothed round trip time.
262 */
263 if (cb->s_rtt && SSEQ_GT(si->si_ack, cb->s_rtseq)) {
264 if (cb->s_srtt == 0)
265 cb->s_srtt = cb->s_rtt;
266 else
267 cb->s_srtt =
268 tcp_alpha * cb->s_srtt +
269 (1 - tcp_alpha) * cb->s_rtt;
270 cb->s_rtt = 0;
271 }
272 }
273 if (SSEQ_GT(si->si_alo,cb->s_ralo)) {
274 cb->s_ralo = si->si_alo;
275 cb->s_timer[TCPT_PERSIST] = 0;
276 }
277 /*
278 * If this is a system packet, we don't need to
279 * queue it up, and won't update acknowledge #
280 */
ca1bb209
KS
281 if (si->si_cc & SP_SP) {
282 m_freem(dtom(si));
9ad31c34 283 return (0);
ca1bb209 284 }
4258e601
KS
285
286 /*
287 * If this packet number has a sequence number less
288 * than that of the first packet not yet seen coming
289 * from them, this must be a duplicate, so drop.
290 */
fe594349
KS
291 if (SSEQ_LT(si->si_seq,cb->s_ack)) {
292 spp_istat.bdreas++;
99e0091e 293 if (si->si_seq == cb->s_ack-1)
fe594349 294 spp_istat.lstdup++;
9ad31c34 295 return (1);
fe594349 296 }
4258e601
KS
297 /*
298 * If this packet number is higher than that which
299 * we have allocated refuse it, unless urgent
300 */
301 if (SSEQ_GT(si->si_seq,cb->s_alo) && (!(si->si_cc & SP_OB))) {
fe594349 302 spp_istat.notyet++;
9ad31c34 303 return (1);
4258e601
KS
304 }
305 /*
306 * If this packet is urgent, inform process
307 */
308 if (si->si_cc & SP_OB) {
309 cb->s_iobc = ((char *)si)[1 + sizeof(*si)];
310 sohasoutofband(so);
311 }
312
313 /*
314 * Loop through all packets queued up to insert in
315 * appropriate sequence.
316 */
317
318 for (q = cb->s_q.si_next; q!=&cb->s_q; q = q->si_next) {
99e0091e 319 if (si->si_seq == SI(q)->si_seq) return (1); /*duplicate */
4258e601
KS
320 if (SSEQ_LT(si->si_seq,SI(q)->si_seq)) break;
321 }
322 insque(si,q->si_prev);
323
324present:
325#define SPINC sizeof(struct sphdr)
326 /*
327 * Loop through all packets queued up to update acknowledge
328 * number, and present all acknowledged data to user;
329 * If in packet interface mode, show packet headers.
330 */
331 for (q = cb->s_q.si_next; q!=&cb->s_q; q = q->si_next) {
99e0091e 332 if (SI(q)->si_seq == cb->s_ack) {
4258e601
KS
333 cb->s_ack++;
334 m = dtom(q);
335 if (SI(q)->si_cc & SP_OB) {
336 if (sb->sb_cc)
337 so->so_oobmark = sb->sb_cc;
338 else
339 so->so_state |= SS_RCVATMARK;
340 }
341 q = q->si_prev;
342 remque(q->si_next);
343 wakeup = 1;
344 if (packetp) {
345 sbappendrecord(sb,m);
346 } else {
347 cb->s_rhdr = *mtod(m, struct sphdr *);
348 m->m_off += SPINC;
349 m->m_len -= SPINC;
350 sbappend(sb,m);
351 }
352 } else
353 break;
354 }
355 if (wakeup) sorwakeup(so);
9ad31c34 356 return (0);
4258e601
KS
357}
358
359spp_ctlinput(cmd, arg)
360 int cmd;
361 caddr_t arg;
362{
363 struct ns_addr *na;
364 extern u_char nsctlerrmap[];
365 extern spp_abort();
f97be0c9 366 extern struct nspcb *idp_drop();
fe594349
KS
367 struct ns_errp *errp;
368 struct nspcb *nsp;
8e189bed 369 struct sockaddr_ns *sns;
4258e601
KS
370 int type;
371
372 if (cmd < 0 || cmd > PRC_NCMDS)
373 return;
374 type = NS_ERR_UNREACH_HOST;
375
376 switch (cmd) {
9ad31c34 377
4258e601
KS
378 case PRC_ROUTEDEAD:
379 case PRC_QUENCH:
380 break;
381
382 case PRC_IFDOWN:
4258e601
KS
383 case PRC_HOSTDEAD:
384 case PRC_HOSTUNREACH:
8e189bed
KS
385 sns = (struct sockaddr_ns *)arg;
386 if (sns->sns_family != AF_NS)
387 return;
388 na = &sns->sns_addr;
4258e601
KS
389 break;
390
391 default:
fe594349
KS
392 errp = (struct ns_errp *)arg;
393 na = &errp->ns_err_idp.idp_dna;
394 type = errp->ns_err_num;
f97be0c9 395 type = ntohs((u_short)type);
4258e601
KS
396 }
397 switch (type) {
9ad31c34 398
4258e601 399 case NS_ERR_UNREACH_HOST:
fe594349 400 ns_pcbnotify(na, (int)nsctlerrmap[cmd], spp_abort, (long) 0);
4258e601 401 break;
9ad31c34 402
4258e601 403 case NS_ERR_TOO_BIG:
fe594349
KS
404 case NS_ERR_NOSOCK:
405 nsp = ns_pcblookup(na, errp->ns_err_idp.idp_sna.x_port,
406 NS_WILDCARD);
407 if (nsp) {
408 if(nsp->nsp_pcb)
f97be0c9
KS
409 (void) spp_drop((struct sppcb *)nsp->nsp_pcb,
410 (int)nsctlerrmap[cmd]);
fe594349 411 else
f97be0c9 412 (void) idp_drop(nsp, (int)nsctlerrmap[cmd]);
fe594349 413 }
4258e601
KS
414 }
415}
416
f97be0c9 417#ifdef notdef
4258e601
KS
418int
419spp_fixmtu(nsp)
420register struct nspcb *nsp;
421{
422 register struct sppcb *cb = (struct sppcb *)(nsp->nsp_pcb);
423 register struct mbuf *m;
424 register struct spidp *si;
425 struct ns_errp *ep;
426 struct sockbuf *sb;
427 int badseq, len;
428 struct mbuf *firstbad, *m0;
429
430 if (cb) {
431 /*
432 * The notification that we have sent
433 * too much is bad news -- we will
434 * have to go through queued up so far
435 * splitting ones which are too big and
436 * reassigning sequence numbers and checksums.
437 * we should then retransmit all packets from
438 * one above the offending packet to the last one
439 * we had sent (or our allocation)
440 * then the offending one so that the any queued
441 * data at our destination will be discarded.
442 */
443 ep = (struct ns_errp *)nsp->nsp_notify_param;
444 sb = &nsp->nsp_socket->so_snd;
445 cb->s_mtu = ep->ns_err_param;
446 badseq = SI(&ep->ns_err_idp)->si_seq;
447 for (m = sb->sb_mb; m; m = m->m_act) {
448 si = mtod(m, struct spidp *);
449 if (si->si_seq == badseq)
450 break;
451 }
99e0091e 452 if (m == 0) return;
4258e601
KS
453 firstbad = m;
454 /*for (;;) {*/
455 /* calculate length */
456 for (m0 = m, len = 0; m ; m = m->m_next)
457 len += m->m_len;
458 if (len > cb->s_mtu) {
459 }
460 /* FINISH THIS
461 } */
462 }
463}
f97be0c9 464#endif
4258e601
KS
465
466int spp_output_cnt = 0;
fe594349 467
4258e601
KS
468spp_output(cb, m0)
469 register struct sppcb *cb;
470 struct mbuf *m0;
471{
472 struct socket *so = cb->s_nspcb->nsp_socket;
473 register struct mbuf *m;
474 register struct spidp *si = (struct spidp *) 0;
475 register struct sockbuf *sb = &(so->so_snd);
476 register int len = 0;
99e0091e
KS
477 int error = 0;
478 u_short lookfor = 0;
4258e601
KS
479 struct mbuf *mprev;
480 extern int idpcksum;
481
99e0091e 482 if (m0) {
8e189bed
KS
483 int mtu = cb->s_mtu;
484 int datalen;
485 /*
486 * Make sure that packet isn't too big.
487 */
4258e601
KS
488 for (m = m0; m ; m = m->m_next) {
489 mprev = m;
490 len += m->m_len;
491 }
8e189bed
KS
492 datalen = (cb->s_flags & SF_HO) ?
493 len - sizeof (struct sphdr) : len;
494 if (datalen > mtu) {
4258e601
KS
495 if (cb->s_flags & SF_PI) {
496 m_freem(m0);
9ad31c34 497 return (EMSGSIZE);
4258e601
KS
498 } else {
499 int off = 0;
8e189bed
KS
500 int oldEM = cb->s_cc & SP_EM;
501
502 cb->s_cc &= ~SP_EM;
4258e601
KS
503 while (len > mtu) {
504 m = m_copy(m0, off, mtu);
99e0091e 505 if (m == NULL) {
8e189bed
KS
506 error = ENOBUFS;
507 goto bad_copy;
9ad31c34 508 }
4258e601
KS
509 error = spp_output(cb, m);
510 if (error) {
8e189bed
KS
511 bad_copy:
512 cb->s_cc |= oldEM;
4258e601 513 m_freem(m0);
8e189bed 514 return(error);
4258e601
KS
515 }
516 m_adj(m0, mtu);
517 len -= mtu;
518 }
8e189bed 519 cb->s_cc |= oldEM;
4258e601
KS
520 }
521 }
99e0091e
KS
522 /*
523 * Force length even, by adding a "garbage byte" if
524 * necessary.
525 */
4258e601 526 if (len & 1) {
fe594349 527 m = mprev;
99e0091e 528 if (m->m_len + m->m_off < MMAXOFF)
4258e601 529 m->m_len++;
99e0091e 530 else {
4258e601
KS
531 struct mbuf *m1 = m_get(M_DONTWAIT, MT_DATA);
532
533 if (m1 == 0) {
534 m_freem(m0);
535 return (ENOBUFS);
536 }
537 m1->m_len = 1;
538 m1->m_off = MMAXOFF - 1;
99e0091e 539 m->m_next = m1;
4258e601
KS
540 }
541 }
542 m = m_get(M_DONTWAIT, MT_HEADER);
543 if (m == 0) {
544 m_freem(m0);
9ad31c34 545 return (ENOBUFS);
4258e601 546 }
4258e601
KS
547 /*
548 * Fill in mbuf with extended SP header
549 * and addresses and length put into network format.
550 */
551 m->m_off = MMAXOFF - sizeof (struct spidp);
552 m->m_len = sizeof (struct spidp);
553 m->m_next = m0;
554 si = mtod(m, struct spidp *);
555 *si = cb->s_shdr;
556 if ((cb->s_flags & SF_PI) && (cb->s_flags & SF_HO)) {
99e0091e
KS
557 register struct sphdr *sh;
558 if (m0->m_len < sizeof (*sh)) {
559 if((m0 = m_pullup(m0, sizeof(*sh))) == NULL) {
560 (void) m_free(m);
561 m_freem(m0);
562 return (EINVAL);
563 }
564 m->m_next = m0;
565 }
566 sh = mtod(m0, struct sphdr *);
4258e601
KS
567 si->si_dt = sh->sp_dt;
568 si->si_cc |= sh->sp_cc & SP_EM;
569 m0->m_len -= sizeof (*sh);
570 m0->m_off += sizeof (*sh);
571 len -= sizeof (*sh);
572 }
573 len += sizeof(*si);
fe594349
KS
574 if (cb->s_oobflags & SF_SOOB) {
575 /*
576 * Per jqj@cornell:
577 * make sure OB packets convey exactly 1 byte.
578 * If the packet is 1 byte or larger, we
579 * have already guaranted there to be at least
580 * one garbage byte for the checksum, and
581 * extra bytes shouldn't hurt!
fe594349
KS
582 */
583 if (len > sizeof(*si)) {
584 si->si_cc |= SP_OB;
585 len = (1 + sizeof(*si));
586 }
587 }
f97be0c9 588 si->si_len = htons((u_short)len);
4258e601
KS
589 /*
590 * queue stuff up for output
591 */
592 sbappendrecord(sb,m);
593 cb->s_seq++;
594 }
4258e601
KS
595 /*
596 * update window
597 */
598 {
f97be0c9 599 register struct sockbuf *sb2 = &so->so_rcv;
d8e9f818
KS
600 int credit = ((sb2->sb_mbmax - sb2->sb_mbcnt) /
601 ((short)cb->s_mtu));
602 int alo = cb->s_ack + (credit > 0 ? credit : 0) - 1;
603
604 if (cb->s_alo < alo) {
605 /* If the amount we are raising the window
606 is more than his remaining headroom, tell
607 him about it. In particular, if he is at
608 his limit, any amount at all will do! */
609 u_short raise = alo - cb->s_alo;
610 u_short headroom = 1 + cb->s_alo - cb->s_ack;
611
612 if(SSEQ_LT(headroom, raise))
613 cb->s_flags |= SF_AK;
99e0091e 614 cb->s_alo = alo;
d8e9f818 615 }
4258e601
KS
616 }
617
618 if (cb->s_oobflags & SF_SOOB) {
619 /*
620 * must transmit this out of band packet
621 */
622 cb->s_oobflags &= ~ SF_SOOB;
623 } else {
624 /*
625 * Decide what to transmit:
626 * If we have a new packet, send that
627 * (So long as it is in our allocation)
628 * If it is time to retransmit a packet,
629 * send that.
630 * Otherwise, see if it time to bang on them
631 * to ask for our current allocation.
632 */
633 if (SSEQ_LT(cb->s_snt, cb->s_ralo))
634 lookfor = cb->s_snt + 1;
99e0091e 635 else if (cb->s_force == (1+TCPT_REXMT)) {
4258e601
KS
636 lookfor = cb->s_rack;
637 } else if (SSEQ_LT(cb->s_ralo, cb->s_seq)) {
638 lookfor = 0;
99e0091e 639 if (cb->s_timer[TCPT_PERSIST] == 0) {
4258e601 640 spp_setpersist(cb);
99e0091e 641 /* tcp has cb->s_rxtshift = 0; here */
4258e601
KS
642 }
643 }
644 m = sb->sb_mb;
99e0091e 645 while (m) {
4258e601
KS
646 si = mtod(m, struct spidp *);
647 m = m->m_act;
648 if (SSEQ_LT(si->si_seq, cb->s_rack)) {
649 if ((sb->sb_flags & SB_WAIT)
650 || so->so_snd.sb_sel)
651 sowwakeup(so);
652 sbdroprecord(sb);
653 si = 0;
654 continue;
655 }
656 if (SSEQ_LT(si->si_seq, lookfor))
657 continue;
658 break;
659 }
99e0091e
KS
660 if (si && (si->si_seq != lookfor))
661 si = 0;
4258e601
KS
662 }
663 cb->s_want = lookfor;
664
665 if (si) {
666 /*
667 * must make a copy of this packet for
668 * idp_output to monkey with
669 */
99e0091e
KS
670 m = m_copy(dtom(si), 0, (int)M_COPYALL);
671 if (m == NULL)
9ad31c34
KS
672 return (ENOBUFS);
673 m0 = m;
4258e601
KS
674 si = mtod(m, struct spidp *);
675 } else if (cb->s_force || cb->s_flags & SF_AK) {
676 /*
677 * Must send an acknowledgement or a probe
678 */
679 m = m_get(M_DONTWAIT, MT_HEADER);
680 if (m == 0)
9ad31c34 681 return (ENOBUFS);
4258e601
KS
682 /*
683 * Fill in mbuf with extended SP header
684 * and addresses and length put into network format.
685 */
686 m->m_off = MMAXOFF - sizeof (struct spidp);
687 m->m_len = sizeof (*si);
688 m->m_next = 0;
689 si = mtod(m, struct spidp *);
690 *si = cb->s_shdr;
691 si->si_seq = cb->s_snt + 1;
fe594349 692 si->si_len = htons(sizeof (*si));
4258e601
KS
693 si->si_cc |= SP_SP;
694 cb->s_flags &= ~SF_AK;
695 }
696 /*
697 * Stuff checksum and output datagram.
698 */
699 if (si) {
700 /*
701 * If we are almost out of allocation
702 * or one of the timers has gone off
703 * request an ack.
704 */
99e0091e 705 if (SSEQ_GEQ(cb->s_seq, cb->s_ralo))
4258e601
KS
706 si->si_cc |= SP_SA;
707 if (cb->s_force) {
708 si->si_cc |= SP_SA;
709 cb->s_force = 0;
710 }
99e0091e
KS
711 /*
712 * If this is a new packet (and not a system packet),
fe594349
KS
713 * and we are not currently timing anything,
714 * time this one and ask for an ack.
4258e601 715 */
99e0091e 716 if (SSEQ_LT(cb->s_snt, si->si_seq) && (!(si->si_cc & SP_SP))) {
4258e601 717 cb->s_snt = si->si_seq;
99e0091e 718 if (cb->s_rtt == 0) {
4258e601
KS
719 cb->s_rtseq = si->si_seq;
720 cb->s_rtt = 1;
721 si->si_cc |= SP_SA;
722 }
723 /*
724 * If the retransmit timer has not been set
725 * and this is a real packet
726 * then start the retransmit timer
727 */
99e0091e 728 if (cb->s_timer[TCPT_REXMT] == 0) {
4258e601
KS
729 TCPT_RANGESET(cb->s_timer[TCPT_REXMT],
730 tcp_beta * cb->s_srtt, TCPTV_MIN,
731 TCPTV_MAX);
732 cb->s_rxtshift = 0;
733 }
734 }
735 si->si_seq = htons(si->si_seq);
736 si->si_alo = htons(cb->s_alo);
737 si->si_ack = htons(cb->s_ack);
738
739 if (idpcksum) {
740 si->si_sum = 0;
fe594349 741 len = ntohs(si->si_len);
99e0091e
KS
742 if (len & 1)
743 len++;
4258e601
KS
744 si->si_sum = ns_cksum(dtom(si), len);
745 } else
746 si->si_sum = 0xffff;
747
748 if (so->so_options & SO_DEBUG || traceallspps)
749 spp_trace(SA_OUTPUT, cb->s_state, cb, si, 0);
750 spp_output_cnt++;
751 if (so->so_options & SO_DONTROUTE)
752 error = ns_output(m, (struct route *)0, NS_ROUTETOIF);
753 else
754 error = ns_output(m, &cb->s_nspcb->nsp_route, 0);
755 if (traceallspps && sppconsdebug) {
756 printf("spp_out: %x\n", error);
757 }
9ad31c34 758 return (error);
4258e601
KS
759 }
760 if (so->so_options & SO_DEBUG || traceallspps)
761 spp_trace(SA_OUTPUT, cb->s_state, cb, si, 0);
9ad31c34 762 return (error);
4258e601
KS
763}
764
765/*ARGSUSED*/
766spp_ctloutput(req, so, level, name, value)
767 int req;
768 struct socket *so;
769 int name;
770 struct mbuf **value;
771{
772 register struct mbuf *m;
773 struct nspcb *nsp = sotonspcb(so);
774 register struct sppcb *cb;
775 int mask, error = 0;
776
777 if (level != NSPROTO_SPP) {
778 /* This will have to be changed when we do more general
779 stacking of protocols */
9ad31c34 780 return (idp_ctloutput(req, so, level, name, value));
4258e601
KS
781 }
782 if (nsp == NULL) {
783 error = EINVAL;
784 goto release;
785 } else
786 cb = nstosppcb(nsp);
787
788 switch (req) {
9ad31c34 789
4258e601 790 case PRCO_GETOPT:
99e0091e 791 if (value == NULL)
9ad31c34 792 return (EINVAL);
4258e601 793 m = m_get(M_DONTWAIT, MT_DATA);
99e0091e 794 if (m == NULL)
9ad31c34 795 return (ENOBUFS);
4258e601 796 switch (name) {
9ad31c34 797
4258e601
KS
798 case SO_HEADERS_ON_INPUT:
799 mask = SF_HI;
800 goto get_flags;
9ad31c34 801
4258e601
KS
802 case SO_HEADERS_ON_OUTPUT:
803 mask = SF_HO;
804 get_flags:
805 m->m_len = sizeof(short);
806 m->m_off = MMAXOFF - sizeof(short);
807 *mtod(m, short *) = cb->s_flags & mask;
808 break;
9ad31c34 809
8e189bed
KS
810 case SO_MTU:
811 m->m_len = sizeof(u_short);
812 m->m_off = MMAXOFF - sizeof(short);
813 *mtod(m, short *) = cb->s_mtu;
814 break;
815
4258e601
KS
816 case SO_LAST_HEADER:
817 m->m_len = sizeof(struct sphdr);
818 m->m_off = MMAXOFF - sizeof(struct sphdr);
819 *mtod(m, struct sphdr *) = cb->s_rhdr;
820 break;
9ad31c34 821
4258e601
KS
822 case SO_DEFAULT_HEADERS:
823 m->m_len = sizeof(struct spidp);
824 m->m_off = MMAXOFF - sizeof(struct sphdr);
825 *mtod(m, struct sphdr *) = cb->s_shdr.si_s;
826 }
827 *value = m;
828 break;
9ad31c34 829
4258e601 830 case PRCO_SETOPT:
8e189bed
KS
831 if (value == 0 || *value == 0) {
832 error = EINVAL;
833 break;
834 }
4258e601 835 switch (name) {
f97be0c9 836 int *ok;
4258e601
KS
837
838 case SO_HEADERS_ON_INPUT:
839 mask = SF_HI;
840 goto set_head;
9ad31c34 841
4258e601
KS
842 case SO_HEADERS_ON_OUTPUT:
843 mask = SF_HO;
844 set_head:
8e189bed 845 if (cb->s_flags & SF_PI) {
4258e601
KS
846 ok = mtod(*value, int *);
847 if (*ok)
848 cb->s_flags |= mask;
849 else
850 cb->s_flags &= ~mask;
851 } else error = EINVAL;
852 break;
9ad31c34 853
8e189bed
KS
854 case SO_MTU:
855 cb->s_mtu = *(mtod(*value, u_short *));
856 break;
857
4258e601
KS
858 case SO_DEFAULT_HEADERS:
859 {
860 register struct sphdr *sp
861 = mtod(*value, struct sphdr *);
862 cb->s_dt = sp->sp_dt;
863 cb->s_cc = sp->sp_cc & SP_EM;
864 }
865 }
8e189bed 866 m_freem(*value);
4258e601
KS
867 break;
868 }
869 release:
9ad31c34 870 return (error);
4258e601
KS
871}
872
873/*ARGSUSED*/
874spp_usrreq(so, req, m, nam, rights)
875 struct socket *so;
876 int req;
877 struct mbuf *m, *nam, *rights;
878{
879 struct nspcb *nsp = sotonspcb(so);
880 register struct sppcb *cb;
881 int s = splnet();
882 int error = 0, ostate;
883
884 if (req == PRU_CONTROL)
885 return (ns_control(so, (int)m, (caddr_t)nam,
886 (struct ifnet *)rights));
887 if (rights && rights->m_len) {
888 error = EINVAL;
889 goto release;
890 }
891 if (nsp == NULL) {
892 if (req != PRU_ATTACH) {
893 error = EINVAL;
894 goto release;
895 }
896 } else
897 cb = nstosppcb(nsp);
898
899 ostate = cb ? cb->s_state : 0;
900
901 switch (req) {
9ad31c34 902
4258e601
KS
903 case PRU_ATTACH:
904 if (nsp != NULL) {
905 error = EISCONN;
906 break;
907 }
908 error = ns_pcballoc(so, &nspcb);
909 if (error)
910 break;
911 error = soreserve(so, 2048, 2048);
912 if (error)
913 break;
914 nsp = sotonspcb(so);
915 {
916 struct mbuf *mm = m_getclr(M_DONTWAIT,MT_PCB);
917
99e0091e 918 if (mm == NULL) {
4258e601
KS
919 error = ENOBUFS;
920 break;
921 }
922 cb = mtod(mm, struct sppcb *);
923 cb->s_state = TCPS_LISTEN;
4258e601
KS
924 cb->s_snt = -1;
925 cb->s_q.si_next = cb->s_q.si_prev = &cb->s_q;
926 cb->s_nspcb = nsp;
927 nsp->nsp_pcb = (caddr_t) cb;
928 }
929 break;
930
931 case PRU_DETACH:
932 if (nsp == NULL) {
933 error = ENOTCONN;
934 break;
935 }
936 if (cb->s_state > TCPS_LISTEN)
937 cb = spp_disconnect(cb);
938 else
939 cb = spp_close(cb);
940 break;
941
942 case PRU_BIND:
943 error = ns_pcbbind(nsp, nam);
944 break;
945
946 case PRU_LISTEN:
947 if (nsp->nsp_lport == 0)
948 error = ns_pcbbind(nsp, (struct mbuf *)0);
949 if (error == 0)
950 cb->s_state = TCPS_LISTEN;
951 break;
952
953 /*
954 * Initiate connection to peer.
955 * Enter SYN_SENT state, and mark socket as connecting.
956 * Start keep-alive timer, setup prototype header,
957 * Send initial system packet requesting connection.
958 */
959 case PRU_CONNECT:
960 if (nsp->nsp_lport == 0) {
961 error = ns_pcbbind(nsp, (struct mbuf *)0);
962 if (error)
963 break;
964 }
965 error = ns_pcbconnect(nsp, nam);
966 if (error)
967 break;
968 soisconnecting(so);
969 cb->s_state = TCPS_SYN_SENT;
970 cb->s_did = 0;
971 spp_template(cb);
972 cb->s_timer[TCPT_KEEP] = TCPTV_KEEP;
973 cb->s_force = 1 + TCPTV_KEEP;
974 /*
975 * Other party is required to respond to
976 * the port I send from, but he is not
977 * required to answer from where I am sending to,
978 * so allow wildcarding.
979 * original port I am sending to is still saved in
980 * cb->s_dport.
981 */
982 nsp->nsp_fport = 0;
983 error = spp_output(cb, (struct mbuf *) 0);
984 break;
985
986 case PRU_CONNECT2:
987 error = EOPNOTSUPP;
988 break;
989
990 /*
991 * We may decide later to implement connection closing
992 * handshaking at the spp level optionally.
993 * here is the hook to do it:
994 */
995 case PRU_DISCONNECT:
996 cb = spp_disconnect(cb);
997 break;
998
999 /*
1000 * Accept a connection. Essentially all the work is
1001 * done at higher levels; just return the address
1002 * of the peer, storing through addr.
1003 */
1004 case PRU_ACCEPT: {
1005 struct sockaddr_ns *sns = mtod(nam, struct sockaddr_ns *);
1006
1007 nam->m_len = sizeof (struct sockaddr_ns);
1008 sns->sns_family = AF_NS;
1009 sns->sns_addr = nsp->nsp_faddr;
1010 break;
1011 }
1012
1013 case PRU_SHUTDOWN:
1014 socantsendmore(so);
1015 cb = spp_usrclosed(cb);
1016 if (cb)
1017 error = spp_output(cb, (struct mbuf *) 0);
1018 break;
1019
1020 /*
1021 * After a receive, possibly send acknowledgment
1022 * updating allocation.
1023 */
1024 case PRU_RCVD:
1025 (void) spp_output(cb, (struct mbuf *) 0);
1026 break;
1027
1028 case PRU_SEND:
1029 error = spp_output(cb, m);
1030 m = NULL;
1031 break;
1032
1033 case PRU_ABORT:
f97be0c9 1034 (void) spp_drop(cb, ECONNABORTED);
4258e601
KS
1035 break;
1036
1037 case PRU_SENSE:
1038 case PRU_CONTROL:
1039 m = NULL;
1040 error = EOPNOTSUPP;
1041 break;
1042
1043 case PRU_RCVOOB:
d8e9f818
KS
1044 if (so->so_oobmark == 0 &&
1045 (so->so_state & SS_RCVATMARK) == 0) {
1046 error = EINVAL;
1047 break;
1048 }
4258e601
KS
1049 if ( ! (cb->s_oobflags & SF_IOOB) ) {
1050 error = EWOULDBLOCK;
1051 break;
1052 }
1053 m->m_len = 1;
1054 *mtod(m, caddr_t) = cb->s_iobc;
d8e9f818
KS
1055 if (((int)nam & MSG_PEEK) == 0)
1056 cb->s_oobflags &= ~ SF_IOOB;
4258e601
KS
1057 break;
1058
1059 case PRU_SENDOOB:
1060 if (sbspace(&so->so_snd) < -512) {
1061 m_freem(m);
1062 error = ENOBUFS;
1063 break;
1064 }
1065 cb->s_oobflags |= SF_SOOB;
1066 error = spp_output(cb, m);
1067 m = NULL;
1068 cb->s_oobflags &= ~SF_SOOB;
1069 break;
1070
1071 case PRU_SOCKADDR:
1072 ns_setsockaddr(nsp, nam);
1073 break;
1074
1075 case PRU_PEERADDR:
1076 ns_setpeeraddr(nsp, nam);
1077 break;
1078
1079 case PRU_SLOWTIMO:
1080 cb = spp_timers(cb, (int)nam);
1081 break;
1082
1083 case PRU_FASTTIMO:
1084 case PRU_PROTORCV:
1085 case PRU_PROTOSEND:
1086 error = EOPNOTSUPP;
1087 break;
1088
1089 default:
1090 panic("sp_usrreq");
1091 }
1092 if (cb && (so->so_options & SO_DEBUG || traceallspps))
f97be0c9 1093 spp_trace(SA_USER, (u_char)ostate, cb, (struct spidp *)0, req);
4258e601
KS
1094release:
1095 if (m != NULL)
1096 m_freem(m);
1097 splx(s);
1098 return (error);
1099}
1100
1101spp_usrreq_sp(so, req, m, nam, rights)
1102 struct socket *so;
1103 int req;
1104 struct mbuf *m, *nam, *rights;
1105{
1106 int error = spp_usrreq(so, req, m, nam, rights);
1107
99e0091e 1108 if (req == PRU_ATTACH && error == 0) {
4258e601
KS
1109 struct nspcb *nsp = sotonspcb(so);
1110 ((struct sppcb *)nsp->nsp_pcb)->s_flags |=
1111 (SF_HI | SF_HO | SF_PI);
1112 }
9ad31c34 1113 return (error);
4258e601
KS
1114}
1115
1116/*
1117 * Create template to be used to send spp packets on a connection.
1118 * Called after host entry created, fills
1119 * in a skeletal spp header (choosing connection id),
1120 * minimizing the amount of work necessary when the connection is used.
1121 */
1122spp_template(cb)
1123 struct sppcb *cb;
1124{
1125 register struct nspcb *nsp = cb->s_nspcb;
1126 register struct spidp *n = &(cb->s_shdr);
1127
8e189bed 1128 cb->s_mtu = 576 - sizeof (struct spidp);
4258e601
KS
1129 n->si_pt = NSPROTO_SPP;
1130 n->si_sna = nsp->nsp_laddr;
1131 n->si_dna = nsp->nsp_faddr;
1132 n->si_sid = htons(spp_iss);
1133 spp_iss += SPP_ISSINCR/2;
1134 n->si_alo = 1;
1135}
1136
1137/*
1138 * Close a SPIP control block:
1139 * discard spp control block itself
1140 * discard ns protocol control block
1141 * wake up any sleepers
1142 */
1143struct sppcb *
1144spp_close(cb)
1145 register struct sppcb *cb;
1146{
1147 register struct spidp_q *s;
1148 struct nspcb *nsp = cb->s_nspcb;
1149 struct socket *so = nsp->nsp_socket;
1150 register struct mbuf *m;
1151
1152 s = cb->s_q.si_next;
1153 while (s != &(cb->s_q)) {
1154 s = s->si_next;
1155 m = dtom(s->si_prev);
1156 remque(s->si_prev);
1157 m_freem(m);
1158 }
1159 (void) m_free(dtom(cb));
1160 nsp->nsp_pcb = 0;
1161 soisdisconnected(so);
1162 ns_pcbdetach(nsp);
9ad31c34 1163 return ((struct sppcb *)0);
4258e601
KS
1164}
1165/*
1166 * Someday we may do level 3 handshaking
1167 * to close a connection or send a xerox style error.
1168 * For now, just close.
1169 */
1170struct sppcb *
1171spp_usrclosed(cb)
1172 register struct sppcb *cb;
1173{
9ad31c34 1174 return (spp_close(cb));
4258e601
KS
1175}
1176struct sppcb *
1177spp_disconnect(cb)
1178 register struct sppcb *cb;
1179{
9ad31c34 1180 return (spp_close(cb));
4258e601
KS
1181}
1182/*
1183 * Drop connection, reporting
1184 * the specified error.
1185 */
1186struct sppcb *
1187spp_drop(cb, errno)
1188 register struct sppcb *cb;
1189 int errno;
1190{
1191 struct socket *so = cb->s_nspcb->nsp_socket;
1192
1193 /*
1194 * someday, in the xerox world
1195 * we will generate error protocol packets
1196 * announcing that the socket has gone away.
1197 */
1198 /*if (TCPS_HAVERCVDSYN(tp->t_state)) {
1199 tp->t_state = TCPS_CLOSED;
1200 (void) tcp_output(tp);
1201 }*/
1202 so->so_error = errno;
1203 return (spp_close(cb));
1204}
1205
1206spp_abort(nsp)
1207 struct nspcb *nsp;
1208{
1209
f97be0c9 1210 (void) spp_close((struct sppcb *)nsp->nsp_pcb);
4258e601
KS
1211}
1212
1213spp_setpersist(cb)
1214 register struct sppcb *cb;
1215{
1216
1217 /*if (cb->s_timer[TCPT_REXMT])
1218 panic("spp_output REXMT");*/
1219 /*
1220 * Start/restart persistance timer.
1221 */
1222 TCPT_RANGESET(cb->s_timer[TCPT_PERSIST],
1223 ((int)(tcp_beta * cb->s_srtt)) << cb->s_rxtshift,
1224 TCPTV_PERSMIN, TCPTV_MAX);
1225 cb->s_rxtshift++;
1226 if (cb->s_rxtshift >= TCP_MAXRXTSHIFT)
1227 cb->s_rxtshift = 0;
1228}
1229/*
1230 * Fast timeout routine for processing delayed acks
1231 */
1232int spp_ftcnt;
1233spp_fasttimo()
1234{
1235 register struct nspcb *nsp;
1236 register struct sppcb *cb;
1237 int s = splnet();
1238
1239 nsp = nspcb.nsp_next;
1240 spp_ftcnt++;
1241 if (nsp)
1242 for (; nsp != &nspcb; nsp = nsp->nsp_next)
1243 if ((cb = (struct sppcb *)nsp->nsp_pcb) &&
1244 (cb->s_flags & SF_DELACK)) {
1245 cb->s_flags &= ~SF_DELACK;
1246 cb->s_flags |= SF_AK;
1247 (void) spp_output(cb, (struct mbuf *) 0);
1248 }
1249 splx(s);
1250}
1251
1252/*
1253 * spp protocol timeout routine called every 500 ms.
1254 * Updates the timers in all active pcb's and
1255 * causes finite state machine actions if timers expire.
1256 */
1257spp_slowtimo()
1258{
1259 register struct nspcb *ip, *ipnxt;
1260 register struct sppcb *cb;
1261 int s = splnet();
1262 register int i;
1263
1264 /*
1265 * Search through tcb's and update active timers.
1266 */
1267 ip = nspcb.nsp_next;
1268 if (ip == 0) {
1269 splx(s);
1270 return;
1271 }
1272 while (ip != &nspcb) {
1273 cb = nstosppcb(ip);
1274 ipnxt = ip->nsp_next;
1275 if (cb == 0)
1276 goto tpgone;
1277 for (i = 0; i < TCPT_NTIMERS; i++) {
1278 if (cb->s_timer[i] && --cb->s_timer[i] == 0) {
1279 (void) spp_usrreq(cb->s_nspcb->nsp_socket,
1280 PRU_SLOWTIMO, (struct mbuf *)0,
1281 (struct mbuf *)i, (struct mbuf *)0);
1282 if (ipnxt->nsp_prev != ip)
1283 goto tpgone;
1284 }
1285 }
1286 cb->s_idle++;
1287 if (cb->s_rtt)
1288 cb->s_rtt++;
1289tpgone:
1290 ip = ipnxt;
1291 }
1292 spp_iss += SPP_ISSINCR/PR_SLOWHZ; /* increment iss */
1293 splx(s);
1294}
1295
1296float spp_backoff[TCP_MAXRXTSHIFT] =
1297 { 1.0, 1.2, 1.4, 1.7, 2.0, 3.0, 5.0, 8.0, 16.0, 32.0 };
a5c5bc2d 1298int sppexprexmtbackoff = 0;
4258e601 1299/*
8e189bed 1300 * SPP timer processing.
4258e601
KS
1301 */
1302struct sppcb *
1303spp_timers(cb, timer)
1304 register struct sppcb *cb;
1305 int timer;
1306{
1307
1308 cb->s_force = 1 + timer;
1309 switch (timer) {
1310
1311 /*
1312 * 2 MSL timeout in shutdown went off. Delete connection
1313 * control block.
1314 */
1315 case TCPT_2MSL:
1316 cb = spp_close(cb);
1317 break;
1318
1319 /*
1320 * Retransmission timer went off. Message has not
1321 * been acked within retransmit interval. Back off
1322 * to a longer retransmit interval and retransmit all
1323 * unacknowledged messages in the window.
1324 */
1325 case TCPT_REXMT:
1326 cb->s_rxtshift++;
1327 if (cb->s_rxtshift > TCP_MAXRXTSHIFT) {
1328 cb = spp_drop(cb, ETIMEDOUT);
1329 break;
1330 }
1331 (void) spp_output(cb, (struct mbuf *) 0);
1332 TCPT_RANGESET(cb->s_timer[TCPT_REXMT],
1333 (int)cb->s_srtt, TCPTV_MIN, TCPTV_MAX);
a5c5bc2d 1334 if (sppexprexmtbackoff) {
4258e601
KS
1335 TCPT_RANGESET(cb->s_timer[TCPT_REXMT],
1336 cb->s_timer[TCPT_REXMT] << cb->s_rxtshift,
1337 TCPTV_MIN, TCPTV_MAX);
1338 } else {
1339 TCPT_RANGESET(cb->s_timer[TCPT_REXMT],
1340 cb->s_timer[TCPT_REXMT] *
1341 spp_backoff[cb->s_rxtshift - 1],
1342 TCPTV_MIN, TCPTV_MAX);
1343 }
1344 break;
1345
1346 /*
1347 * Persistance timer into zero window.
1348 * Force a probe to be sent.
1349 */
1350 case TCPT_PERSIST:
1351 (void) spp_output(cb, (struct mbuf *) 0);
1352 spp_setpersist(cb);
1353 break;
1354
1355 /*
1356 * Keep-alive timer went off; send something
1357 * or drop connection if idle for too long.
1358 */
1359 case TCPT_KEEP:
1360 if (cb->s_state < TCPS_ESTABLISHED)
1361 goto dropit;
1362 if (cb->s_nspcb->nsp_socket->so_options & SO_KEEPALIVE) {
1363 if (cb->s_idle >= TCPTV_MAXIDLE)
1364 goto dropit;
1365 (void) spp_output(cb, (struct mbuf *) 0);
1366 } else
1367 cb->s_idle = 0;
1368 cb->s_timer[TCPT_KEEP] = TCPTV_KEEP;
1369 break;
1370 dropit:
1371 cb = spp_drop(cb, ETIMEDOUT);
1372 break;
1373 }
1374 return (cb);
1375}