123215Smckusick /* 225334Ssklower * Copyright (c) 1984, 1985 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*25623Ssklower * @(#)spp_usrreq.c 6.16 (Berkeley) 12/18/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; 4525037Ssklower 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 20825037Ssklower if (spp_reass(cb, si)) { 20925334Ssklower m_freem(m); 21021496Ssklower } 21125037Ssklower (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 */ 23725037Ssklower 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) 25525037Ssklower cb->s_flags |= (spp_use_delack ? SF_DELACK : SF_AK); 25625037Ssklower if (SSEQ_GT(si->si_ack, cb->s_rack)) { 25721496Ssklower cb->s_rack = si->si_ack; 25821496Ssklower /* 25925037Ssklower * If there are other packets outstanding, 26025037Ssklower * restart the timer for them. 26125037Ssklower */ 26225037Ssklower if (SSEQ_GEQ(cb->s_snt, si->si_ack)) { 26325037Ssklower TCPT_RANGESET(cb->s_timer[TCPT_REXMT], 26425037Ssklower tcp_beta * cb->s_srtt, TCPTV_MIN, 26525037Ssklower TCPTV_MAX); 26625037Ssklower cb->s_rxtshift = 0; 26725037Ssklower } else 26825037Ssklower cb->s_timer[TCPT_REXMT] = 0; 26925037Ssklower /* 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 } 28325037Ssklower 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 */ 30125037Ssklower 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 */ 31125037Ssklower if (SSEQ_GT(si->si_seq, cb->s_alo)) { 31225037Ssklower if (si->si_cc & SP_OB) { 31325037Ssklower if (SSEQ_GT(si->si_seq, cb->s_alo + 60)) { 31425037Ssklower ns_error(dtom(si), NS_ERR_FULLUP, 0); 31525037Ssklower return (0); 31625037Ssklower } /* else queue this packet; */ 31725037Ssklower } else { 31825037Ssklower spp_istat.notyet++; 31925037Ssklower return (1); 32025037Ssklower } 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 */ 33025037Ssklower if (SSEQ_LT(si->si_seq, SI(q)->si_seq)) break; 33121496Ssklower } 33225037Ssklower insque(si, q->si_prev); 33325037Ssklower /* 33425037Ssklower * If this packet is urgent, inform process 33525037Ssklower */ 33625037Ssklower if (si->si_cc & SP_OB) { 33725037Ssklower cb->s_iobc = ((char *)si)[1 + sizeof(*si)]; 33825037Ssklower sohasoutofband(so); 33925037Ssklower cb->s_oobflags |= SF_IOOB; 34025037Ssklower } 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) { 35325037Ssklower 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) { 36325037Ssklower sbappendrecord(sb, m); 36421496Ssklower } else { 36521496Ssklower cb->s_rhdr = *mtod(m, struct sphdr *); 36621496Ssklower m->m_off += SPINC; 36721496Ssklower m->m_len -= SPINC; 36825037Ssklower 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. 568*25623Ssklower * Long align so prepended ip headers will work on Gould. 56921496Ssklower */ 570*25623Ssklower m->m_off = MMAXOFF - sizeof (struct spidp) - 2; 57121496Ssklower m->m_len = sizeof (struct spidp); 57221496Ssklower m->m_next = m0; 57321496Ssklower si = mtod(m, struct spidp *); 57421496Ssklower *si = cb->s_shdr; 57521496Ssklower if ((cb->s_flags & SF_PI) && (cb->s_flags & SF_HO)) { 57624330Ssklower register struct sphdr *sh; 57724330Ssklower if (m0->m_len < sizeof (*sh)) { 57824330Ssklower if((m0 = m_pullup(m0, sizeof(*sh))) == NULL) { 57924330Ssklower (void) m_free(m); 58024330Ssklower m_freem(m0); 58124330Ssklower return (EINVAL); 58224330Ssklower } 58324330Ssklower m->m_next = m0; 58424330Ssklower } 58524330Ssklower sh = mtod(m0, struct sphdr *); 58621496Ssklower si->si_dt = sh->sp_dt; 58721496Ssklower si->si_cc |= sh->sp_cc & SP_EM; 58821496Ssklower m0->m_len -= sizeof (*sh); 58921496Ssklower m0->m_off += sizeof (*sh); 59021496Ssklower len -= sizeof (*sh); 59121496Ssklower } 59221496Ssklower len += sizeof(*si); 59323979Ssklower if (cb->s_oobflags & SF_SOOB) { 59423979Ssklower /* 59523979Ssklower * Per jqj@cornell: 59623979Ssklower * make sure OB packets convey exactly 1 byte. 59723979Ssklower * If the packet is 1 byte or larger, we 59823979Ssklower * have already guaranted there to be at least 59923979Ssklower * one garbage byte for the checksum, and 60023979Ssklower * extra bytes shouldn't hurt! 60123979Ssklower */ 60223979Ssklower if (len > sizeof(*si)) { 60323979Ssklower si->si_cc |= SP_OB; 60423979Ssklower len = (1 + sizeof(*si)); 60523979Ssklower } 60623979Ssklower } 60724225Ssklower si->si_len = htons((u_short)len); 60821496Ssklower /* 60921496Ssklower * queue stuff up for output 61021496Ssklower */ 61125037Ssklower sbappendrecord(sb, m); 61221496Ssklower cb->s_seq++; 61321496Ssklower } 61421496Ssklower /* 61521496Ssklower * update window 61621496Ssklower */ 61721496Ssklower { 61824225Ssklower register struct sockbuf *sb2 = &so->so_rcv; 619*25623Ssklower int credit = ((((int)sb2->sb_mbmax) - (int)sb2->sb_mbcnt) / 62024732Ssklower ((short)cb->s_mtu)); 62124732Ssklower int alo = cb->s_ack + (credit > 0 ? credit : 0) - 1; 62221496Ssklower 62324732Ssklower if (cb->s_alo < alo) { 62424732Ssklower /* If the amount we are raising the window 62524732Ssklower is more than his remaining headroom, tell 62624732Ssklower him about it. In particular, if he is at 62724732Ssklower his limit, any amount at all will do! */ 62824732Ssklower u_short raise = alo - cb->s_alo; 62924732Ssklower u_short headroom = 1 + cb->s_alo - cb->s_ack; 63024732Ssklower 63124732Ssklower if(SSEQ_LT(headroom, raise)) 63224732Ssklower cb->s_flags |= SF_AK; 63324330Ssklower cb->s_alo = alo; 63424732Ssklower } 63521496Ssklower } 63621496Ssklower 63721496Ssklower if (cb->s_oobflags & SF_SOOB) { 63821496Ssklower /* 63921496Ssklower * must transmit this out of band packet 64021496Ssklower */ 64121496Ssklower cb->s_oobflags &= ~ SF_SOOB; 64221496Ssklower } else { 64321496Ssklower /* 64421496Ssklower * Decide what to transmit: 64525168Ssklower * If it is time to retransmit a packet, 64625168Ssklower * send that. 64721496Ssklower * If we have a new packet, send that 64821496Ssklower * (So long as it is in our allocation) 64921496Ssklower * Otherwise, see if it time to bang on them 65021496Ssklower * to ask for our current allocation. 65121496Ssklower */ 65225168Ssklower if (cb->s_force == (1+TCPT_REXMT)) { 65325168Ssklower lookfor = cb->s_rack; 65425168Ssklower } else if (SSEQ_LT(cb->s_snt, cb->s_ralo)) { 65521496Ssklower lookfor = cb->s_snt + 1; 65621496Ssklower } else if (SSEQ_LT(cb->s_ralo, cb->s_seq)) { 65721496Ssklower lookfor = 0; 65824330Ssklower if (cb->s_timer[TCPT_PERSIST] == 0) { 65921496Ssklower spp_setpersist(cb); 66024330Ssklower /* tcp has cb->s_rxtshift = 0; here */ 66121496Ssklower } 66221496Ssklower } 66321496Ssklower m = sb->sb_mb; 66424330Ssklower while (m) { 66521496Ssklower si = mtod(m, struct spidp *); 66621496Ssklower m = m->m_act; 66721496Ssklower if (SSEQ_LT(si->si_seq, cb->s_rack)) { 66821496Ssklower if ((sb->sb_flags & SB_WAIT) 66921496Ssklower || so->so_snd.sb_sel) 67021496Ssklower sowwakeup(so); 67121496Ssklower sbdroprecord(sb); 67221496Ssklower si = 0; 67321496Ssklower continue; 67421496Ssklower } 67521496Ssklower if (SSEQ_LT(si->si_seq, lookfor)) 67621496Ssklower continue; 67721496Ssklower break; 67821496Ssklower } 67924330Ssklower if (si && (si->si_seq != lookfor)) 68024330Ssklower si = 0; 68121496Ssklower } 68221496Ssklower cb->s_want = lookfor; 68321496Ssklower 68421496Ssklower if (si) { 68521496Ssklower /* 68621496Ssklower * must make a copy of this packet for 68721496Ssklower * idp_output to monkey with 68821496Ssklower */ 68924330Ssklower m = m_copy(dtom(si), 0, (int)M_COPYALL); 69024330Ssklower if (m == NULL) 69123515Ssklower return (ENOBUFS); 69223515Ssklower m0 = m; 69321496Ssklower si = mtod(m, struct spidp *); 69421496Ssklower } else if (cb->s_force || cb->s_flags & SF_AK) { 69521496Ssklower /* 69621496Ssklower * Must send an acknowledgement or a probe 69721496Ssklower */ 69821496Ssklower m = m_get(M_DONTWAIT, MT_HEADER); 69921496Ssklower if (m == 0) 70023515Ssklower return (ENOBUFS); 70121496Ssklower /* 70221496Ssklower * Fill in mbuf with extended SP header 70321496Ssklower * and addresses and length put into network format. 70421496Ssklower */ 70521496Ssklower m->m_off = MMAXOFF - sizeof (struct spidp); 70621496Ssklower m->m_len = sizeof (*si); 70721496Ssklower m->m_next = 0; 70821496Ssklower si = mtod(m, struct spidp *); 70921496Ssklower *si = cb->s_shdr; 71021496Ssklower si->si_seq = cb->s_snt + 1; 71123979Ssklower si->si_len = htons(sizeof (*si)); 71221496Ssklower si->si_cc |= SP_SP; 71321496Ssklower } 71421496Ssklower /* 71521496Ssklower * Stuff checksum and output datagram. 71621496Ssklower */ 71721496Ssklower if (si) { 71825037Ssklower if (cb->s_flags & (SF_AK|SF_DELACK)) 71925037Ssklower cb->s_flags &= ~(SF_AK|SF_DELACK); 72021496Ssklower /* 72121496Ssklower * If we are almost out of allocation 72221496Ssklower * or one of the timers has gone off 72321496Ssklower * request an ack. 72421496Ssklower */ 72524330Ssklower if (SSEQ_GEQ(cb->s_seq, cb->s_ralo)) 72621496Ssklower si->si_cc |= SP_SA; 72721496Ssklower if (cb->s_force) { 72821496Ssklower si->si_cc |= SP_SA; 72921496Ssklower cb->s_force = 0; 73021496Ssklower } 73124330Ssklower /* 73224330Ssklower * If this is a new packet (and not a system packet), 73323979Ssklower * and we are not currently timing anything, 73423979Ssklower * time this one and ask for an ack. 73521496Ssklower */ 73624330Ssklower if (SSEQ_LT(cb->s_snt, si->si_seq) && (!(si->si_cc & SP_SP))) { 73721496Ssklower cb->s_snt = si->si_seq; 73824330Ssklower if (cb->s_rtt == 0) { 73921496Ssklower cb->s_rtseq = si->si_seq; 74021496Ssklower cb->s_rtt = 1; 74121496Ssklower si->si_cc |= SP_SA; 74221496Ssklower } 74321496Ssklower /* 74421496Ssklower * If the retransmit timer has not been set 74521496Ssklower * and this is a real packet 74621496Ssklower * then start the retransmit timer 74721496Ssklower */ 74824330Ssklower if (cb->s_timer[TCPT_REXMT] == 0) { 74921496Ssklower TCPT_RANGESET(cb->s_timer[TCPT_REXMT], 75021496Ssklower tcp_beta * cb->s_srtt, TCPTV_MIN, 75121496Ssklower TCPTV_MAX); 75221496Ssklower cb->s_rxtshift = 0; 75321496Ssklower } 75421496Ssklower } 75521496Ssklower si->si_seq = htons(si->si_seq); 75621496Ssklower si->si_alo = htons(cb->s_alo); 75721496Ssklower si->si_ack = htons(cb->s_ack); 75821496Ssklower 75921496Ssklower if (idpcksum) { 76021496Ssklower si->si_sum = 0; 76123979Ssklower len = ntohs(si->si_len); 76224330Ssklower if (len & 1) 76324330Ssklower len++; 76421496Ssklower si->si_sum = ns_cksum(dtom(si), len); 76521496Ssklower } else 76621496Ssklower si->si_sum = 0xffff; 76721496Ssklower 76821496Ssklower if (so->so_options & SO_DEBUG || traceallspps) 76921496Ssklower spp_trace(SA_OUTPUT, cb->s_state, cb, si, 0); 77021496Ssklower spp_output_cnt++; 77121496Ssklower if (so->so_options & SO_DONTROUTE) 77221496Ssklower error = ns_output(m, (struct route *)0, NS_ROUTETOIF); 77321496Ssklower else 77421496Ssklower error = ns_output(m, &cb->s_nspcb->nsp_route, 0); 77521496Ssklower if (traceallspps && sppconsdebug) { 77621496Ssklower printf("spp_out: %x\n", error); 77721496Ssklower } 77825168Ssklower if (so->so_options & SO_DEBUG || traceallspps) 77925168Ssklower spp_trace(SA_OUTPUT, cb->s_state, cb, si, 0); 78021496Ssklower } 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; 84525334Ssklower break; 84625334Ssklower 84725334Ssklower default: 84825334Ssklower error = EINVAL; 84921496Ssklower } 85021496Ssklower *value = m; 85121496Ssklower break; 85223515Ssklower 85321496Ssklower case PRCO_SETOPT: 85424615Ssklower if (value == 0 || *value == 0) { 85524615Ssklower error = EINVAL; 85624615Ssklower break; 85724615Ssklower } 85821496Ssklower switch (name) { 85924225Ssklower int *ok; 86021496Ssklower 86121496Ssklower case SO_HEADERS_ON_INPUT: 86221496Ssklower mask = SF_HI; 86321496Ssklower goto set_head; 86423515Ssklower 86521496Ssklower case SO_HEADERS_ON_OUTPUT: 86621496Ssklower mask = SF_HO; 86721496Ssklower set_head: 86824615Ssklower if (cb->s_flags & SF_PI) { 86921496Ssklower ok = mtod(*value, int *); 87021496Ssklower if (*ok) 87121496Ssklower cb->s_flags |= mask; 87221496Ssklower else 87321496Ssklower cb->s_flags &= ~mask; 87421496Ssklower } else error = EINVAL; 87521496Ssklower break; 87623515Ssklower 87724615Ssklower case SO_MTU: 87824615Ssklower cb->s_mtu = *(mtod(*value, u_short *)); 87924615Ssklower break; 88024615Ssklower 88121496Ssklower case SO_DEFAULT_HEADERS: 88221496Ssklower { 88321496Ssklower register struct sphdr *sp 88421496Ssklower = mtod(*value, struct sphdr *); 88521496Ssklower cb->s_dt = sp->sp_dt; 88621496Ssklower cb->s_cc = sp->sp_cc & SP_EM; 88721496Ssklower } 88825334Ssklower break; 88925334Ssklower 89025334Ssklower default: 89125334Ssklower error = EINVAL; 89221496Ssklower } 89324615Ssklower m_freem(*value); 89421496Ssklower break; 89521496Ssklower } 89621496Ssklower release: 89723515Ssklower return (error); 89821496Ssklower } 89921496Ssklower 90021496Ssklower /*ARGSUSED*/ 90121496Ssklower spp_usrreq(so, req, m, nam, rights) 90221496Ssklower struct socket *so; 90321496Ssklower int req; 90421496Ssklower struct mbuf *m, *nam, *rights; 90521496Ssklower { 90621496Ssklower struct nspcb *nsp = sotonspcb(so); 90721496Ssklower register struct sppcb *cb; 90821496Ssklower int s = splnet(); 90921496Ssklower int error = 0, ostate; 91021496Ssklower 91121496Ssklower if (req == PRU_CONTROL) 91221496Ssklower return (ns_control(so, (int)m, (caddr_t)nam, 91321496Ssklower (struct ifnet *)rights)); 91421496Ssklower if (rights && rights->m_len) { 91521496Ssklower error = EINVAL; 91621496Ssklower goto release; 91721496Ssklower } 91821496Ssklower if (nsp == NULL) { 91921496Ssklower if (req != PRU_ATTACH) { 92021496Ssklower error = EINVAL; 92121496Ssklower goto release; 92221496Ssklower } 92321496Ssklower } else 92421496Ssklower cb = nstosppcb(nsp); 92521496Ssklower 92621496Ssklower ostate = cb ? cb->s_state : 0; 92721496Ssklower 92821496Ssklower switch (req) { 92923515Ssklower 93021496Ssklower case PRU_ATTACH: 93121496Ssklower if (nsp != NULL) { 93221496Ssklower error = EISCONN; 93321496Ssklower break; 93421496Ssklower } 93521496Ssklower error = ns_pcballoc(so, &nspcb); 93621496Ssklower if (error) 93721496Ssklower break; 93821496Ssklower error = soreserve(so, 2048, 2048); 93921496Ssklower if (error) 94021496Ssklower break; 94121496Ssklower nsp = sotonspcb(so); 94221496Ssklower { 94325037Ssklower struct mbuf *mm = m_getclr(M_DONTWAIT, MT_PCB); 94421496Ssklower 94524330Ssklower if (mm == NULL) { 94621496Ssklower error = ENOBUFS; 94721496Ssklower break; 94821496Ssklower } 94921496Ssklower cb = mtod(mm, struct sppcb *); 95021496Ssklower cb->s_state = TCPS_LISTEN; 95121496Ssklower cb->s_snt = -1; 95221496Ssklower cb->s_q.si_next = cb->s_q.si_prev = &cb->s_q; 95321496Ssklower cb->s_nspcb = nsp; 95421496Ssklower nsp->nsp_pcb = (caddr_t) cb; 95521496Ssklower } 95621496Ssklower break; 95721496Ssklower 95821496Ssklower case PRU_DETACH: 95921496Ssklower if (nsp == NULL) { 96021496Ssklower error = ENOTCONN; 96121496Ssklower break; 96221496Ssklower } 96321496Ssklower if (cb->s_state > TCPS_LISTEN) 96421496Ssklower cb = spp_disconnect(cb); 96521496Ssklower else 96621496Ssklower cb = spp_close(cb); 96721496Ssklower break; 96821496Ssklower 96921496Ssklower case PRU_BIND: 97021496Ssklower error = ns_pcbbind(nsp, nam); 97121496Ssklower break; 97221496Ssklower 97321496Ssklower case PRU_LISTEN: 97421496Ssklower if (nsp->nsp_lport == 0) 97521496Ssklower error = ns_pcbbind(nsp, (struct mbuf *)0); 97621496Ssklower if (error == 0) 97721496Ssklower cb->s_state = TCPS_LISTEN; 97821496Ssklower break; 97921496Ssklower 98021496Ssklower /* 98121496Ssklower * Initiate connection to peer. 98221496Ssklower * Enter SYN_SENT state, and mark socket as connecting. 98321496Ssklower * Start keep-alive timer, setup prototype header, 98421496Ssklower * Send initial system packet requesting connection. 98521496Ssklower */ 98621496Ssklower case PRU_CONNECT: 98721496Ssklower if (nsp->nsp_lport == 0) { 98821496Ssklower error = ns_pcbbind(nsp, (struct mbuf *)0); 98921496Ssklower if (error) 99021496Ssklower break; 99121496Ssklower } 99221496Ssklower error = ns_pcbconnect(nsp, nam); 99321496Ssklower if (error) 99421496Ssklower break; 99521496Ssklower soisconnecting(so); 99621496Ssklower cb->s_state = TCPS_SYN_SENT; 99721496Ssklower cb->s_did = 0; 99821496Ssklower spp_template(cb); 99921496Ssklower cb->s_timer[TCPT_KEEP] = TCPTV_KEEP; 100021496Ssklower cb->s_force = 1 + TCPTV_KEEP; 100121496Ssklower /* 100221496Ssklower * Other party is required to respond to 100321496Ssklower * the port I send from, but he is not 100421496Ssklower * required to answer from where I am sending to, 100521496Ssklower * so allow wildcarding. 100621496Ssklower * original port I am sending to is still saved in 100721496Ssklower * cb->s_dport. 100821496Ssklower */ 100921496Ssklower nsp->nsp_fport = 0; 101021496Ssklower error = spp_output(cb, (struct mbuf *) 0); 101121496Ssklower break; 101221496Ssklower 101321496Ssklower case PRU_CONNECT2: 101421496Ssklower error = EOPNOTSUPP; 101521496Ssklower break; 101621496Ssklower 101721496Ssklower /* 101821496Ssklower * We may decide later to implement connection closing 101921496Ssklower * handshaking at the spp level optionally. 102021496Ssklower * here is the hook to do it: 102121496Ssklower */ 102221496Ssklower case PRU_DISCONNECT: 102321496Ssklower cb = spp_disconnect(cb); 102421496Ssklower break; 102521496Ssklower 102621496Ssklower /* 102721496Ssklower * Accept a connection. Essentially all the work is 102821496Ssklower * done at higher levels; just return the address 102921496Ssklower * of the peer, storing through addr. 103021496Ssklower */ 103121496Ssklower case PRU_ACCEPT: { 103221496Ssklower struct sockaddr_ns *sns = mtod(nam, struct sockaddr_ns *); 103321496Ssklower 103421496Ssklower nam->m_len = sizeof (struct sockaddr_ns); 103521496Ssklower sns->sns_family = AF_NS; 103621496Ssklower sns->sns_addr = nsp->nsp_faddr; 103721496Ssklower break; 103821496Ssklower } 103921496Ssklower 104021496Ssklower case PRU_SHUTDOWN: 104121496Ssklower socantsendmore(so); 104221496Ssklower cb = spp_usrclosed(cb); 104321496Ssklower if (cb) 104421496Ssklower error = spp_output(cb, (struct mbuf *) 0); 104521496Ssklower break; 104621496Ssklower 104721496Ssklower /* 104821496Ssklower * After a receive, possibly send acknowledgment 104921496Ssklower * updating allocation. 105021496Ssklower */ 105121496Ssklower case PRU_RCVD: 105221496Ssklower (void) spp_output(cb, (struct mbuf *) 0); 105321496Ssklower break; 105421496Ssklower 105521496Ssklower case PRU_ABORT: 105624225Ssklower (void) spp_drop(cb, ECONNABORTED); 105721496Ssklower break; 105821496Ssklower 105921496Ssklower case PRU_SENSE: 106021496Ssklower case PRU_CONTROL: 106121496Ssklower m = NULL; 106221496Ssklower error = EOPNOTSUPP; 106321496Ssklower break; 106421496Ssklower 106521496Ssklower case PRU_RCVOOB: 106625037Ssklower if ((cb->s_oobflags & SF_IOOB) || so->so_oobmark || 106725037Ssklower (so->so_state & SS_RCVATMARK)) { 106825037Ssklower m->m_len = 1; 106925037Ssklower *mtod(m, caddr_t) = cb->s_iobc; 107024732Ssklower break; 107124732Ssklower } 107225037Ssklower error = EINVAL; 107321496Ssklower break; 107421496Ssklower 107521496Ssklower case PRU_SENDOOB: 107621496Ssklower if (sbspace(&so->so_snd) < -512) { 107721496Ssklower error = ENOBUFS; 107821496Ssklower break; 107921496Ssklower } 108021496Ssklower cb->s_oobflags |= SF_SOOB; 1081*25623Ssklower /* fall into */ 1082*25623Ssklower case PRU_SEND: 108321496Ssklower error = spp_output(cb, m); 108421496Ssklower m = NULL; 108521496Ssklower break; 108621496Ssklower 108721496Ssklower case PRU_SOCKADDR: 108821496Ssklower ns_setsockaddr(nsp, nam); 108921496Ssklower break; 109021496Ssklower 109121496Ssklower case PRU_PEERADDR: 109221496Ssklower ns_setpeeraddr(nsp, nam); 109321496Ssklower break; 109421496Ssklower 109521496Ssklower case PRU_SLOWTIMO: 109621496Ssklower cb = spp_timers(cb, (int)nam); 109721496Ssklower break; 109821496Ssklower 109921496Ssklower case PRU_FASTTIMO: 110021496Ssklower case PRU_PROTORCV: 110121496Ssklower case PRU_PROTOSEND: 110221496Ssklower error = EOPNOTSUPP; 110321496Ssklower break; 110421496Ssklower 110521496Ssklower default: 110621496Ssklower panic("sp_usrreq"); 110721496Ssklower } 110821496Ssklower if (cb && (so->so_options & SO_DEBUG || traceallspps)) 110924225Ssklower spp_trace(SA_USER, (u_char)ostate, cb, (struct spidp *)0, req); 111021496Ssklower release: 111121496Ssklower if (m != NULL) 111221496Ssklower m_freem(m); 111321496Ssklower splx(s); 111421496Ssklower return (error); 111521496Ssklower } 111621496Ssklower 111721496Ssklower spp_usrreq_sp(so, req, m, nam, rights) 111821496Ssklower struct socket *so; 111921496Ssklower int req; 112021496Ssklower struct mbuf *m, *nam, *rights; 112121496Ssklower { 112221496Ssklower int error = spp_usrreq(so, req, m, nam, rights); 112321496Ssklower 112424330Ssklower if (req == PRU_ATTACH && error == 0) { 112521496Ssklower struct nspcb *nsp = sotonspcb(so); 112621496Ssklower ((struct sppcb *)nsp->nsp_pcb)->s_flags |= 112721496Ssklower (SF_HI | SF_HO | SF_PI); 112821496Ssklower } 112923515Ssklower return (error); 113021496Ssklower } 113121496Ssklower 113221496Ssklower /* 113321496Ssklower * Create template to be used to send spp packets on a connection. 113421496Ssklower * Called after host entry created, fills 113521496Ssklower * in a skeletal spp header (choosing connection id), 113621496Ssklower * minimizing the amount of work necessary when the connection is used. 113721496Ssklower */ 113821496Ssklower spp_template(cb) 113921496Ssklower struct sppcb *cb; 114021496Ssklower { 114121496Ssklower register struct nspcb *nsp = cb->s_nspcb; 114221496Ssklower register struct spidp *n = &(cb->s_shdr); 114321496Ssklower 114424615Ssklower cb->s_mtu = 576 - sizeof (struct spidp); 114521496Ssklower n->si_pt = NSPROTO_SPP; 114621496Ssklower n->si_sna = nsp->nsp_laddr; 114721496Ssklower n->si_dna = nsp->nsp_faddr; 114821496Ssklower n->si_sid = htons(spp_iss); 114921496Ssklower spp_iss += SPP_ISSINCR/2; 115021496Ssklower n->si_alo = 1; 115121496Ssklower } 115221496Ssklower 115321496Ssklower /* 115421496Ssklower * Close a SPIP control block: 115521496Ssklower * discard spp control block itself 115621496Ssklower * discard ns protocol control block 115721496Ssklower * wake up any sleepers 115821496Ssklower */ 115921496Ssklower struct sppcb * 116021496Ssklower spp_close(cb) 116121496Ssklower register struct sppcb *cb; 116221496Ssklower { 116321496Ssklower register struct spidp_q *s; 116421496Ssklower struct nspcb *nsp = cb->s_nspcb; 116521496Ssklower struct socket *so = nsp->nsp_socket; 116621496Ssklower register struct mbuf *m; 116721496Ssklower 116821496Ssklower s = cb->s_q.si_next; 116921496Ssklower while (s != &(cb->s_q)) { 117021496Ssklower s = s->si_next; 117121496Ssklower m = dtom(s->si_prev); 117221496Ssklower remque(s->si_prev); 117321496Ssklower m_freem(m); 117421496Ssklower } 117521496Ssklower (void) m_free(dtom(cb)); 117621496Ssklower nsp->nsp_pcb = 0; 117721496Ssklower soisdisconnected(so); 117821496Ssklower ns_pcbdetach(nsp); 117923515Ssklower return ((struct sppcb *)0); 118021496Ssklower } 118121496Ssklower /* 118221496Ssklower * Someday we may do level 3 handshaking 118321496Ssklower * to close a connection or send a xerox style error. 118421496Ssklower * For now, just close. 118521496Ssklower */ 118621496Ssklower struct sppcb * 118721496Ssklower spp_usrclosed(cb) 118821496Ssklower register struct sppcb *cb; 118921496Ssklower { 119023515Ssklower return (spp_close(cb)); 119121496Ssklower } 119221496Ssklower struct sppcb * 119321496Ssklower spp_disconnect(cb) 119421496Ssklower register struct sppcb *cb; 119521496Ssklower { 119623515Ssklower return (spp_close(cb)); 119721496Ssklower } 119821496Ssklower /* 119921496Ssklower * Drop connection, reporting 120021496Ssklower * the specified error. 120121496Ssklower */ 120221496Ssklower struct sppcb * 120321496Ssklower spp_drop(cb, errno) 120421496Ssklower register struct sppcb *cb; 120521496Ssklower int errno; 120621496Ssklower { 120721496Ssklower struct socket *so = cb->s_nspcb->nsp_socket; 120821496Ssklower 120921496Ssklower /* 121021496Ssklower * someday, in the xerox world 121121496Ssklower * we will generate error protocol packets 121221496Ssklower * announcing that the socket has gone away. 121321496Ssklower */ 121421496Ssklower /*if (TCPS_HAVERCVDSYN(tp->t_state)) { 121521496Ssklower tp->t_state = TCPS_CLOSED; 121621496Ssklower (void) tcp_output(tp); 121721496Ssklower }*/ 121821496Ssklower so->so_error = errno; 121921496Ssklower return (spp_close(cb)); 122021496Ssklower } 122121496Ssklower 122221496Ssklower spp_abort(nsp) 122321496Ssklower struct nspcb *nsp; 122421496Ssklower { 122521496Ssklower 122624225Ssklower (void) spp_close((struct sppcb *)nsp->nsp_pcb); 122721496Ssklower } 122821496Ssklower 122921496Ssklower spp_setpersist(cb) 123021496Ssklower register struct sppcb *cb; 123121496Ssklower { 123221496Ssklower 123321496Ssklower /*if (cb->s_timer[TCPT_REXMT]) 123421496Ssklower panic("spp_output REXMT");*/ 123521496Ssklower /* 123621496Ssklower * Start/restart persistance timer. 123721496Ssklower */ 123821496Ssklower TCPT_RANGESET(cb->s_timer[TCPT_PERSIST], 123921496Ssklower ((int)(tcp_beta * cb->s_srtt)) << cb->s_rxtshift, 124021496Ssklower TCPTV_PERSMIN, TCPTV_MAX); 124121496Ssklower cb->s_rxtshift++; 124221496Ssklower if (cb->s_rxtshift >= TCP_MAXRXTSHIFT) 124321496Ssklower cb->s_rxtshift = 0; 124421496Ssklower } 124521496Ssklower /* 124621496Ssklower * Fast timeout routine for processing delayed acks 124721496Ssklower */ 124821496Ssklower int spp_ftcnt; 124921496Ssklower spp_fasttimo() 125021496Ssklower { 125121496Ssklower register struct nspcb *nsp; 125221496Ssklower register struct sppcb *cb; 125321496Ssklower int s = splnet(); 125421496Ssklower 125521496Ssklower nsp = nspcb.nsp_next; 125621496Ssklower spp_ftcnt++; 125721496Ssklower if (nsp) 125821496Ssklower for (; nsp != &nspcb; nsp = nsp->nsp_next) 125921496Ssklower if ((cb = (struct sppcb *)nsp->nsp_pcb) && 126021496Ssklower (cb->s_flags & SF_DELACK)) { 126121496Ssklower cb->s_flags &= ~SF_DELACK; 126221496Ssklower cb->s_flags |= SF_AK; 126321496Ssklower (void) spp_output(cb, (struct mbuf *) 0); 126421496Ssklower } 126521496Ssklower splx(s); 126621496Ssklower } 126721496Ssklower 126821496Ssklower /* 126921496Ssklower * spp protocol timeout routine called every 500 ms. 127021496Ssklower * Updates the timers in all active pcb's and 127121496Ssklower * causes finite state machine actions if timers expire. 127221496Ssklower */ 127321496Ssklower spp_slowtimo() 127421496Ssklower { 127521496Ssklower register struct nspcb *ip, *ipnxt; 127621496Ssklower register struct sppcb *cb; 127721496Ssklower int s = splnet(); 127821496Ssklower register int i; 127921496Ssklower 128021496Ssklower /* 128121496Ssklower * Search through tcb's and update active timers. 128221496Ssklower */ 128321496Ssklower ip = nspcb.nsp_next; 128421496Ssklower if (ip == 0) { 128521496Ssklower splx(s); 128621496Ssklower return; 128721496Ssklower } 128821496Ssklower while (ip != &nspcb) { 128921496Ssklower cb = nstosppcb(ip); 129021496Ssklower ipnxt = ip->nsp_next; 129121496Ssklower if (cb == 0) 129221496Ssklower goto tpgone; 129321496Ssklower for (i = 0; i < TCPT_NTIMERS; i++) { 129421496Ssklower if (cb->s_timer[i] && --cb->s_timer[i] == 0) { 129521496Ssklower (void) spp_usrreq(cb->s_nspcb->nsp_socket, 129621496Ssklower PRU_SLOWTIMO, (struct mbuf *)0, 129721496Ssklower (struct mbuf *)i, (struct mbuf *)0); 129821496Ssklower if (ipnxt->nsp_prev != ip) 129921496Ssklower goto tpgone; 130021496Ssklower } 130121496Ssklower } 130221496Ssklower cb->s_idle++; 130321496Ssklower if (cb->s_rtt) 130421496Ssklower cb->s_rtt++; 130521496Ssklower tpgone: 130621496Ssklower ip = ipnxt; 130721496Ssklower } 130821496Ssklower spp_iss += SPP_ISSINCR/PR_SLOWHZ; /* increment iss */ 130921496Ssklower splx(s); 131021496Ssklower } 131121496Ssklower 131221496Ssklower float spp_backoff[TCP_MAXRXTSHIFT] = 131321496Ssklower { 1.0, 1.2, 1.4, 1.7, 2.0, 3.0, 5.0, 8.0, 16.0, 32.0 }; 131424412Swalsh int sppexprexmtbackoff = 0; 131521496Ssklower /* 131624615Ssklower * SPP timer processing. 131721496Ssklower */ 131821496Ssklower struct sppcb * 131921496Ssklower spp_timers(cb, timer) 132021496Ssklower register struct sppcb *cb; 132121496Ssklower int timer; 132221496Ssklower { 132321496Ssklower 132421496Ssklower cb->s_force = 1 + timer; 132521496Ssklower switch (timer) { 132621496Ssklower 132721496Ssklower /* 132821496Ssklower * 2 MSL timeout in shutdown went off. Delete connection 132921496Ssklower * control block. 133021496Ssklower */ 133121496Ssklower case TCPT_2MSL: 133221496Ssklower cb = spp_close(cb); 133321496Ssklower break; 133421496Ssklower 133521496Ssklower /* 133621496Ssklower * Retransmission timer went off. Message has not 133721496Ssklower * been acked within retransmit interval. Back off 133821496Ssklower * to a longer retransmit interval and retransmit all 133921496Ssklower * unacknowledged messages in the window. 134021496Ssklower */ 134121496Ssklower case TCPT_REXMT: 134221496Ssklower cb->s_rxtshift++; 134321496Ssklower if (cb->s_rxtshift > TCP_MAXRXTSHIFT) { 134421496Ssklower cb = spp_drop(cb, ETIMEDOUT); 134521496Ssklower break; 134621496Ssklower } 134721496Ssklower (void) spp_output(cb, (struct mbuf *) 0); 134821496Ssklower TCPT_RANGESET(cb->s_timer[TCPT_REXMT], 134921496Ssklower (int)cb->s_srtt, TCPTV_MIN, TCPTV_MAX); 135024412Swalsh if (sppexprexmtbackoff) { 135121496Ssklower TCPT_RANGESET(cb->s_timer[TCPT_REXMT], 135221496Ssklower cb->s_timer[TCPT_REXMT] << cb->s_rxtshift, 135321496Ssklower TCPTV_MIN, TCPTV_MAX); 135421496Ssklower } else { 135521496Ssklower TCPT_RANGESET(cb->s_timer[TCPT_REXMT], 135621496Ssklower cb->s_timer[TCPT_REXMT] * 135721496Ssklower spp_backoff[cb->s_rxtshift - 1], 135821496Ssklower TCPTV_MIN, TCPTV_MAX); 135921496Ssklower } 136021496Ssklower break; 136121496Ssklower 136221496Ssklower /* 136321496Ssklower * Persistance timer into zero window. 136421496Ssklower * Force a probe to be sent. 136521496Ssklower */ 136621496Ssklower case TCPT_PERSIST: 136721496Ssklower (void) spp_output(cb, (struct mbuf *) 0); 136821496Ssklower spp_setpersist(cb); 136921496Ssklower break; 137021496Ssklower 137121496Ssklower /* 137221496Ssklower * Keep-alive timer went off; send something 137321496Ssklower * or drop connection if idle for too long. 137421496Ssklower */ 137521496Ssklower case TCPT_KEEP: 137621496Ssklower if (cb->s_state < TCPS_ESTABLISHED) 137721496Ssklower goto dropit; 137821496Ssklower if (cb->s_nspcb->nsp_socket->so_options & SO_KEEPALIVE) { 137921496Ssklower if (cb->s_idle >= TCPTV_MAXIDLE) 138021496Ssklower goto dropit; 138121496Ssklower (void) spp_output(cb, (struct mbuf *) 0); 138221496Ssklower } else 138321496Ssklower cb->s_idle = 0; 138421496Ssklower cb->s_timer[TCPT_KEEP] = TCPTV_KEEP; 138521496Ssklower break; 138621496Ssklower dropit: 138721496Ssklower cb = spp_drop(cb, ETIMEDOUT); 138821496Ssklower break; 138921496Ssklower } 139021496Ssklower return (cb); 139121496Ssklower } 1392