123215Smckusick /* 223215Smckusick * Copyright (c) 1982 Regents of the University of California. 323215Smckusick * All rights reserved. The Berkeley software License Agreement 423215Smckusick * specifies the terms and conditions for redistribution. 523215Smckusick * 6*25037Ssklower * @(#)spp_usrreq.c 6.13 (Berkeley) 09/26/85 723215Smckusick */ 821496Ssklower 921496Ssklower #include "param.h" 1021496Ssklower #include "dir.h" 1121496Ssklower #include "user.h" 1221496Ssklower #include "mbuf.h" 1321496Ssklower #include "protosw.h" 1421496Ssklower #include "socket.h" 1521496Ssklower #include "socketvar.h" 1621496Ssklower #include "errno.h" 1721496Ssklower 1821496Ssklower #include "../net/if.h" 1921496Ssklower #include "../net/route.h" 2021496Ssklower #include "../netinet/tcp_fsm.h" 2121496Ssklower #include "../netinet/tcp_timer.h" 2221496Ssklower 2321496Ssklower #include "ns.h" 2421496Ssklower #include "ns_pcb.h" 2521496Ssklower #include "idp.h" 2621496Ssklower #include "idp_var.h" 2721496Ssklower #include "ns_error.h" 2821496Ssklower #include "sp.h" 2921496Ssklower #include "spidp.h" 3021496Ssklower #include "spp_var.h" 3121496Ssklower #include "spp_debug.h" 3221496Ssklower 3321496Ssklower /* 3421496Ssklower * SP protocol implementation. 3521496Ssklower */ 3621496Ssklower spp_init() 3721496Ssklower { 3821496Ssklower 3921496Ssklower spp_iss = 1; /* WRONG !! should fish it out of TODR */ 4021496Ssklower } 4121496Ssklower struct spidp spp_savesi; 4221496Ssklower int traceallspps = 0; 4321496Ssklower extern int sppconsdebug; 4424615Ssklower int spp_hardnosed; 45*25037Ssklower int spp_use_delack = 0; 4621496Ssklower 4724615Ssklower /*ARGSUSED*/ 4824615Ssklower spp_input(m, nsp, ifp) 4921496Ssklower register struct mbuf *m; 5024047Ssklower register struct nspcb *nsp; 5124615Ssklower struct ifnet *ifp; 5221496Ssklower { 5321496Ssklower register struct sppcb *cb; 5421496Ssklower register struct spidp *si = mtod(m, struct spidp *); 5521496Ssklower register struct socket *so; 5624225Ssklower short ostate; 5721496Ssklower int dropsocket = 0; 5821496Ssklower 5921496Ssklower 6024330Ssklower if (nsp == 0) { 6124047Ssklower panic("No nspcb in spp_input\n"); 6223979Ssklower return; 6323979Ssklower } 6421496Ssklower 6521496Ssklower cb = nstosppcb(nsp); 6621496Ssklower if (cb == 0) goto bad; 6721496Ssklower 6824047Ssklower if (m->m_len < sizeof(*si)) { 6924330Ssklower if ((m = m_pullup(m, sizeof(*si))) == 0) { 7024047Ssklower spp_istat.hdrops++; 7124047Ssklower return; 7224047Ssklower } 7324047Ssklower si = mtod(m, struct spidp *); 7424047Ssklower } 7521496Ssklower si->si_seq = ntohs(si->si_seq); 7621496Ssklower si->si_ack = ntohs(si->si_ack); 7721496Ssklower si->si_alo = ntohs(si->si_alo); 7821496Ssklower 7921496Ssklower so = nsp->nsp_socket; 8021496Ssklower if (so->so_options & SO_DEBUG || traceallspps) { 8121496Ssklower ostate = cb->s_state; 8221496Ssklower spp_savesi = *si; 8321496Ssklower } 8421496Ssklower if (so->so_options & SO_ACCEPTCONN) { 8521496Ssklower so = sonewconn(so); 8621496Ssklower if (so == 0) { 8721496Ssklower spp_istat.nonucn++; 8821496Ssklower goto drop; 8921496Ssklower } 9021496Ssklower /* 9121496Ssklower * This is ugly, but .... 9221496Ssklower * 9321496Ssklower * Mark socket as temporary until we're 9421496Ssklower * committed to keeping it. The code at 9521496Ssklower * ``drop'' and ``dropwithreset'' check the 9621496Ssklower * flag dropsocket to see if the temporary 9721496Ssklower * socket created here should be discarded. 9821496Ssklower * We mark the socket as discardable until 9921496Ssklower * we're committed to it below in TCPS_LISTEN. 10021496Ssklower */ 10121496Ssklower dropsocket++; 10221496Ssklower nsp = (struct nspcb *)so->so_pcb; 10321496Ssklower nsp->nsp_laddr = si->si_dna; 10421496Ssklower cb = nstosppcb(nsp); 10521496Ssklower cb->s_state = TCPS_LISTEN; 10621496Ssklower } 10721496Ssklower 10821496Ssklower /* 10921496Ssklower * Packet received on connection. 11021496Ssklower * reset idle time and keep-alive timer; 11121496Ssklower */ 11221496Ssklower cb->s_idle = 0; 11321496Ssklower cb->s_timer[TCPT_KEEP] = TCPTV_KEEP; 11421496Ssklower 11521496Ssklower switch (cb->s_state) { 11623515Ssklower 11721496Ssklower case TCPS_LISTEN:{ 11821496Ssklower struct mbuf *am; 11921496Ssklower register struct sockaddr_ns *sns; 12021496Ssklower struct ns_addr laddr; 12121496Ssklower 12221496Ssklower /* 12321496Ssklower * If somebody here was carying on a conversation 12421496Ssklower * and went away, and his pen pal thinks he can 12521496Ssklower * still talk, we get the misdirected packet. 12621496Ssklower */ 12721496Ssklower if (spp_hardnosed && (si->si_did != 0 || si->si_seq != 0)) { 12821496Ssklower spp_istat.gonawy++; 12921496Ssklower goto dropwithreset; 13021496Ssklower } 13121496Ssklower am = m_get(M_DONTWAIT, MT_SONAME); 13221496Ssklower if (am == NULL) 13321496Ssklower goto drop; 13421496Ssklower am->m_len = sizeof (struct sockaddr_ns); 13521496Ssklower sns = mtod(am, struct sockaddr_ns *); 13621496Ssklower sns->sns_family = AF_NS; 13721496Ssklower sns->sns_addr = si->si_sna; 13821496Ssklower laddr = nsp->nsp_laddr; 13921496Ssklower if (ns_nullhost(laddr)) 14021496Ssklower nsp->nsp_laddr = si->si_dna; 14121496Ssklower if (ns_pcbconnect(nsp, am)) { 14221496Ssklower nsp->nsp_laddr = laddr; 14321496Ssklower (void) m_free(am); 14421496Ssklower spp_istat.noconn++; 14521496Ssklower goto drop; 14621496Ssklower } 14721496Ssklower (void) m_free(am); 14821496Ssklower spp_template(cb); 14924732Ssklower dropsocket = 0; /* committed to socket */ 15021496Ssklower cb->s_did = si->si_sid; 15121496Ssklower cb->s_rack = si->si_ack; 15221496Ssklower cb->s_ralo = si->si_alo; 15324732Ssklower #define THREEWAYSHAKE 15424732Ssklower #ifdef THREEWAYSHAKE 15524732Ssklower cb->s_state = TCPS_SYN_RECEIVED; 15624732Ssklower cb->s_force = 1 + TCPT_REXMT; 15724732Ssklower cb->s_timer[TCPT_REXMT] = 2 * TCPTV_MIN; 15821496Ssklower } 15921496Ssklower break; 16024732Ssklower /* 16124732Ssklower * This state means that we have heard a response 16224732Ssklower * to our acceptance of their connection 16324732Ssklower * It is probably logically unnecessary in this 16424732Ssklower * implementation. 16524732Ssklower */ 16624732Ssklower case TCPS_SYN_RECEIVED: 16724732Ssklower if (si->si_did!=cb->s_sid) { 16824732Ssklower spp_istat.wrncon++; 16924732Ssklower goto drop; 17024732Ssklower } 17124732Ssklower #endif 17224732Ssklower nsp->nsp_fport = si->si_sport; 17324732Ssklower cb->s_timer[TCPT_REXMT] = 0; 17424732Ssklower cb->s_timer[TCPT_KEEP] = TCPTV_KEEP; 17524732Ssklower soisconnected(so); 17624732Ssklower cb->s_state = TCPS_ESTABLISHED; 17724732Ssklower break; 17821496Ssklower 17921496Ssklower /* 18021496Ssklower * This state means that we have gotten a response 18121496Ssklower * to our attempt to establish a connection. 18223979Ssklower * We fill in the data from the other side, 18323979Ssklower * telling us which port to respond to, instead of the well- 18423979Ssklower * known one we might have sent to in the first place. 18521496Ssklower * We also require that this is a response to our 18623979Ssklower * connection id. 18721496Ssklower */ 18821496Ssklower case TCPS_SYN_SENT: 18921496Ssklower if (si->si_did!=cb->s_sid) { 19021496Ssklower spp_istat.notme++; 19121496Ssklower goto drop; 19221496Ssklower } 19321496Ssklower cb->s_did = si->si_sid; 19421496Ssklower cb->s_rack = si->si_ack; 19521496Ssklower cb->s_ralo = si->si_alo; 19621496Ssklower cb->s_dport = nsp->nsp_fport = si->si_sport; 19721496Ssklower cb->s_timer[TCPT_REXMT] = 0; 19821496Ssklower cb->s_flags |= SF_AK; 19921496Ssklower soisconnected(so); 20021496Ssklower cb->s_state = TCPS_ESTABLISHED; 20121496Ssklower } 20221496Ssklower if (so->so_options & SO_DEBUG || traceallspps) 20324225Ssklower spp_trace(SA_INPUT, (u_char)ostate, cb, &spp_savesi, 0); 20421496Ssklower 20521496Ssklower m->m_len -= sizeof (struct idp); 20621496Ssklower m->m_off += sizeof (struct idp); 20721496Ssklower 208*25037Ssklower if (spp_reass(cb, si)) { 20921496Ssklower goto drop; 21021496Ssklower } 211*25037Ssklower (void) spp_output(cb, (struct mbuf *)0); 21221496Ssklower return; 21321496Ssklower 21421496Ssklower dropwithreset: 21521496Ssklower if (dropsocket) 21621496Ssklower (void) soabort(so); 21721496Ssklower si->si_seq = ntohs(si->si_seq); 21821496Ssklower si->si_ack = ntohs(si->si_ack); 21921496Ssklower si->si_alo = ntohs(si->si_alo); 22021496Ssklower ns_error(dtom(si), NS_ERR_NOSOCK, 0); 22121496Ssklower if (cb->s_nspcb->nsp_socket->so_options & SO_DEBUG || traceallspps) 22224225Ssklower spp_trace(SA_DROP, (u_char)ostate, cb, &spp_savesi, 0); 22321496Ssklower return; 22421496Ssklower 22521496Ssklower drop: 22621496Ssklower bad: 22724330Ssklower if (cb == 0 || cb->s_nspcb->nsp_socket->so_options & SO_DEBUG || traceallspps) 22824225Ssklower spp_trace(SA_DROP, (u_char)ostate, cb, &spp_savesi, 0); 22921496Ssklower m_freem(m); 23021496Ssklower } 23121496Ssklower 23221496Ssklower /* 23321496Ssklower * This is structurally similar to the tcp reassembly routine 23421496Ssklower * but its function is somewhat different: It merely queues 23521496Ssklower * packets up, and suppresses duplicates. 23621496Ssklower */ 237*25037Ssklower spp_reass(cb, si) 23821496Ssklower register struct sppcb *cb; 23921496Ssklower register struct spidp *si; 24021496Ssklower { 24121496Ssklower register struct spidp_q *q; 24221496Ssklower register struct mbuf *m; 24321496Ssklower struct socket *so = cb->s_nspcb->nsp_socket; 24421496Ssklower struct sockbuf *sb = & (so->so_rcv); 24521496Ssklower char packetp = cb->s_flags & SF_HI; 24621496Ssklower char wakeup = 0; 24721496Ssklower 24821496Ssklower 24924330Ssklower if (si == SI(0)) 25021496Ssklower goto present; 25121496Ssklower /* 25221496Ssklower * Update our news from them. 25321496Ssklower */ 25421496Ssklower if (si->si_cc & SP_SA) 255*25037Ssklower cb->s_flags |= (spp_use_delack ? SF_DELACK : SF_AK); 256*25037Ssklower if (SSEQ_GT(si->si_ack, cb->s_rack)) { 25721496Ssklower cb->s_rack = si->si_ack; 25821496Ssklower /* 259*25037Ssklower * If there are other packets outstanding, 260*25037Ssklower * restart the timer for them. 261*25037Ssklower */ 262*25037Ssklower if (SSEQ_GEQ(cb->s_snt, si->si_ack)) { 263*25037Ssklower TCPT_RANGESET(cb->s_timer[TCPT_REXMT], 264*25037Ssklower tcp_beta * cb->s_srtt, TCPTV_MIN, 265*25037Ssklower TCPTV_MAX); 266*25037Ssklower cb->s_rxtshift = 0; 267*25037Ssklower } else 268*25037Ssklower cb->s_timer[TCPT_REXMT] = 0; 269*25037Ssklower /* 27021496Ssklower * If transmit timer is running and timed sequence 27121496Ssklower * number was acked, update smoothed round trip time. 27221496Ssklower */ 27321496Ssklower if (cb->s_rtt && SSEQ_GT(si->si_ack, cb->s_rtseq)) { 27421496Ssklower if (cb->s_srtt == 0) 27521496Ssklower cb->s_srtt = cb->s_rtt; 27621496Ssklower else 27721496Ssklower cb->s_srtt = 27821496Ssklower tcp_alpha * cb->s_srtt + 27921496Ssklower (1 - tcp_alpha) * cb->s_rtt; 28021496Ssklower cb->s_rtt = 0; 28121496Ssklower } 28221496Ssklower } 283*25037Ssklower if (SSEQ_GT(si->si_alo, cb->s_ralo)) { 28421496Ssklower cb->s_ralo = si->si_alo; 28521496Ssklower cb->s_timer[TCPT_PERSIST] = 0; 28621496Ssklower } 28721496Ssklower /* 28821496Ssklower * If this is a system packet, we don't need to 28921496Ssklower * queue it up, and won't update acknowledge # 29021496Ssklower */ 29123561Ssklower if (si->si_cc & SP_SP) { 29223561Ssklower m_freem(dtom(si)); 29323515Ssklower return (0); 29423561Ssklower } 29521496Ssklower 29621496Ssklower /* 29721496Ssklower * If this packet number has a sequence number less 29821496Ssklower * than that of the first packet not yet seen coming 29921496Ssklower * from them, this must be a duplicate, so drop. 30021496Ssklower */ 301*25037Ssklower if (SSEQ_LT(si->si_seq, cb->s_ack)) { 30223979Ssklower spp_istat.bdreas++; 30324330Ssklower if (si->si_seq == cb->s_ack-1) 30423979Ssklower spp_istat.lstdup++; 30523515Ssklower return (1); 30623979Ssklower } 30721496Ssklower /* 30821496Ssklower * If this packet number is higher than that which 30921496Ssklower * we have allocated refuse it, unless urgent 31021496Ssklower */ 311*25037Ssklower if (SSEQ_GT(si->si_seq, cb->s_alo)) { 312*25037Ssklower if (si->si_cc & SP_OB) { 313*25037Ssklower if (SSEQ_GT(si->si_seq, cb->s_alo + 60)) { 314*25037Ssklower ns_error(dtom(si), NS_ERR_FULLUP, 0); 315*25037Ssklower return (0); 316*25037Ssklower } /* else queue this packet; */ 317*25037Ssklower } else { 318*25037Ssklower spp_istat.notyet++; 319*25037Ssklower return (1); 320*25037Ssklower } 32121496Ssklower } 32221496Ssklower 32321496Ssklower /* 32421496Ssklower * Loop through all packets queued up to insert in 32521496Ssklower * appropriate sequence. 32621496Ssklower */ 32721496Ssklower 32821496Ssklower for (q = cb->s_q.si_next; q!=&cb->s_q; q = q->si_next) { 32924330Ssklower if (si->si_seq == SI(q)->si_seq) return (1); /*duplicate */ 330*25037Ssklower if (SSEQ_LT(si->si_seq, SI(q)->si_seq)) break; 33121496Ssklower } 332*25037Ssklower insque(si, q->si_prev); 333*25037Ssklower /* 334*25037Ssklower * If this packet is urgent, inform process 335*25037Ssklower */ 336*25037Ssklower if (si->si_cc & SP_OB) { 337*25037Ssklower cb->s_iobc = ((char *)si)[1 + sizeof(*si)]; 338*25037Ssklower sohasoutofband(so); 339*25037Ssklower cb->s_oobflags |= SF_IOOB; 340*25037Ssklower } 34121496Ssklower present: 34221496Ssklower #define SPINC sizeof(struct sphdr) 34321496Ssklower /* 34421496Ssklower * Loop through all packets queued up to update acknowledge 34521496Ssklower * number, and present all acknowledged data to user; 34621496Ssklower * If in packet interface mode, show packet headers. 34721496Ssklower */ 34821496Ssklower for (q = cb->s_q.si_next; q!=&cb->s_q; q = q->si_next) { 34924330Ssklower if (SI(q)->si_seq == cb->s_ack) { 35021496Ssklower cb->s_ack++; 35121496Ssklower m = dtom(q); 35221496Ssklower if (SI(q)->si_cc & SP_OB) { 353*25037Ssklower cb->s_oobflags &= ~SF_IOOB; 35421496Ssklower if (sb->sb_cc) 35521496Ssklower so->so_oobmark = sb->sb_cc; 35621496Ssklower else 35721496Ssklower so->so_state |= SS_RCVATMARK; 35821496Ssklower } 35921496Ssklower q = q->si_prev; 36021496Ssklower remque(q->si_next); 36121496Ssklower wakeup = 1; 36221496Ssklower if (packetp) { 363*25037Ssklower sbappendrecord(sb, m); 36421496Ssklower } else { 36521496Ssklower cb->s_rhdr = *mtod(m, struct sphdr *); 36621496Ssklower m->m_off += SPINC; 36721496Ssklower m->m_len -= SPINC; 368*25037Ssklower sbappend(sb, m); 36921496Ssklower } 37021496Ssklower } else 37121496Ssklower break; 37221496Ssklower } 37321496Ssklower if (wakeup) sorwakeup(so); 37423515Ssklower return (0); 37521496Ssklower } 37621496Ssklower 37721496Ssklower spp_ctlinput(cmd, arg) 37821496Ssklower int cmd; 37921496Ssklower caddr_t arg; 38021496Ssklower { 38121496Ssklower struct ns_addr *na; 38221496Ssklower extern u_char nsctlerrmap[]; 38321496Ssklower extern spp_abort(); 38424225Ssklower extern struct nspcb *idp_drop(); 38523979Ssklower struct ns_errp *errp; 38623979Ssklower struct nspcb *nsp; 38724615Ssklower struct sockaddr_ns *sns; 38821496Ssklower int type; 38921496Ssklower 39021496Ssklower if (cmd < 0 || cmd > PRC_NCMDS) 39121496Ssklower return; 39221496Ssklower type = NS_ERR_UNREACH_HOST; 39321496Ssklower 39421496Ssklower switch (cmd) { 39523515Ssklower 39621496Ssklower case PRC_ROUTEDEAD: 39721496Ssklower case PRC_QUENCH: 39821496Ssklower break; 39921496Ssklower 40021496Ssklower case PRC_IFDOWN: 40121496Ssklower case PRC_HOSTDEAD: 40221496Ssklower case PRC_HOSTUNREACH: 40324615Ssklower sns = (struct sockaddr_ns *)arg; 40424615Ssklower if (sns->sns_family != AF_NS) 40524615Ssklower return; 40624615Ssklower na = &sns->sns_addr; 40721496Ssklower break; 40821496Ssklower 40921496Ssklower default: 41023979Ssklower errp = (struct ns_errp *)arg; 41123979Ssklower na = &errp->ns_err_idp.idp_dna; 41223979Ssklower type = errp->ns_err_num; 41324225Ssklower type = ntohs((u_short)type); 41421496Ssklower } 41521496Ssklower switch (type) { 41623515Ssklower 41721496Ssklower case NS_ERR_UNREACH_HOST: 41823979Ssklower ns_pcbnotify(na, (int)nsctlerrmap[cmd], spp_abort, (long) 0); 41921496Ssklower break; 42023515Ssklower 42121496Ssklower case NS_ERR_TOO_BIG: 42223979Ssklower case NS_ERR_NOSOCK: 42323979Ssklower nsp = ns_pcblookup(na, errp->ns_err_idp.idp_sna.x_port, 42423979Ssklower NS_WILDCARD); 42523979Ssklower if (nsp) { 42623979Ssklower if(nsp->nsp_pcb) 42724225Ssklower (void) spp_drop((struct sppcb *)nsp->nsp_pcb, 42824225Ssklower (int)nsctlerrmap[cmd]); 42923979Ssklower else 43024225Ssklower (void) idp_drop(nsp, (int)nsctlerrmap[cmd]); 43123979Ssklower } 43221496Ssklower } 43321496Ssklower } 43421496Ssklower 43524225Ssklower #ifdef notdef 43621496Ssklower int 43721496Ssklower spp_fixmtu(nsp) 43821496Ssklower register struct nspcb *nsp; 43921496Ssklower { 44021496Ssklower register struct sppcb *cb = (struct sppcb *)(nsp->nsp_pcb); 44121496Ssklower register struct mbuf *m; 44221496Ssklower register struct spidp *si; 44321496Ssklower struct ns_errp *ep; 44421496Ssklower struct sockbuf *sb; 44521496Ssklower int badseq, len; 44621496Ssklower struct mbuf *firstbad, *m0; 44721496Ssklower 44821496Ssklower if (cb) { 44921496Ssklower /* 45021496Ssklower * The notification that we have sent 45121496Ssklower * too much is bad news -- we will 45221496Ssklower * have to go through queued up so far 45321496Ssklower * splitting ones which are too big and 45421496Ssklower * reassigning sequence numbers and checksums. 45521496Ssklower * we should then retransmit all packets from 45621496Ssklower * one above the offending packet to the last one 45721496Ssklower * we had sent (or our allocation) 45821496Ssklower * then the offending one so that the any queued 45921496Ssklower * data at our destination will be discarded. 46021496Ssklower */ 46121496Ssklower ep = (struct ns_errp *)nsp->nsp_notify_param; 46221496Ssklower sb = &nsp->nsp_socket->so_snd; 46321496Ssklower cb->s_mtu = ep->ns_err_param; 46421496Ssklower badseq = SI(&ep->ns_err_idp)->si_seq; 46521496Ssklower for (m = sb->sb_mb; m; m = m->m_act) { 46621496Ssklower si = mtod(m, struct spidp *); 46721496Ssklower if (si->si_seq == badseq) 46821496Ssklower break; 46921496Ssklower } 47024330Ssklower if (m == 0) return; 47121496Ssklower firstbad = m; 47221496Ssklower /*for (;;) {*/ 47321496Ssklower /* calculate length */ 47421496Ssklower for (m0 = m, len = 0; m ; m = m->m_next) 47521496Ssklower len += m->m_len; 47621496Ssklower if (len > cb->s_mtu) { 47721496Ssklower } 47821496Ssklower /* FINISH THIS 47921496Ssklower } */ 48021496Ssklower } 48121496Ssklower } 48224225Ssklower #endif 48321496Ssklower 48421496Ssklower int spp_output_cnt = 0; 48523979Ssklower 48621496Ssklower spp_output(cb, m0) 48721496Ssklower register struct sppcb *cb; 48821496Ssklower struct mbuf *m0; 48921496Ssklower { 49021496Ssklower struct socket *so = cb->s_nspcb->nsp_socket; 49121496Ssklower register struct mbuf *m; 49221496Ssklower register struct spidp *si = (struct spidp *) 0; 49321496Ssklower register struct sockbuf *sb = &(so->so_snd); 49421496Ssklower register int len = 0; 49524330Ssklower int error = 0; 49624330Ssklower u_short lookfor = 0; 49721496Ssklower struct mbuf *mprev; 49821496Ssklower extern int idpcksum; 49921496Ssklower 50024330Ssklower if (m0) { 50124615Ssklower int mtu = cb->s_mtu; 50224615Ssklower int datalen; 50324615Ssklower /* 50424615Ssklower * Make sure that packet isn't too big. 50524615Ssklower */ 50621496Ssklower for (m = m0; m ; m = m->m_next) { 50721496Ssklower mprev = m; 50821496Ssklower len += m->m_len; 50921496Ssklower } 51024615Ssklower datalen = (cb->s_flags & SF_HO) ? 51124615Ssklower len - sizeof (struct sphdr) : len; 51224615Ssklower if (datalen > mtu) { 51321496Ssklower if (cb->s_flags & SF_PI) { 51421496Ssklower m_freem(m0); 51523515Ssklower return (EMSGSIZE); 51621496Ssklower } else { 51721496Ssklower int off = 0; 51824615Ssklower int oldEM = cb->s_cc & SP_EM; 51924615Ssklower 52024615Ssklower cb->s_cc &= ~SP_EM; 52121496Ssklower while (len > mtu) { 52221496Ssklower m = m_copy(m0, off, mtu); 52324330Ssklower if (m == NULL) { 52424615Ssklower error = ENOBUFS; 52524615Ssklower goto bad_copy; 52623515Ssklower } 52721496Ssklower error = spp_output(cb, m); 52821496Ssklower if (error) { 52924615Ssklower bad_copy: 53024615Ssklower cb->s_cc |= oldEM; 53121496Ssklower m_freem(m0); 53224615Ssklower return(error); 53321496Ssklower } 53421496Ssklower m_adj(m0, mtu); 53521496Ssklower len -= mtu; 53621496Ssklower } 53724615Ssklower cb->s_cc |= oldEM; 53821496Ssklower } 53921496Ssklower } 54024330Ssklower /* 54124330Ssklower * Force length even, by adding a "garbage byte" if 54224330Ssklower * necessary. 54324330Ssklower */ 54421496Ssklower if (len & 1) { 54523979Ssklower m = mprev; 54624330Ssklower if (m->m_len + m->m_off < MMAXOFF) 54721496Ssklower m->m_len++; 54824330Ssklower else { 54921496Ssklower struct mbuf *m1 = m_get(M_DONTWAIT, MT_DATA); 55021496Ssklower 55121496Ssklower if (m1 == 0) { 55221496Ssklower m_freem(m0); 55321496Ssklower return (ENOBUFS); 55421496Ssklower } 55521496Ssklower m1->m_len = 1; 55621496Ssklower m1->m_off = MMAXOFF - 1; 55724330Ssklower m->m_next = m1; 55821496Ssklower } 55921496Ssklower } 56021496Ssklower m = m_get(M_DONTWAIT, MT_HEADER); 56121496Ssklower if (m == 0) { 56221496Ssklower m_freem(m0); 56323515Ssklower return (ENOBUFS); 56421496Ssklower } 56521496Ssklower /* 56621496Ssklower * Fill in mbuf with extended SP header 56721496Ssklower * and addresses and length put into network format. 56821496Ssklower */ 56921496Ssklower m->m_off = MMAXOFF - sizeof (struct spidp); 57021496Ssklower m->m_len = sizeof (struct spidp); 57121496Ssklower m->m_next = m0; 57221496Ssklower si = mtod(m, struct spidp *); 57321496Ssklower *si = cb->s_shdr; 57421496Ssklower if ((cb->s_flags & SF_PI) && (cb->s_flags & SF_HO)) { 57524330Ssklower register struct sphdr *sh; 57624330Ssklower if (m0->m_len < sizeof (*sh)) { 57724330Ssklower if((m0 = m_pullup(m0, sizeof(*sh))) == NULL) { 57824330Ssklower (void) m_free(m); 57924330Ssklower m_freem(m0); 58024330Ssklower return (EINVAL); 58124330Ssklower } 58224330Ssklower m->m_next = m0; 58324330Ssklower } 58424330Ssklower sh = mtod(m0, struct sphdr *); 58521496Ssklower si->si_dt = sh->sp_dt; 58621496Ssklower si->si_cc |= sh->sp_cc & SP_EM; 58721496Ssklower m0->m_len -= sizeof (*sh); 58821496Ssklower m0->m_off += sizeof (*sh); 58921496Ssklower len -= sizeof (*sh); 59021496Ssklower } 59121496Ssklower len += sizeof(*si); 59223979Ssklower if (cb->s_oobflags & SF_SOOB) { 59323979Ssklower /* 59423979Ssklower * Per jqj@cornell: 59523979Ssklower * make sure OB packets convey exactly 1 byte. 59623979Ssklower * If the packet is 1 byte or larger, we 59723979Ssklower * have already guaranted there to be at least 59823979Ssklower * one garbage byte for the checksum, and 59923979Ssklower * extra bytes shouldn't hurt! 60023979Ssklower */ 60123979Ssklower if (len > sizeof(*si)) { 60223979Ssklower si->si_cc |= SP_OB; 60323979Ssklower len = (1 + sizeof(*si)); 60423979Ssklower } 60523979Ssklower } 60624225Ssklower si->si_len = htons((u_short)len); 60721496Ssklower /* 60821496Ssklower * queue stuff up for output 60921496Ssklower */ 610*25037Ssklower sbappendrecord(sb, m); 61121496Ssklower cb->s_seq++; 61221496Ssklower } 61321496Ssklower /* 61421496Ssklower * update window 61521496Ssklower */ 61621496Ssklower { 61724225Ssklower register struct sockbuf *sb2 = &so->so_rcv; 61824732Ssklower int credit = ((sb2->sb_mbmax - sb2->sb_mbcnt) / 61924732Ssklower ((short)cb->s_mtu)); 62024732Ssklower int alo = cb->s_ack + (credit > 0 ? credit : 0) - 1; 62121496Ssklower 62224732Ssklower if (cb->s_alo < alo) { 62324732Ssklower /* If the amount we are raising the window 62424732Ssklower is more than his remaining headroom, tell 62524732Ssklower him about it. In particular, if he is at 62624732Ssklower his limit, any amount at all will do! */ 62724732Ssklower u_short raise = alo - cb->s_alo; 62824732Ssklower u_short headroom = 1 + cb->s_alo - cb->s_ack; 62924732Ssklower 63024732Ssklower if(SSEQ_LT(headroom, raise)) 63124732Ssklower cb->s_flags |= SF_AK; 63224330Ssklower cb->s_alo = alo; 63324732Ssklower } 63421496Ssklower } 63521496Ssklower 63621496Ssklower if (cb->s_oobflags & SF_SOOB) { 63721496Ssklower /* 63821496Ssklower * must transmit this out of band packet 63921496Ssklower */ 64021496Ssklower cb->s_oobflags &= ~ SF_SOOB; 64121496Ssklower } else { 64221496Ssklower /* 64321496Ssklower * Decide what to transmit: 64421496Ssklower * If we have a new packet, send that 64521496Ssklower * (So long as it is in our allocation) 64621496Ssklower * If it is time to retransmit a packet, 64721496Ssklower * send that. 64821496Ssklower * Otherwise, see if it time to bang on them 64921496Ssklower * to ask for our current allocation. 65021496Ssklower */ 65121496Ssklower if (SSEQ_LT(cb->s_snt, cb->s_ralo)) 65221496Ssklower lookfor = cb->s_snt + 1; 65324330Ssklower else if (cb->s_force == (1+TCPT_REXMT)) { 65421496Ssklower lookfor = cb->s_rack; 65521496Ssklower } else if (SSEQ_LT(cb->s_ralo, cb->s_seq)) { 65621496Ssklower lookfor = 0; 65724330Ssklower if (cb->s_timer[TCPT_PERSIST] == 0) { 65821496Ssklower spp_setpersist(cb); 65924330Ssklower /* tcp has cb->s_rxtshift = 0; here */ 66021496Ssklower } 66121496Ssklower } 66221496Ssklower m = sb->sb_mb; 66324330Ssklower while (m) { 66421496Ssklower si = mtod(m, struct spidp *); 66521496Ssklower m = m->m_act; 66621496Ssklower if (SSEQ_LT(si->si_seq, cb->s_rack)) { 66721496Ssklower if ((sb->sb_flags & SB_WAIT) 66821496Ssklower || so->so_snd.sb_sel) 66921496Ssklower sowwakeup(so); 67021496Ssklower sbdroprecord(sb); 67121496Ssklower si = 0; 67221496Ssklower continue; 67321496Ssklower } 67421496Ssklower if (SSEQ_LT(si->si_seq, lookfor)) 67521496Ssklower continue; 67621496Ssklower break; 67721496Ssklower } 67824330Ssklower if (si && (si->si_seq != lookfor)) 67924330Ssklower si = 0; 68021496Ssklower } 68121496Ssklower cb->s_want = lookfor; 68221496Ssklower 68321496Ssklower if (si) { 68421496Ssklower /* 68521496Ssklower * must make a copy of this packet for 68621496Ssklower * idp_output to monkey with 68721496Ssklower */ 68824330Ssklower m = m_copy(dtom(si), 0, (int)M_COPYALL); 68924330Ssklower if (m == NULL) 69023515Ssklower return (ENOBUFS); 69123515Ssklower m0 = m; 69221496Ssklower si = mtod(m, struct spidp *); 69321496Ssklower } else if (cb->s_force || cb->s_flags & SF_AK) { 69421496Ssklower /* 69521496Ssklower * Must send an acknowledgement or a probe 69621496Ssklower */ 69721496Ssklower m = m_get(M_DONTWAIT, MT_HEADER); 69821496Ssklower if (m == 0) 69923515Ssklower return (ENOBUFS); 70021496Ssklower /* 70121496Ssklower * Fill in mbuf with extended SP header 70221496Ssklower * and addresses and length put into network format. 70321496Ssklower */ 70421496Ssklower m->m_off = MMAXOFF - sizeof (struct spidp); 70521496Ssklower m->m_len = sizeof (*si); 70621496Ssklower m->m_next = 0; 70721496Ssklower si = mtod(m, struct spidp *); 70821496Ssklower *si = cb->s_shdr; 70921496Ssklower si->si_seq = cb->s_snt + 1; 71023979Ssklower si->si_len = htons(sizeof (*si)); 71121496Ssklower si->si_cc |= SP_SP; 71221496Ssklower } 71321496Ssklower /* 71421496Ssklower * Stuff checksum and output datagram. 71521496Ssklower */ 71621496Ssklower if (si) { 717*25037Ssklower if (cb->s_flags & (SF_AK|SF_DELACK)) 718*25037Ssklower cb->s_flags &= ~(SF_AK|SF_DELACK); 71921496Ssklower /* 72021496Ssklower * If we are almost out of allocation 72121496Ssklower * or one of the timers has gone off 72221496Ssklower * request an ack. 72321496Ssklower */ 72424330Ssklower if (SSEQ_GEQ(cb->s_seq, cb->s_ralo)) 72521496Ssklower si->si_cc |= SP_SA; 72621496Ssklower if (cb->s_force) { 72721496Ssklower si->si_cc |= SP_SA; 72821496Ssklower cb->s_force = 0; 72921496Ssklower } 73024330Ssklower /* 73124330Ssklower * If this is a new packet (and not a system packet), 73223979Ssklower * and we are not currently timing anything, 73323979Ssklower * time this one and ask for an ack. 73421496Ssklower */ 73524330Ssklower if (SSEQ_LT(cb->s_snt, si->si_seq) && (!(si->si_cc & SP_SP))) { 73621496Ssklower cb->s_snt = si->si_seq; 73724330Ssklower if (cb->s_rtt == 0) { 73821496Ssklower cb->s_rtseq = si->si_seq; 73921496Ssklower cb->s_rtt = 1; 74021496Ssklower si->si_cc |= SP_SA; 74121496Ssklower } 74221496Ssklower /* 74321496Ssklower * If the retransmit timer has not been set 74421496Ssklower * and this is a real packet 74521496Ssklower * then start the retransmit timer 74621496Ssklower */ 74724330Ssklower if (cb->s_timer[TCPT_REXMT] == 0) { 74821496Ssklower TCPT_RANGESET(cb->s_timer[TCPT_REXMT], 74921496Ssklower tcp_beta * cb->s_srtt, TCPTV_MIN, 75021496Ssklower TCPTV_MAX); 75121496Ssklower cb->s_rxtshift = 0; 75221496Ssklower } 75321496Ssklower } 75421496Ssklower si->si_seq = htons(si->si_seq); 75521496Ssklower si->si_alo = htons(cb->s_alo); 75621496Ssklower si->si_ack = htons(cb->s_ack); 75721496Ssklower 75821496Ssklower if (idpcksum) { 75921496Ssklower si->si_sum = 0; 76023979Ssklower len = ntohs(si->si_len); 76124330Ssklower if (len & 1) 76224330Ssklower len++; 76321496Ssklower si->si_sum = ns_cksum(dtom(si), len); 76421496Ssklower } else 76521496Ssklower si->si_sum = 0xffff; 76621496Ssklower 76721496Ssklower if (so->so_options & SO_DEBUG || traceallspps) 76821496Ssklower spp_trace(SA_OUTPUT, cb->s_state, cb, si, 0); 76921496Ssklower spp_output_cnt++; 77021496Ssklower if (so->so_options & SO_DONTROUTE) 77121496Ssklower error = ns_output(m, (struct route *)0, NS_ROUTETOIF); 77221496Ssklower else 77321496Ssklower error = ns_output(m, &cb->s_nspcb->nsp_route, 0); 77421496Ssklower if (traceallspps && sppconsdebug) { 77521496Ssklower printf("spp_out: %x\n", error); 77621496Ssklower } 77723515Ssklower return (error); 77821496Ssklower } 77921496Ssklower if (so->so_options & SO_DEBUG || traceallspps) 78021496Ssklower spp_trace(SA_OUTPUT, cb->s_state, cb, si, 0); 78123515Ssklower return (error); 78221496Ssklower } 78321496Ssklower 78421496Ssklower /*ARGSUSED*/ 78521496Ssklower spp_ctloutput(req, so, level, name, value) 78621496Ssklower int req; 78721496Ssklower struct socket *so; 78821496Ssklower int name; 78921496Ssklower struct mbuf **value; 79021496Ssklower { 79121496Ssklower register struct mbuf *m; 79221496Ssklower struct nspcb *nsp = sotonspcb(so); 79321496Ssklower register struct sppcb *cb; 79421496Ssklower int mask, error = 0; 79521496Ssklower 79621496Ssklower if (level != NSPROTO_SPP) { 79721496Ssklower /* This will have to be changed when we do more general 79821496Ssklower stacking of protocols */ 79923515Ssklower return (idp_ctloutput(req, so, level, name, value)); 80021496Ssklower } 80121496Ssklower if (nsp == NULL) { 80221496Ssklower error = EINVAL; 80321496Ssklower goto release; 80421496Ssklower } else 80521496Ssklower cb = nstosppcb(nsp); 80621496Ssklower 80721496Ssklower switch (req) { 80823515Ssklower 80921496Ssklower case PRCO_GETOPT: 81024330Ssklower if (value == NULL) 81123515Ssklower return (EINVAL); 81221496Ssklower m = m_get(M_DONTWAIT, MT_DATA); 81324330Ssklower if (m == NULL) 81423515Ssklower return (ENOBUFS); 81521496Ssklower switch (name) { 81623515Ssklower 81721496Ssklower case SO_HEADERS_ON_INPUT: 81821496Ssklower mask = SF_HI; 81921496Ssklower goto get_flags; 82023515Ssklower 82121496Ssklower case SO_HEADERS_ON_OUTPUT: 82221496Ssklower mask = SF_HO; 82321496Ssklower get_flags: 82421496Ssklower m->m_len = sizeof(short); 82521496Ssklower m->m_off = MMAXOFF - sizeof(short); 82621496Ssklower *mtod(m, short *) = cb->s_flags & mask; 82721496Ssklower break; 82823515Ssklower 82924615Ssklower case SO_MTU: 83024615Ssklower m->m_len = sizeof(u_short); 83124615Ssklower m->m_off = MMAXOFF - sizeof(short); 83224615Ssklower *mtod(m, short *) = cb->s_mtu; 83324615Ssklower break; 83424615Ssklower 83521496Ssklower case SO_LAST_HEADER: 83621496Ssklower m->m_len = sizeof(struct sphdr); 83721496Ssklower m->m_off = MMAXOFF - sizeof(struct sphdr); 83821496Ssklower *mtod(m, struct sphdr *) = cb->s_rhdr; 83921496Ssklower break; 84023515Ssklower 84121496Ssklower case SO_DEFAULT_HEADERS: 84221496Ssklower m->m_len = sizeof(struct spidp); 84321496Ssklower m->m_off = MMAXOFF - sizeof(struct sphdr); 84421496Ssklower *mtod(m, struct sphdr *) = cb->s_shdr.si_s; 84521496Ssklower } 84621496Ssklower *value = m; 84721496Ssklower break; 84823515Ssklower 84921496Ssklower case PRCO_SETOPT: 85024615Ssklower if (value == 0 || *value == 0) { 85124615Ssklower error = EINVAL; 85224615Ssklower break; 85324615Ssklower } 85421496Ssklower switch (name) { 85524225Ssklower int *ok; 85621496Ssklower 85721496Ssklower case SO_HEADERS_ON_INPUT: 85821496Ssklower mask = SF_HI; 85921496Ssklower goto set_head; 86023515Ssklower 86121496Ssklower case SO_HEADERS_ON_OUTPUT: 86221496Ssklower mask = SF_HO; 86321496Ssklower set_head: 86424615Ssklower if (cb->s_flags & SF_PI) { 86521496Ssklower ok = mtod(*value, int *); 86621496Ssklower if (*ok) 86721496Ssklower cb->s_flags |= mask; 86821496Ssklower else 86921496Ssklower cb->s_flags &= ~mask; 87021496Ssklower } else error = EINVAL; 87121496Ssklower break; 87223515Ssklower 87324615Ssklower case SO_MTU: 87424615Ssklower cb->s_mtu = *(mtod(*value, u_short *)); 87524615Ssklower break; 87624615Ssklower 87721496Ssklower case SO_DEFAULT_HEADERS: 87821496Ssklower { 87921496Ssklower register struct sphdr *sp 88021496Ssklower = mtod(*value, struct sphdr *); 88121496Ssklower cb->s_dt = sp->sp_dt; 88221496Ssklower cb->s_cc = sp->sp_cc & SP_EM; 88321496Ssklower } 88421496Ssklower } 88524615Ssklower m_freem(*value); 88621496Ssklower break; 88721496Ssklower } 88821496Ssklower release: 88923515Ssklower return (error); 89021496Ssklower } 89121496Ssklower 89221496Ssklower /*ARGSUSED*/ 89321496Ssklower spp_usrreq(so, req, m, nam, rights) 89421496Ssklower struct socket *so; 89521496Ssklower int req; 89621496Ssklower struct mbuf *m, *nam, *rights; 89721496Ssklower { 89821496Ssklower struct nspcb *nsp = sotonspcb(so); 89921496Ssklower register struct sppcb *cb; 90021496Ssklower int s = splnet(); 90121496Ssklower int error = 0, ostate; 90221496Ssklower 90321496Ssklower if (req == PRU_CONTROL) 90421496Ssklower return (ns_control(so, (int)m, (caddr_t)nam, 90521496Ssklower (struct ifnet *)rights)); 90621496Ssklower if (rights && rights->m_len) { 90721496Ssklower error = EINVAL; 90821496Ssklower goto release; 90921496Ssklower } 91021496Ssklower if (nsp == NULL) { 91121496Ssklower if (req != PRU_ATTACH) { 91221496Ssklower error = EINVAL; 91321496Ssklower goto release; 91421496Ssklower } 91521496Ssklower } else 91621496Ssklower cb = nstosppcb(nsp); 91721496Ssklower 91821496Ssklower ostate = cb ? cb->s_state : 0; 91921496Ssklower 92021496Ssklower switch (req) { 92123515Ssklower 92221496Ssklower case PRU_ATTACH: 92321496Ssklower if (nsp != NULL) { 92421496Ssklower error = EISCONN; 92521496Ssklower break; 92621496Ssklower } 92721496Ssklower error = ns_pcballoc(so, &nspcb); 92821496Ssklower if (error) 92921496Ssklower break; 93021496Ssklower error = soreserve(so, 2048, 2048); 93121496Ssklower if (error) 93221496Ssklower break; 93321496Ssklower nsp = sotonspcb(so); 93421496Ssklower { 935*25037Ssklower struct mbuf *mm = m_getclr(M_DONTWAIT, MT_PCB); 93621496Ssklower 93724330Ssklower if (mm == NULL) { 93821496Ssklower error = ENOBUFS; 93921496Ssklower break; 94021496Ssklower } 94121496Ssklower cb = mtod(mm, struct sppcb *); 94221496Ssklower cb->s_state = TCPS_LISTEN; 94321496Ssklower cb->s_snt = -1; 94421496Ssklower cb->s_q.si_next = cb->s_q.si_prev = &cb->s_q; 94521496Ssklower cb->s_nspcb = nsp; 94621496Ssklower nsp->nsp_pcb = (caddr_t) cb; 94721496Ssklower } 94821496Ssklower break; 94921496Ssklower 95021496Ssklower case PRU_DETACH: 95121496Ssklower if (nsp == NULL) { 95221496Ssklower error = ENOTCONN; 95321496Ssklower break; 95421496Ssklower } 95521496Ssklower if (cb->s_state > TCPS_LISTEN) 95621496Ssklower cb = spp_disconnect(cb); 95721496Ssklower else 95821496Ssklower cb = spp_close(cb); 95921496Ssklower break; 96021496Ssklower 96121496Ssklower case PRU_BIND: 96221496Ssklower error = ns_pcbbind(nsp, nam); 96321496Ssklower break; 96421496Ssklower 96521496Ssklower case PRU_LISTEN: 96621496Ssklower if (nsp->nsp_lport == 0) 96721496Ssklower error = ns_pcbbind(nsp, (struct mbuf *)0); 96821496Ssklower if (error == 0) 96921496Ssklower cb->s_state = TCPS_LISTEN; 97021496Ssklower break; 97121496Ssklower 97221496Ssklower /* 97321496Ssklower * Initiate connection to peer. 97421496Ssklower * Enter SYN_SENT state, and mark socket as connecting. 97521496Ssklower * Start keep-alive timer, setup prototype header, 97621496Ssklower * Send initial system packet requesting connection. 97721496Ssklower */ 97821496Ssklower case PRU_CONNECT: 97921496Ssklower if (nsp->nsp_lport == 0) { 98021496Ssklower error = ns_pcbbind(nsp, (struct mbuf *)0); 98121496Ssklower if (error) 98221496Ssklower break; 98321496Ssklower } 98421496Ssklower error = ns_pcbconnect(nsp, nam); 98521496Ssklower if (error) 98621496Ssklower break; 98721496Ssklower soisconnecting(so); 98821496Ssklower cb->s_state = TCPS_SYN_SENT; 98921496Ssklower cb->s_did = 0; 99021496Ssklower spp_template(cb); 99121496Ssklower cb->s_timer[TCPT_KEEP] = TCPTV_KEEP; 99221496Ssklower cb->s_force = 1 + TCPTV_KEEP; 99321496Ssklower /* 99421496Ssklower * Other party is required to respond to 99521496Ssklower * the port I send from, but he is not 99621496Ssklower * required to answer from where I am sending to, 99721496Ssklower * so allow wildcarding. 99821496Ssklower * original port I am sending to is still saved in 99921496Ssklower * cb->s_dport. 100021496Ssklower */ 100121496Ssklower nsp->nsp_fport = 0; 100221496Ssklower error = spp_output(cb, (struct mbuf *) 0); 100321496Ssklower break; 100421496Ssklower 100521496Ssklower case PRU_CONNECT2: 100621496Ssklower error = EOPNOTSUPP; 100721496Ssklower break; 100821496Ssklower 100921496Ssklower /* 101021496Ssklower * We may decide later to implement connection closing 101121496Ssklower * handshaking at the spp level optionally. 101221496Ssklower * here is the hook to do it: 101321496Ssklower */ 101421496Ssklower case PRU_DISCONNECT: 101521496Ssklower cb = spp_disconnect(cb); 101621496Ssklower break; 101721496Ssklower 101821496Ssklower /* 101921496Ssklower * Accept a connection. Essentially all the work is 102021496Ssklower * done at higher levels; just return the address 102121496Ssklower * of the peer, storing through addr. 102221496Ssklower */ 102321496Ssklower case PRU_ACCEPT: { 102421496Ssklower struct sockaddr_ns *sns = mtod(nam, struct sockaddr_ns *); 102521496Ssklower 102621496Ssklower nam->m_len = sizeof (struct sockaddr_ns); 102721496Ssklower sns->sns_family = AF_NS; 102821496Ssklower sns->sns_addr = nsp->nsp_faddr; 102921496Ssklower break; 103021496Ssklower } 103121496Ssklower 103221496Ssklower case PRU_SHUTDOWN: 103321496Ssklower socantsendmore(so); 103421496Ssklower cb = spp_usrclosed(cb); 103521496Ssklower if (cb) 103621496Ssklower error = spp_output(cb, (struct mbuf *) 0); 103721496Ssklower break; 103821496Ssklower 103921496Ssklower /* 104021496Ssklower * After a receive, possibly send acknowledgment 104121496Ssklower * updating allocation. 104221496Ssklower */ 104321496Ssklower case PRU_RCVD: 104421496Ssklower (void) spp_output(cb, (struct mbuf *) 0); 104521496Ssklower break; 104621496Ssklower 104721496Ssklower case PRU_SEND: 104821496Ssklower error = spp_output(cb, m); 104921496Ssklower m = NULL; 105021496Ssklower break; 105121496Ssklower 105221496Ssklower case PRU_ABORT: 105324225Ssklower (void) spp_drop(cb, ECONNABORTED); 105421496Ssklower break; 105521496Ssklower 105621496Ssklower case PRU_SENSE: 105721496Ssklower case PRU_CONTROL: 105821496Ssklower m = NULL; 105921496Ssklower error = EOPNOTSUPP; 106021496Ssklower break; 106121496Ssklower 106221496Ssklower case PRU_RCVOOB: 1063*25037Ssklower if ((cb->s_oobflags & SF_IOOB) || so->so_oobmark || 1064*25037Ssklower (so->so_state & SS_RCVATMARK)) { 1065*25037Ssklower m->m_len = 1; 1066*25037Ssklower *mtod(m, caddr_t) = cb->s_iobc; 106724732Ssklower break; 106824732Ssklower } 1069*25037Ssklower error = EINVAL; 107021496Ssklower break; 107121496Ssklower 107221496Ssklower case PRU_SENDOOB: 107321496Ssklower if (sbspace(&so->so_snd) < -512) { 107421496Ssklower m_freem(m); 107521496Ssklower error = ENOBUFS; 107621496Ssklower break; 107721496Ssklower } 107821496Ssklower cb->s_oobflags |= SF_SOOB; 107921496Ssklower error = spp_output(cb, m); 108021496Ssklower m = NULL; 108121496Ssklower break; 108221496Ssklower 108321496Ssklower case PRU_SOCKADDR: 108421496Ssklower ns_setsockaddr(nsp, nam); 108521496Ssklower break; 108621496Ssklower 108721496Ssklower case PRU_PEERADDR: 108821496Ssklower ns_setpeeraddr(nsp, nam); 108921496Ssklower break; 109021496Ssklower 109121496Ssklower case PRU_SLOWTIMO: 109221496Ssklower cb = spp_timers(cb, (int)nam); 109321496Ssklower break; 109421496Ssklower 109521496Ssklower case PRU_FASTTIMO: 109621496Ssklower case PRU_PROTORCV: 109721496Ssklower case PRU_PROTOSEND: 109821496Ssklower error = EOPNOTSUPP; 109921496Ssklower break; 110021496Ssklower 110121496Ssklower default: 110221496Ssklower panic("sp_usrreq"); 110321496Ssklower } 110421496Ssklower if (cb && (so->so_options & SO_DEBUG || traceallspps)) 110524225Ssklower spp_trace(SA_USER, (u_char)ostate, cb, (struct spidp *)0, req); 110621496Ssklower release: 110721496Ssklower if (m != NULL) 110821496Ssklower m_freem(m); 110921496Ssklower splx(s); 111021496Ssklower return (error); 111121496Ssklower } 111221496Ssklower 111321496Ssklower spp_usrreq_sp(so, req, m, nam, rights) 111421496Ssklower struct socket *so; 111521496Ssklower int req; 111621496Ssklower struct mbuf *m, *nam, *rights; 111721496Ssklower { 111821496Ssklower int error = spp_usrreq(so, req, m, nam, rights); 111921496Ssklower 112024330Ssklower if (req == PRU_ATTACH && error == 0) { 112121496Ssklower struct nspcb *nsp = sotonspcb(so); 112221496Ssklower ((struct sppcb *)nsp->nsp_pcb)->s_flags |= 112321496Ssklower (SF_HI | SF_HO | SF_PI); 112421496Ssklower } 112523515Ssklower return (error); 112621496Ssklower } 112721496Ssklower 112821496Ssklower /* 112921496Ssklower * Create template to be used to send spp packets on a connection. 113021496Ssklower * Called after host entry created, fills 113121496Ssklower * in a skeletal spp header (choosing connection id), 113221496Ssklower * minimizing the amount of work necessary when the connection is used. 113321496Ssklower */ 113421496Ssklower spp_template(cb) 113521496Ssklower struct sppcb *cb; 113621496Ssklower { 113721496Ssklower register struct nspcb *nsp = cb->s_nspcb; 113821496Ssklower register struct spidp *n = &(cb->s_shdr); 113921496Ssklower 114024615Ssklower cb->s_mtu = 576 - sizeof (struct spidp); 114121496Ssklower n->si_pt = NSPROTO_SPP; 114221496Ssklower n->si_sna = nsp->nsp_laddr; 114321496Ssklower n->si_dna = nsp->nsp_faddr; 114421496Ssklower n->si_sid = htons(spp_iss); 114521496Ssklower spp_iss += SPP_ISSINCR/2; 114621496Ssklower n->si_alo = 1; 114721496Ssklower } 114821496Ssklower 114921496Ssklower /* 115021496Ssklower * Close a SPIP control block: 115121496Ssklower * discard spp control block itself 115221496Ssklower * discard ns protocol control block 115321496Ssklower * wake up any sleepers 115421496Ssklower */ 115521496Ssklower struct sppcb * 115621496Ssklower spp_close(cb) 115721496Ssklower register struct sppcb *cb; 115821496Ssklower { 115921496Ssklower register struct spidp_q *s; 116021496Ssklower struct nspcb *nsp = cb->s_nspcb; 116121496Ssklower struct socket *so = nsp->nsp_socket; 116221496Ssklower register struct mbuf *m; 116321496Ssklower 116421496Ssklower s = cb->s_q.si_next; 116521496Ssklower while (s != &(cb->s_q)) { 116621496Ssklower s = s->si_next; 116721496Ssklower m = dtom(s->si_prev); 116821496Ssklower remque(s->si_prev); 116921496Ssklower m_freem(m); 117021496Ssklower } 117121496Ssklower (void) m_free(dtom(cb)); 117221496Ssklower nsp->nsp_pcb = 0; 117321496Ssklower soisdisconnected(so); 117421496Ssklower ns_pcbdetach(nsp); 117523515Ssklower return ((struct sppcb *)0); 117621496Ssklower } 117721496Ssklower /* 117821496Ssklower * Someday we may do level 3 handshaking 117921496Ssklower * to close a connection or send a xerox style error. 118021496Ssklower * For now, just close. 118121496Ssklower */ 118221496Ssklower struct sppcb * 118321496Ssklower spp_usrclosed(cb) 118421496Ssklower register struct sppcb *cb; 118521496Ssklower { 118623515Ssklower return (spp_close(cb)); 118721496Ssklower } 118821496Ssklower struct sppcb * 118921496Ssklower spp_disconnect(cb) 119021496Ssklower register struct sppcb *cb; 119121496Ssklower { 119223515Ssklower return (spp_close(cb)); 119321496Ssklower } 119421496Ssklower /* 119521496Ssklower * Drop connection, reporting 119621496Ssklower * the specified error. 119721496Ssklower */ 119821496Ssklower struct sppcb * 119921496Ssklower spp_drop(cb, errno) 120021496Ssklower register struct sppcb *cb; 120121496Ssklower int errno; 120221496Ssklower { 120321496Ssklower struct socket *so = cb->s_nspcb->nsp_socket; 120421496Ssklower 120521496Ssklower /* 120621496Ssklower * someday, in the xerox world 120721496Ssklower * we will generate error protocol packets 120821496Ssklower * announcing that the socket has gone away. 120921496Ssklower */ 121021496Ssklower /*if (TCPS_HAVERCVDSYN(tp->t_state)) { 121121496Ssklower tp->t_state = TCPS_CLOSED; 121221496Ssklower (void) tcp_output(tp); 121321496Ssklower }*/ 121421496Ssklower so->so_error = errno; 121521496Ssklower return (spp_close(cb)); 121621496Ssklower } 121721496Ssklower 121821496Ssklower spp_abort(nsp) 121921496Ssklower struct nspcb *nsp; 122021496Ssklower { 122121496Ssklower 122224225Ssklower (void) spp_close((struct sppcb *)nsp->nsp_pcb); 122321496Ssklower } 122421496Ssklower 122521496Ssklower spp_setpersist(cb) 122621496Ssklower register struct sppcb *cb; 122721496Ssklower { 122821496Ssklower 122921496Ssklower /*if (cb->s_timer[TCPT_REXMT]) 123021496Ssklower panic("spp_output REXMT");*/ 123121496Ssklower /* 123221496Ssklower * Start/restart persistance timer. 123321496Ssklower */ 123421496Ssklower TCPT_RANGESET(cb->s_timer[TCPT_PERSIST], 123521496Ssklower ((int)(tcp_beta * cb->s_srtt)) << cb->s_rxtshift, 123621496Ssklower TCPTV_PERSMIN, TCPTV_MAX); 123721496Ssklower cb->s_rxtshift++; 123821496Ssklower if (cb->s_rxtshift >= TCP_MAXRXTSHIFT) 123921496Ssklower cb->s_rxtshift = 0; 124021496Ssklower } 124121496Ssklower /* 124221496Ssklower * Fast timeout routine for processing delayed acks 124321496Ssklower */ 124421496Ssklower int spp_ftcnt; 124521496Ssklower spp_fasttimo() 124621496Ssklower { 124721496Ssklower register struct nspcb *nsp; 124821496Ssklower register struct sppcb *cb; 124921496Ssklower int s = splnet(); 125021496Ssklower 125121496Ssklower nsp = nspcb.nsp_next; 125221496Ssklower spp_ftcnt++; 125321496Ssklower if (nsp) 125421496Ssklower for (; nsp != &nspcb; nsp = nsp->nsp_next) 125521496Ssklower if ((cb = (struct sppcb *)nsp->nsp_pcb) && 125621496Ssklower (cb->s_flags & SF_DELACK)) { 125721496Ssklower cb->s_flags &= ~SF_DELACK; 125821496Ssklower cb->s_flags |= SF_AK; 125921496Ssklower (void) spp_output(cb, (struct mbuf *) 0); 126021496Ssklower } 126121496Ssklower splx(s); 126221496Ssklower } 126321496Ssklower 126421496Ssklower /* 126521496Ssklower * spp protocol timeout routine called every 500 ms. 126621496Ssklower * Updates the timers in all active pcb's and 126721496Ssklower * causes finite state machine actions if timers expire. 126821496Ssklower */ 126921496Ssklower spp_slowtimo() 127021496Ssklower { 127121496Ssklower register struct nspcb *ip, *ipnxt; 127221496Ssklower register struct sppcb *cb; 127321496Ssklower int s = splnet(); 127421496Ssklower register int i; 127521496Ssklower 127621496Ssklower /* 127721496Ssklower * Search through tcb's and update active timers. 127821496Ssklower */ 127921496Ssklower ip = nspcb.nsp_next; 128021496Ssklower if (ip == 0) { 128121496Ssklower splx(s); 128221496Ssklower return; 128321496Ssklower } 128421496Ssklower while (ip != &nspcb) { 128521496Ssklower cb = nstosppcb(ip); 128621496Ssklower ipnxt = ip->nsp_next; 128721496Ssklower if (cb == 0) 128821496Ssklower goto tpgone; 128921496Ssklower for (i = 0; i < TCPT_NTIMERS; i++) { 129021496Ssklower if (cb->s_timer[i] && --cb->s_timer[i] == 0) { 129121496Ssklower (void) spp_usrreq(cb->s_nspcb->nsp_socket, 129221496Ssklower PRU_SLOWTIMO, (struct mbuf *)0, 129321496Ssklower (struct mbuf *)i, (struct mbuf *)0); 129421496Ssklower if (ipnxt->nsp_prev != ip) 129521496Ssklower goto tpgone; 129621496Ssklower } 129721496Ssklower } 129821496Ssklower cb->s_idle++; 129921496Ssklower if (cb->s_rtt) 130021496Ssklower cb->s_rtt++; 130121496Ssklower tpgone: 130221496Ssklower ip = ipnxt; 130321496Ssklower } 130421496Ssklower spp_iss += SPP_ISSINCR/PR_SLOWHZ; /* increment iss */ 130521496Ssklower splx(s); 130621496Ssklower } 130721496Ssklower 130821496Ssklower float spp_backoff[TCP_MAXRXTSHIFT] = 130921496Ssklower { 1.0, 1.2, 1.4, 1.7, 2.0, 3.0, 5.0, 8.0, 16.0, 32.0 }; 131024412Swalsh int sppexprexmtbackoff = 0; 131121496Ssklower /* 131224615Ssklower * SPP timer processing. 131321496Ssklower */ 131421496Ssklower struct sppcb * 131521496Ssklower spp_timers(cb, timer) 131621496Ssklower register struct sppcb *cb; 131721496Ssklower int timer; 131821496Ssklower { 131921496Ssklower 132021496Ssklower cb->s_force = 1 + timer; 132121496Ssklower switch (timer) { 132221496Ssklower 132321496Ssklower /* 132421496Ssklower * 2 MSL timeout in shutdown went off. Delete connection 132521496Ssklower * control block. 132621496Ssklower */ 132721496Ssklower case TCPT_2MSL: 132821496Ssklower cb = spp_close(cb); 132921496Ssklower break; 133021496Ssklower 133121496Ssklower /* 133221496Ssklower * Retransmission timer went off. Message has not 133321496Ssklower * been acked within retransmit interval. Back off 133421496Ssklower * to a longer retransmit interval and retransmit all 133521496Ssklower * unacknowledged messages in the window. 133621496Ssklower */ 133721496Ssklower case TCPT_REXMT: 133821496Ssklower cb->s_rxtshift++; 133921496Ssklower if (cb->s_rxtshift > TCP_MAXRXTSHIFT) { 134021496Ssklower cb = spp_drop(cb, ETIMEDOUT); 134121496Ssklower break; 134221496Ssklower } 134321496Ssklower (void) spp_output(cb, (struct mbuf *) 0); 134421496Ssklower TCPT_RANGESET(cb->s_timer[TCPT_REXMT], 134521496Ssklower (int)cb->s_srtt, TCPTV_MIN, TCPTV_MAX); 134624412Swalsh if (sppexprexmtbackoff) { 134721496Ssklower TCPT_RANGESET(cb->s_timer[TCPT_REXMT], 134821496Ssklower cb->s_timer[TCPT_REXMT] << cb->s_rxtshift, 134921496Ssklower TCPTV_MIN, TCPTV_MAX); 135021496Ssklower } else { 135121496Ssklower TCPT_RANGESET(cb->s_timer[TCPT_REXMT], 135221496Ssklower cb->s_timer[TCPT_REXMT] * 135321496Ssklower spp_backoff[cb->s_rxtshift - 1], 135421496Ssklower TCPTV_MIN, TCPTV_MAX); 135521496Ssklower } 135621496Ssklower break; 135721496Ssklower 135821496Ssklower /* 135921496Ssklower * Persistance timer into zero window. 136021496Ssklower * Force a probe to be sent. 136121496Ssklower */ 136221496Ssklower case TCPT_PERSIST: 136321496Ssklower (void) spp_output(cb, (struct mbuf *) 0); 136421496Ssklower spp_setpersist(cb); 136521496Ssklower break; 136621496Ssklower 136721496Ssklower /* 136821496Ssklower * Keep-alive timer went off; send something 136921496Ssklower * or drop connection if idle for too long. 137021496Ssklower */ 137121496Ssklower case TCPT_KEEP: 137221496Ssklower if (cb->s_state < TCPS_ESTABLISHED) 137321496Ssklower goto dropit; 137421496Ssklower if (cb->s_nspcb->nsp_socket->so_options & SO_KEEPALIVE) { 137521496Ssklower if (cb->s_idle >= TCPTV_MAXIDLE) 137621496Ssklower goto dropit; 137721496Ssklower (void) spp_output(cb, (struct mbuf *) 0); 137821496Ssklower } else 137921496Ssklower cb->s_idle = 0; 138021496Ssklower cb->s_timer[TCPT_KEEP] = TCPTV_KEEP; 138121496Ssklower break; 138221496Ssklower dropit: 138321496Ssklower cb = spp_drop(cb, ETIMEDOUT); 138421496Ssklower break; 138521496Ssklower } 138621496Ssklower return (cb); 138721496Ssklower } 1388