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