123215Smckusick /* 2*25334Ssklower * 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*25334Ssklower * @(#)spp_usrreq.c 6.15 (Berkeley) 10/30/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)) { 209*25334Ssklower 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. 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 */ 61025037Ssklower 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: 64425168Ssklower * If it is time to retransmit a packet, 64525168Ssklower * send that. 64621496Ssklower * If we have a new packet, send that 64721496Ssklower * (So long as it is in our allocation) 64821496Ssklower * Otherwise, see if it time to bang on them 64921496Ssklower * to ask for our current allocation. 65021496Ssklower */ 65125168Ssklower if (cb->s_force == (1+TCPT_REXMT)) { 65225168Ssklower lookfor = cb->s_rack; 65325168Ssklower } else if (SSEQ_LT(cb->s_snt, cb->s_ralo)) { 65421496Ssklower lookfor = cb->s_snt + 1; 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) { 71725037Ssklower if (cb->s_flags & (SF_AK|SF_DELACK)) 71825037Ssklower 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 } 77725168Ssklower if (so->so_options & SO_DEBUG || traceallspps) 77825168Ssklower spp_trace(SA_OUTPUT, cb->s_state, cb, si, 0); 77921496Ssklower } 78023515Ssklower return (error); 78121496Ssklower } 78221496Ssklower 78321496Ssklower /*ARGSUSED*/ 78421496Ssklower spp_ctloutput(req, so, level, name, value) 78521496Ssklower int req; 78621496Ssklower struct socket *so; 78721496Ssklower int name; 78821496Ssklower struct mbuf **value; 78921496Ssklower { 79021496Ssklower register struct mbuf *m; 79121496Ssklower struct nspcb *nsp = sotonspcb(so); 79221496Ssklower register struct sppcb *cb; 79321496Ssklower int mask, error = 0; 79421496Ssklower 79521496Ssklower if (level != NSPROTO_SPP) { 79621496Ssklower /* This will have to be changed when we do more general 79721496Ssklower stacking of protocols */ 79823515Ssklower return (idp_ctloutput(req, so, level, name, value)); 79921496Ssklower } 80021496Ssklower if (nsp == NULL) { 80121496Ssklower error = EINVAL; 80221496Ssklower goto release; 80321496Ssklower } else 80421496Ssklower cb = nstosppcb(nsp); 80521496Ssklower 80621496Ssklower switch (req) { 80723515Ssklower 80821496Ssklower case PRCO_GETOPT: 80924330Ssklower if (value == NULL) 81023515Ssklower return (EINVAL); 81121496Ssklower m = m_get(M_DONTWAIT, MT_DATA); 81224330Ssklower if (m == NULL) 81323515Ssklower return (ENOBUFS); 81421496Ssklower switch (name) { 81523515Ssklower 81621496Ssklower case SO_HEADERS_ON_INPUT: 81721496Ssklower mask = SF_HI; 81821496Ssklower goto get_flags; 81923515Ssklower 82021496Ssklower case SO_HEADERS_ON_OUTPUT: 82121496Ssklower mask = SF_HO; 82221496Ssklower get_flags: 82321496Ssklower m->m_len = sizeof(short); 82421496Ssklower m->m_off = MMAXOFF - sizeof(short); 82521496Ssklower *mtod(m, short *) = cb->s_flags & mask; 82621496Ssklower break; 82723515Ssklower 82824615Ssklower case SO_MTU: 82924615Ssklower m->m_len = sizeof(u_short); 83024615Ssklower m->m_off = MMAXOFF - sizeof(short); 83124615Ssklower *mtod(m, short *) = cb->s_mtu; 83224615Ssklower break; 83324615Ssklower 83421496Ssklower case SO_LAST_HEADER: 83521496Ssklower m->m_len = sizeof(struct sphdr); 83621496Ssklower m->m_off = MMAXOFF - sizeof(struct sphdr); 83721496Ssklower *mtod(m, struct sphdr *) = cb->s_rhdr; 83821496Ssklower break; 83923515Ssklower 84021496Ssklower case SO_DEFAULT_HEADERS: 84121496Ssklower m->m_len = sizeof(struct spidp); 84221496Ssklower m->m_off = MMAXOFF - sizeof(struct sphdr); 84321496Ssklower *mtod(m, struct sphdr *) = cb->s_shdr.si_s; 844*25334Ssklower break; 845*25334Ssklower 846*25334Ssklower default: 847*25334Ssklower error = EINVAL; 84821496Ssklower } 84921496Ssklower *value = m; 85021496Ssklower break; 85123515Ssklower 85221496Ssklower case PRCO_SETOPT: 85324615Ssklower if (value == 0 || *value == 0) { 85424615Ssklower error = EINVAL; 85524615Ssklower break; 85624615Ssklower } 85721496Ssklower switch (name) { 85824225Ssklower int *ok; 85921496Ssklower 86021496Ssklower case SO_HEADERS_ON_INPUT: 86121496Ssklower mask = SF_HI; 86221496Ssklower goto set_head; 86323515Ssklower 86421496Ssklower case SO_HEADERS_ON_OUTPUT: 86521496Ssklower mask = SF_HO; 86621496Ssklower set_head: 86724615Ssklower if (cb->s_flags & SF_PI) { 86821496Ssklower ok = mtod(*value, int *); 86921496Ssklower if (*ok) 87021496Ssklower cb->s_flags |= mask; 87121496Ssklower else 87221496Ssklower cb->s_flags &= ~mask; 87321496Ssklower } else error = EINVAL; 87421496Ssklower break; 87523515Ssklower 87624615Ssklower case SO_MTU: 87724615Ssklower cb->s_mtu = *(mtod(*value, u_short *)); 87824615Ssklower break; 87924615Ssklower 88021496Ssklower case SO_DEFAULT_HEADERS: 88121496Ssklower { 88221496Ssklower register struct sphdr *sp 88321496Ssklower = mtod(*value, struct sphdr *); 88421496Ssklower cb->s_dt = sp->sp_dt; 88521496Ssklower cb->s_cc = sp->sp_cc & SP_EM; 88621496Ssklower } 887*25334Ssklower break; 888*25334Ssklower 889*25334Ssklower default: 890*25334Ssklower error = EINVAL; 89121496Ssklower } 89224615Ssklower m_freem(*value); 89321496Ssklower break; 89421496Ssklower } 89521496Ssklower release: 89623515Ssklower return (error); 89721496Ssklower } 89821496Ssklower 89921496Ssklower /*ARGSUSED*/ 90021496Ssklower spp_usrreq(so, req, m, nam, rights) 90121496Ssklower struct socket *so; 90221496Ssklower int req; 90321496Ssklower struct mbuf *m, *nam, *rights; 90421496Ssklower { 90521496Ssklower struct nspcb *nsp = sotonspcb(so); 90621496Ssklower register struct sppcb *cb; 90721496Ssklower int s = splnet(); 90821496Ssklower int error = 0, ostate; 90921496Ssklower 91021496Ssklower if (req == PRU_CONTROL) 91121496Ssklower return (ns_control(so, (int)m, (caddr_t)nam, 91221496Ssklower (struct ifnet *)rights)); 91321496Ssklower if (rights && rights->m_len) { 91421496Ssklower error = EINVAL; 91521496Ssklower goto release; 91621496Ssklower } 91721496Ssklower if (nsp == NULL) { 91821496Ssklower if (req != PRU_ATTACH) { 91921496Ssklower error = EINVAL; 92021496Ssklower goto release; 92121496Ssklower } 92221496Ssklower } else 92321496Ssklower cb = nstosppcb(nsp); 92421496Ssklower 92521496Ssklower ostate = cb ? cb->s_state : 0; 92621496Ssklower 92721496Ssklower switch (req) { 92823515Ssklower 92921496Ssklower case PRU_ATTACH: 93021496Ssklower if (nsp != NULL) { 93121496Ssklower error = EISCONN; 93221496Ssklower break; 93321496Ssklower } 93421496Ssklower error = ns_pcballoc(so, &nspcb); 93521496Ssklower if (error) 93621496Ssklower break; 93721496Ssklower error = soreserve(so, 2048, 2048); 93821496Ssklower if (error) 93921496Ssklower break; 94021496Ssklower nsp = sotonspcb(so); 94121496Ssklower { 94225037Ssklower struct mbuf *mm = m_getclr(M_DONTWAIT, MT_PCB); 94321496Ssklower 94424330Ssklower if (mm == NULL) { 94521496Ssklower error = ENOBUFS; 94621496Ssklower break; 94721496Ssklower } 94821496Ssklower cb = mtod(mm, struct sppcb *); 94921496Ssklower cb->s_state = TCPS_LISTEN; 95021496Ssklower cb->s_snt = -1; 95121496Ssklower cb->s_q.si_next = cb->s_q.si_prev = &cb->s_q; 95221496Ssklower cb->s_nspcb = nsp; 95321496Ssklower nsp->nsp_pcb = (caddr_t) cb; 95421496Ssklower } 95521496Ssklower break; 95621496Ssklower 95721496Ssklower case PRU_DETACH: 95821496Ssklower if (nsp == NULL) { 95921496Ssklower error = ENOTCONN; 96021496Ssklower break; 96121496Ssklower } 96221496Ssklower if (cb->s_state > TCPS_LISTEN) 96321496Ssklower cb = spp_disconnect(cb); 96421496Ssklower else 96521496Ssklower cb = spp_close(cb); 96621496Ssklower break; 96721496Ssklower 96821496Ssklower case PRU_BIND: 96921496Ssklower error = ns_pcbbind(nsp, nam); 97021496Ssklower break; 97121496Ssklower 97221496Ssklower case PRU_LISTEN: 97321496Ssklower if (nsp->nsp_lport == 0) 97421496Ssklower error = ns_pcbbind(nsp, (struct mbuf *)0); 97521496Ssklower if (error == 0) 97621496Ssklower cb->s_state = TCPS_LISTEN; 97721496Ssklower break; 97821496Ssklower 97921496Ssklower /* 98021496Ssklower * Initiate connection to peer. 98121496Ssklower * Enter SYN_SENT state, and mark socket as connecting. 98221496Ssklower * Start keep-alive timer, setup prototype header, 98321496Ssklower * Send initial system packet requesting connection. 98421496Ssklower */ 98521496Ssklower case PRU_CONNECT: 98621496Ssklower if (nsp->nsp_lport == 0) { 98721496Ssklower error = ns_pcbbind(nsp, (struct mbuf *)0); 98821496Ssklower if (error) 98921496Ssklower break; 99021496Ssklower } 99121496Ssklower error = ns_pcbconnect(nsp, nam); 99221496Ssklower if (error) 99321496Ssklower break; 99421496Ssklower soisconnecting(so); 99521496Ssklower cb->s_state = TCPS_SYN_SENT; 99621496Ssklower cb->s_did = 0; 99721496Ssklower spp_template(cb); 99821496Ssklower cb->s_timer[TCPT_KEEP] = TCPTV_KEEP; 99921496Ssklower cb->s_force = 1 + TCPTV_KEEP; 100021496Ssklower /* 100121496Ssklower * Other party is required to respond to 100221496Ssklower * the port I send from, but he is not 100321496Ssklower * required to answer from where I am sending to, 100421496Ssklower * so allow wildcarding. 100521496Ssklower * original port I am sending to is still saved in 100621496Ssklower * cb->s_dport. 100721496Ssklower */ 100821496Ssklower nsp->nsp_fport = 0; 100921496Ssklower error = spp_output(cb, (struct mbuf *) 0); 101021496Ssklower break; 101121496Ssklower 101221496Ssklower case PRU_CONNECT2: 101321496Ssklower error = EOPNOTSUPP; 101421496Ssklower break; 101521496Ssklower 101621496Ssklower /* 101721496Ssklower * We may decide later to implement connection closing 101821496Ssklower * handshaking at the spp level optionally. 101921496Ssklower * here is the hook to do it: 102021496Ssklower */ 102121496Ssklower case PRU_DISCONNECT: 102221496Ssklower cb = spp_disconnect(cb); 102321496Ssklower break; 102421496Ssklower 102521496Ssklower /* 102621496Ssklower * Accept a connection. Essentially all the work is 102721496Ssklower * done at higher levels; just return the address 102821496Ssklower * of the peer, storing through addr. 102921496Ssklower */ 103021496Ssklower case PRU_ACCEPT: { 103121496Ssklower struct sockaddr_ns *sns = mtod(nam, struct sockaddr_ns *); 103221496Ssklower 103321496Ssklower nam->m_len = sizeof (struct sockaddr_ns); 103421496Ssklower sns->sns_family = AF_NS; 103521496Ssklower sns->sns_addr = nsp->nsp_faddr; 103621496Ssklower break; 103721496Ssklower } 103821496Ssklower 103921496Ssklower case PRU_SHUTDOWN: 104021496Ssklower socantsendmore(so); 104121496Ssklower cb = spp_usrclosed(cb); 104221496Ssklower if (cb) 104321496Ssklower error = spp_output(cb, (struct mbuf *) 0); 104421496Ssklower break; 104521496Ssklower 104621496Ssklower /* 104721496Ssklower * After a receive, possibly send acknowledgment 104821496Ssklower * updating allocation. 104921496Ssklower */ 105021496Ssklower case PRU_RCVD: 105121496Ssklower (void) spp_output(cb, (struct mbuf *) 0); 105221496Ssklower break; 105321496Ssklower 105421496Ssklower case PRU_SEND: 105521496Ssklower error = spp_output(cb, m); 105621496Ssklower m = NULL; 105721496Ssklower break; 105821496Ssklower 105921496Ssklower case PRU_ABORT: 106024225Ssklower (void) spp_drop(cb, ECONNABORTED); 106121496Ssklower break; 106221496Ssklower 106321496Ssklower case PRU_SENSE: 106421496Ssklower case PRU_CONTROL: 106521496Ssklower m = NULL; 106621496Ssklower error = EOPNOTSUPP; 106721496Ssklower break; 106821496Ssklower 106921496Ssklower case PRU_RCVOOB: 107025037Ssklower if ((cb->s_oobflags & SF_IOOB) || so->so_oobmark || 107125037Ssklower (so->so_state & SS_RCVATMARK)) { 107225037Ssklower m->m_len = 1; 107325037Ssklower *mtod(m, caddr_t) = cb->s_iobc; 107424732Ssklower break; 107524732Ssklower } 107625037Ssklower error = EINVAL; 107721496Ssklower break; 107821496Ssklower 107921496Ssklower case PRU_SENDOOB: 108021496Ssklower if (sbspace(&so->so_snd) < -512) { 108121496Ssklower m_freem(m); 108221496Ssklower error = ENOBUFS; 108321496Ssklower break; 108421496Ssklower } 108521496Ssklower cb->s_oobflags |= SF_SOOB; 108621496Ssklower error = spp_output(cb, m); 108721496Ssklower m = NULL; 108821496Ssklower break; 108921496Ssklower 109021496Ssklower case PRU_SOCKADDR: 109121496Ssklower ns_setsockaddr(nsp, nam); 109221496Ssklower break; 109321496Ssklower 109421496Ssklower case PRU_PEERADDR: 109521496Ssklower ns_setpeeraddr(nsp, nam); 109621496Ssklower break; 109721496Ssklower 109821496Ssklower case PRU_SLOWTIMO: 109921496Ssklower cb = spp_timers(cb, (int)nam); 110021496Ssklower break; 110121496Ssklower 110221496Ssklower case PRU_FASTTIMO: 110321496Ssklower case PRU_PROTORCV: 110421496Ssklower case PRU_PROTOSEND: 110521496Ssklower error = EOPNOTSUPP; 110621496Ssklower break; 110721496Ssklower 110821496Ssklower default: 110921496Ssklower panic("sp_usrreq"); 111021496Ssklower } 111121496Ssklower if (cb && (so->so_options & SO_DEBUG || traceallspps)) 111224225Ssklower spp_trace(SA_USER, (u_char)ostate, cb, (struct spidp *)0, req); 111321496Ssklower release: 111421496Ssklower if (m != NULL) 111521496Ssklower m_freem(m); 111621496Ssklower splx(s); 111721496Ssklower return (error); 111821496Ssklower } 111921496Ssklower 112021496Ssklower spp_usrreq_sp(so, req, m, nam, rights) 112121496Ssklower struct socket *so; 112221496Ssklower int req; 112321496Ssklower struct mbuf *m, *nam, *rights; 112421496Ssklower { 112521496Ssklower int error = spp_usrreq(so, req, m, nam, rights); 112621496Ssklower 112724330Ssklower if (req == PRU_ATTACH && error == 0) { 112821496Ssklower struct nspcb *nsp = sotonspcb(so); 112921496Ssklower ((struct sppcb *)nsp->nsp_pcb)->s_flags |= 113021496Ssklower (SF_HI | SF_HO | SF_PI); 113121496Ssklower } 113223515Ssklower return (error); 113321496Ssklower } 113421496Ssklower 113521496Ssklower /* 113621496Ssklower * Create template to be used to send spp packets on a connection. 113721496Ssklower * Called after host entry created, fills 113821496Ssklower * in a skeletal spp header (choosing connection id), 113921496Ssklower * minimizing the amount of work necessary when the connection is used. 114021496Ssklower */ 114121496Ssklower spp_template(cb) 114221496Ssklower struct sppcb *cb; 114321496Ssklower { 114421496Ssklower register struct nspcb *nsp = cb->s_nspcb; 114521496Ssklower register struct spidp *n = &(cb->s_shdr); 114621496Ssklower 114724615Ssklower cb->s_mtu = 576 - sizeof (struct spidp); 114821496Ssklower n->si_pt = NSPROTO_SPP; 114921496Ssklower n->si_sna = nsp->nsp_laddr; 115021496Ssklower n->si_dna = nsp->nsp_faddr; 115121496Ssklower n->si_sid = htons(spp_iss); 115221496Ssklower spp_iss += SPP_ISSINCR/2; 115321496Ssklower n->si_alo = 1; 115421496Ssklower } 115521496Ssklower 115621496Ssklower /* 115721496Ssklower * Close a SPIP control block: 115821496Ssklower * discard spp control block itself 115921496Ssklower * discard ns protocol control block 116021496Ssklower * wake up any sleepers 116121496Ssklower */ 116221496Ssklower struct sppcb * 116321496Ssklower spp_close(cb) 116421496Ssklower register struct sppcb *cb; 116521496Ssklower { 116621496Ssklower register struct spidp_q *s; 116721496Ssklower struct nspcb *nsp = cb->s_nspcb; 116821496Ssklower struct socket *so = nsp->nsp_socket; 116921496Ssklower register struct mbuf *m; 117021496Ssklower 117121496Ssklower s = cb->s_q.si_next; 117221496Ssklower while (s != &(cb->s_q)) { 117321496Ssklower s = s->si_next; 117421496Ssklower m = dtom(s->si_prev); 117521496Ssklower remque(s->si_prev); 117621496Ssklower m_freem(m); 117721496Ssklower } 117821496Ssklower (void) m_free(dtom(cb)); 117921496Ssklower nsp->nsp_pcb = 0; 118021496Ssklower soisdisconnected(so); 118121496Ssklower ns_pcbdetach(nsp); 118223515Ssklower return ((struct sppcb *)0); 118321496Ssklower } 118421496Ssklower /* 118521496Ssklower * Someday we may do level 3 handshaking 118621496Ssklower * to close a connection or send a xerox style error. 118721496Ssklower * For now, just close. 118821496Ssklower */ 118921496Ssklower struct sppcb * 119021496Ssklower spp_usrclosed(cb) 119121496Ssklower register struct sppcb *cb; 119221496Ssklower { 119323515Ssklower return (spp_close(cb)); 119421496Ssklower } 119521496Ssklower struct sppcb * 119621496Ssklower spp_disconnect(cb) 119721496Ssklower register struct sppcb *cb; 119821496Ssklower { 119923515Ssklower return (spp_close(cb)); 120021496Ssklower } 120121496Ssklower /* 120221496Ssklower * Drop connection, reporting 120321496Ssklower * the specified error. 120421496Ssklower */ 120521496Ssklower struct sppcb * 120621496Ssklower spp_drop(cb, errno) 120721496Ssklower register struct sppcb *cb; 120821496Ssklower int errno; 120921496Ssklower { 121021496Ssklower struct socket *so = cb->s_nspcb->nsp_socket; 121121496Ssklower 121221496Ssklower /* 121321496Ssklower * someday, in the xerox world 121421496Ssklower * we will generate error protocol packets 121521496Ssklower * announcing that the socket has gone away. 121621496Ssklower */ 121721496Ssklower /*if (TCPS_HAVERCVDSYN(tp->t_state)) { 121821496Ssklower tp->t_state = TCPS_CLOSED; 121921496Ssklower (void) tcp_output(tp); 122021496Ssklower }*/ 122121496Ssklower so->so_error = errno; 122221496Ssklower return (spp_close(cb)); 122321496Ssklower } 122421496Ssklower 122521496Ssklower spp_abort(nsp) 122621496Ssklower struct nspcb *nsp; 122721496Ssklower { 122821496Ssklower 122924225Ssklower (void) spp_close((struct sppcb *)nsp->nsp_pcb); 123021496Ssklower } 123121496Ssklower 123221496Ssklower spp_setpersist(cb) 123321496Ssklower register struct sppcb *cb; 123421496Ssklower { 123521496Ssklower 123621496Ssklower /*if (cb->s_timer[TCPT_REXMT]) 123721496Ssklower panic("spp_output REXMT");*/ 123821496Ssklower /* 123921496Ssklower * Start/restart persistance timer. 124021496Ssklower */ 124121496Ssklower TCPT_RANGESET(cb->s_timer[TCPT_PERSIST], 124221496Ssklower ((int)(tcp_beta * cb->s_srtt)) << cb->s_rxtshift, 124321496Ssklower TCPTV_PERSMIN, TCPTV_MAX); 124421496Ssklower cb->s_rxtshift++; 124521496Ssklower if (cb->s_rxtshift >= TCP_MAXRXTSHIFT) 124621496Ssklower cb->s_rxtshift = 0; 124721496Ssklower } 124821496Ssklower /* 124921496Ssklower * Fast timeout routine for processing delayed acks 125021496Ssklower */ 125121496Ssklower int spp_ftcnt; 125221496Ssklower spp_fasttimo() 125321496Ssklower { 125421496Ssklower register struct nspcb *nsp; 125521496Ssklower register struct sppcb *cb; 125621496Ssklower int s = splnet(); 125721496Ssklower 125821496Ssklower nsp = nspcb.nsp_next; 125921496Ssklower spp_ftcnt++; 126021496Ssklower if (nsp) 126121496Ssklower for (; nsp != &nspcb; nsp = nsp->nsp_next) 126221496Ssklower if ((cb = (struct sppcb *)nsp->nsp_pcb) && 126321496Ssklower (cb->s_flags & SF_DELACK)) { 126421496Ssklower cb->s_flags &= ~SF_DELACK; 126521496Ssklower cb->s_flags |= SF_AK; 126621496Ssklower (void) spp_output(cb, (struct mbuf *) 0); 126721496Ssklower } 126821496Ssklower splx(s); 126921496Ssklower } 127021496Ssklower 127121496Ssklower /* 127221496Ssklower * spp protocol timeout routine called every 500 ms. 127321496Ssklower * Updates the timers in all active pcb's and 127421496Ssklower * causes finite state machine actions if timers expire. 127521496Ssklower */ 127621496Ssklower spp_slowtimo() 127721496Ssklower { 127821496Ssklower register struct nspcb *ip, *ipnxt; 127921496Ssklower register struct sppcb *cb; 128021496Ssklower int s = splnet(); 128121496Ssklower register int i; 128221496Ssklower 128321496Ssklower /* 128421496Ssklower * Search through tcb's and update active timers. 128521496Ssklower */ 128621496Ssklower ip = nspcb.nsp_next; 128721496Ssklower if (ip == 0) { 128821496Ssklower splx(s); 128921496Ssklower return; 129021496Ssklower } 129121496Ssklower while (ip != &nspcb) { 129221496Ssklower cb = nstosppcb(ip); 129321496Ssklower ipnxt = ip->nsp_next; 129421496Ssklower if (cb == 0) 129521496Ssklower goto tpgone; 129621496Ssklower for (i = 0; i < TCPT_NTIMERS; i++) { 129721496Ssklower if (cb->s_timer[i] && --cb->s_timer[i] == 0) { 129821496Ssklower (void) spp_usrreq(cb->s_nspcb->nsp_socket, 129921496Ssklower PRU_SLOWTIMO, (struct mbuf *)0, 130021496Ssklower (struct mbuf *)i, (struct mbuf *)0); 130121496Ssklower if (ipnxt->nsp_prev != ip) 130221496Ssklower goto tpgone; 130321496Ssklower } 130421496Ssklower } 130521496Ssklower cb->s_idle++; 130621496Ssklower if (cb->s_rtt) 130721496Ssklower cb->s_rtt++; 130821496Ssklower tpgone: 130921496Ssklower ip = ipnxt; 131021496Ssklower } 131121496Ssklower spp_iss += SPP_ISSINCR/PR_SLOWHZ; /* increment iss */ 131221496Ssklower splx(s); 131321496Ssklower } 131421496Ssklower 131521496Ssklower float spp_backoff[TCP_MAXRXTSHIFT] = 131621496Ssklower { 1.0, 1.2, 1.4, 1.7, 2.0, 3.0, 5.0, 8.0, 16.0, 32.0 }; 131724412Swalsh int sppexprexmtbackoff = 0; 131821496Ssklower /* 131924615Ssklower * SPP timer processing. 132021496Ssklower */ 132121496Ssklower struct sppcb * 132221496Ssklower spp_timers(cb, timer) 132321496Ssklower register struct sppcb *cb; 132421496Ssklower int timer; 132521496Ssklower { 132621496Ssklower 132721496Ssklower cb->s_force = 1 + timer; 132821496Ssklower switch (timer) { 132921496Ssklower 133021496Ssklower /* 133121496Ssklower * 2 MSL timeout in shutdown went off. Delete connection 133221496Ssklower * control block. 133321496Ssklower */ 133421496Ssklower case TCPT_2MSL: 133521496Ssklower cb = spp_close(cb); 133621496Ssklower break; 133721496Ssklower 133821496Ssklower /* 133921496Ssklower * Retransmission timer went off. Message has not 134021496Ssklower * been acked within retransmit interval. Back off 134121496Ssklower * to a longer retransmit interval and retransmit all 134221496Ssklower * unacknowledged messages in the window. 134321496Ssklower */ 134421496Ssklower case TCPT_REXMT: 134521496Ssklower cb->s_rxtshift++; 134621496Ssklower if (cb->s_rxtshift > TCP_MAXRXTSHIFT) { 134721496Ssklower cb = spp_drop(cb, ETIMEDOUT); 134821496Ssklower break; 134921496Ssklower } 135021496Ssklower (void) spp_output(cb, (struct mbuf *) 0); 135121496Ssklower TCPT_RANGESET(cb->s_timer[TCPT_REXMT], 135221496Ssklower (int)cb->s_srtt, TCPTV_MIN, TCPTV_MAX); 135324412Swalsh if (sppexprexmtbackoff) { 135421496Ssklower TCPT_RANGESET(cb->s_timer[TCPT_REXMT], 135521496Ssklower cb->s_timer[TCPT_REXMT] << cb->s_rxtshift, 135621496Ssklower TCPTV_MIN, TCPTV_MAX); 135721496Ssklower } else { 135821496Ssklower TCPT_RANGESET(cb->s_timer[TCPT_REXMT], 135921496Ssklower cb->s_timer[TCPT_REXMT] * 136021496Ssklower spp_backoff[cb->s_rxtshift - 1], 136121496Ssklower TCPTV_MIN, TCPTV_MAX); 136221496Ssklower } 136321496Ssklower break; 136421496Ssklower 136521496Ssklower /* 136621496Ssklower * Persistance timer into zero window. 136721496Ssklower * Force a probe to be sent. 136821496Ssklower */ 136921496Ssklower case TCPT_PERSIST: 137021496Ssklower (void) spp_output(cb, (struct mbuf *) 0); 137121496Ssklower spp_setpersist(cb); 137221496Ssklower break; 137321496Ssklower 137421496Ssklower /* 137521496Ssklower * Keep-alive timer went off; send something 137621496Ssklower * or drop connection if idle for too long. 137721496Ssklower */ 137821496Ssklower case TCPT_KEEP: 137921496Ssklower if (cb->s_state < TCPS_ESTABLISHED) 138021496Ssklower goto dropit; 138121496Ssklower if (cb->s_nspcb->nsp_socket->so_options & SO_KEEPALIVE) { 138221496Ssklower if (cb->s_idle >= TCPTV_MAXIDLE) 138321496Ssklower goto dropit; 138421496Ssklower (void) spp_output(cb, (struct mbuf *) 0); 138521496Ssklower } else 138621496Ssklower cb->s_idle = 0; 138721496Ssklower cb->s_timer[TCPT_KEEP] = TCPTV_KEEP; 138821496Ssklower break; 138921496Ssklower dropit: 139021496Ssklower cb = spp_drop(cb, ETIMEDOUT); 139121496Ssklower break; 139221496Ssklower } 139321496Ssklower return (cb); 139421496Ssklower } 1395