123215Smckusick /* 223215Smckusick * Copyright (c) 1982 Regents of the University of California. 323215Smckusick * All rights reserved. The Berkeley software License Agreement 423215Smckusick * specifies the terms and conditions for redistribution. 523215Smckusick * 6*25168Ssklower * @(#)spp_usrreq.c 6.14 (Berkeley) 10/11/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)) { 20921496Ssklower goto drop; 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: 644*25168Ssklower * If it is time to retransmit a packet, 645*25168Ssklower * 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 */ 651*25168Ssklower if (cb->s_force == (1+TCPT_REXMT)) { 652*25168Ssklower lookfor = cb->s_rack; 653*25168Ssklower } 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 } 777*25168Ssklower if (so->so_options & SO_DEBUG || traceallspps) 778*25168Ssklower 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; 84421496Ssklower } 84521496Ssklower *value = m; 84621496Ssklower break; 84723515Ssklower 84821496Ssklower case PRCO_SETOPT: 84924615Ssklower if (value == 0 || *value == 0) { 85024615Ssklower error = EINVAL; 85124615Ssklower break; 85224615Ssklower } 85321496Ssklower switch (name) { 85424225Ssklower int *ok; 85521496Ssklower 85621496Ssklower case SO_HEADERS_ON_INPUT: 85721496Ssklower mask = SF_HI; 85821496Ssklower goto set_head; 85923515Ssklower 86021496Ssklower case SO_HEADERS_ON_OUTPUT: 86121496Ssklower mask = SF_HO; 86221496Ssklower set_head: 86324615Ssklower if (cb->s_flags & SF_PI) { 86421496Ssklower ok = mtod(*value, int *); 86521496Ssklower if (*ok) 86621496Ssklower cb->s_flags |= mask; 86721496Ssklower else 86821496Ssklower cb->s_flags &= ~mask; 86921496Ssklower } else error = EINVAL; 87021496Ssklower break; 87123515Ssklower 87224615Ssklower case SO_MTU: 87324615Ssklower cb->s_mtu = *(mtod(*value, u_short *)); 87424615Ssklower break; 87524615Ssklower 87621496Ssklower case SO_DEFAULT_HEADERS: 87721496Ssklower { 87821496Ssklower register struct sphdr *sp 87921496Ssklower = mtod(*value, struct sphdr *); 88021496Ssklower cb->s_dt = sp->sp_dt; 88121496Ssklower cb->s_cc = sp->sp_cc & SP_EM; 88221496Ssklower } 88321496Ssklower } 88424615Ssklower m_freem(*value); 88521496Ssklower break; 88621496Ssklower } 88721496Ssklower release: 88823515Ssklower return (error); 88921496Ssklower } 89021496Ssklower 89121496Ssklower /*ARGSUSED*/ 89221496Ssklower spp_usrreq(so, req, m, nam, rights) 89321496Ssklower struct socket *so; 89421496Ssklower int req; 89521496Ssklower struct mbuf *m, *nam, *rights; 89621496Ssklower { 89721496Ssklower struct nspcb *nsp = sotonspcb(so); 89821496Ssklower register struct sppcb *cb; 89921496Ssklower int s = splnet(); 90021496Ssklower int error = 0, ostate; 90121496Ssklower 90221496Ssklower if (req == PRU_CONTROL) 90321496Ssklower return (ns_control(so, (int)m, (caddr_t)nam, 90421496Ssklower (struct ifnet *)rights)); 90521496Ssklower if (rights && rights->m_len) { 90621496Ssklower error = EINVAL; 90721496Ssklower goto release; 90821496Ssklower } 90921496Ssklower if (nsp == NULL) { 91021496Ssklower if (req != PRU_ATTACH) { 91121496Ssklower error = EINVAL; 91221496Ssklower goto release; 91321496Ssklower } 91421496Ssklower } else 91521496Ssklower cb = nstosppcb(nsp); 91621496Ssklower 91721496Ssklower ostate = cb ? cb->s_state : 0; 91821496Ssklower 91921496Ssklower switch (req) { 92023515Ssklower 92121496Ssklower case PRU_ATTACH: 92221496Ssklower if (nsp != NULL) { 92321496Ssklower error = EISCONN; 92421496Ssklower break; 92521496Ssklower } 92621496Ssklower error = ns_pcballoc(so, &nspcb); 92721496Ssklower if (error) 92821496Ssklower break; 92921496Ssklower error = soreserve(so, 2048, 2048); 93021496Ssklower if (error) 93121496Ssklower break; 93221496Ssklower nsp = sotonspcb(so); 93321496Ssklower { 93425037Ssklower struct mbuf *mm = m_getclr(M_DONTWAIT, MT_PCB); 93521496Ssklower 93624330Ssklower if (mm == NULL) { 93721496Ssklower error = ENOBUFS; 93821496Ssklower break; 93921496Ssklower } 94021496Ssklower cb = mtod(mm, struct sppcb *); 94121496Ssklower cb->s_state = TCPS_LISTEN; 94221496Ssklower cb->s_snt = -1; 94321496Ssklower cb->s_q.si_next = cb->s_q.si_prev = &cb->s_q; 94421496Ssklower cb->s_nspcb = nsp; 94521496Ssklower nsp->nsp_pcb = (caddr_t) cb; 94621496Ssklower } 94721496Ssklower break; 94821496Ssklower 94921496Ssklower case PRU_DETACH: 95021496Ssklower if (nsp == NULL) { 95121496Ssklower error = ENOTCONN; 95221496Ssklower break; 95321496Ssklower } 95421496Ssklower if (cb->s_state > TCPS_LISTEN) 95521496Ssklower cb = spp_disconnect(cb); 95621496Ssklower else 95721496Ssklower cb = spp_close(cb); 95821496Ssklower break; 95921496Ssklower 96021496Ssklower case PRU_BIND: 96121496Ssklower error = ns_pcbbind(nsp, nam); 96221496Ssklower break; 96321496Ssklower 96421496Ssklower case PRU_LISTEN: 96521496Ssklower if (nsp->nsp_lport == 0) 96621496Ssklower error = ns_pcbbind(nsp, (struct mbuf *)0); 96721496Ssklower if (error == 0) 96821496Ssklower cb->s_state = TCPS_LISTEN; 96921496Ssklower break; 97021496Ssklower 97121496Ssklower /* 97221496Ssklower * Initiate connection to peer. 97321496Ssklower * Enter SYN_SENT state, and mark socket as connecting. 97421496Ssklower * Start keep-alive timer, setup prototype header, 97521496Ssklower * Send initial system packet requesting connection. 97621496Ssklower */ 97721496Ssklower case PRU_CONNECT: 97821496Ssklower if (nsp->nsp_lport == 0) { 97921496Ssklower error = ns_pcbbind(nsp, (struct mbuf *)0); 98021496Ssklower if (error) 98121496Ssklower break; 98221496Ssklower } 98321496Ssklower error = ns_pcbconnect(nsp, nam); 98421496Ssklower if (error) 98521496Ssklower break; 98621496Ssklower soisconnecting(so); 98721496Ssklower cb->s_state = TCPS_SYN_SENT; 98821496Ssklower cb->s_did = 0; 98921496Ssklower spp_template(cb); 99021496Ssklower cb->s_timer[TCPT_KEEP] = TCPTV_KEEP; 99121496Ssklower cb->s_force = 1 + TCPTV_KEEP; 99221496Ssklower /* 99321496Ssklower * Other party is required to respond to 99421496Ssklower * the port I send from, but he is not 99521496Ssklower * required to answer from where I am sending to, 99621496Ssklower * so allow wildcarding. 99721496Ssklower * original port I am sending to is still saved in 99821496Ssklower * cb->s_dport. 99921496Ssklower */ 100021496Ssklower nsp->nsp_fport = 0; 100121496Ssklower error = spp_output(cb, (struct mbuf *) 0); 100221496Ssklower break; 100321496Ssklower 100421496Ssklower case PRU_CONNECT2: 100521496Ssklower error = EOPNOTSUPP; 100621496Ssklower break; 100721496Ssklower 100821496Ssklower /* 100921496Ssklower * We may decide later to implement connection closing 101021496Ssklower * handshaking at the spp level optionally. 101121496Ssklower * here is the hook to do it: 101221496Ssklower */ 101321496Ssklower case PRU_DISCONNECT: 101421496Ssklower cb = spp_disconnect(cb); 101521496Ssklower break; 101621496Ssklower 101721496Ssklower /* 101821496Ssklower * Accept a connection. Essentially all the work is 101921496Ssklower * done at higher levels; just return the address 102021496Ssklower * of the peer, storing through addr. 102121496Ssklower */ 102221496Ssklower case PRU_ACCEPT: { 102321496Ssklower struct sockaddr_ns *sns = mtod(nam, struct sockaddr_ns *); 102421496Ssklower 102521496Ssklower nam->m_len = sizeof (struct sockaddr_ns); 102621496Ssklower sns->sns_family = AF_NS; 102721496Ssklower sns->sns_addr = nsp->nsp_faddr; 102821496Ssklower break; 102921496Ssklower } 103021496Ssklower 103121496Ssklower case PRU_SHUTDOWN: 103221496Ssklower socantsendmore(so); 103321496Ssklower cb = spp_usrclosed(cb); 103421496Ssklower if (cb) 103521496Ssklower error = spp_output(cb, (struct mbuf *) 0); 103621496Ssklower break; 103721496Ssklower 103821496Ssklower /* 103921496Ssklower * After a receive, possibly send acknowledgment 104021496Ssklower * updating allocation. 104121496Ssklower */ 104221496Ssklower case PRU_RCVD: 104321496Ssklower (void) spp_output(cb, (struct mbuf *) 0); 104421496Ssklower break; 104521496Ssklower 104621496Ssklower case PRU_SEND: 104721496Ssklower error = spp_output(cb, m); 104821496Ssklower m = NULL; 104921496Ssklower break; 105021496Ssklower 105121496Ssklower case PRU_ABORT: 105224225Ssklower (void) spp_drop(cb, ECONNABORTED); 105321496Ssklower break; 105421496Ssklower 105521496Ssklower case PRU_SENSE: 105621496Ssklower case PRU_CONTROL: 105721496Ssklower m = NULL; 105821496Ssklower error = EOPNOTSUPP; 105921496Ssklower break; 106021496Ssklower 106121496Ssklower case PRU_RCVOOB: 106225037Ssklower if ((cb->s_oobflags & SF_IOOB) || so->so_oobmark || 106325037Ssklower (so->so_state & SS_RCVATMARK)) { 106425037Ssklower m->m_len = 1; 106525037Ssklower *mtod(m, caddr_t) = cb->s_iobc; 106624732Ssklower break; 106724732Ssklower } 106825037Ssklower error = EINVAL; 106921496Ssklower break; 107021496Ssklower 107121496Ssklower case PRU_SENDOOB: 107221496Ssklower if (sbspace(&so->so_snd) < -512) { 107321496Ssklower m_freem(m); 107421496Ssklower error = ENOBUFS; 107521496Ssklower break; 107621496Ssklower } 107721496Ssklower cb->s_oobflags |= SF_SOOB; 107821496Ssklower error = spp_output(cb, m); 107921496Ssklower m = NULL; 108021496Ssklower break; 108121496Ssklower 108221496Ssklower case PRU_SOCKADDR: 108321496Ssklower ns_setsockaddr(nsp, nam); 108421496Ssklower break; 108521496Ssklower 108621496Ssklower case PRU_PEERADDR: 108721496Ssklower ns_setpeeraddr(nsp, nam); 108821496Ssklower break; 108921496Ssklower 109021496Ssklower case PRU_SLOWTIMO: 109121496Ssklower cb = spp_timers(cb, (int)nam); 109221496Ssklower break; 109321496Ssklower 109421496Ssklower case PRU_FASTTIMO: 109521496Ssklower case PRU_PROTORCV: 109621496Ssklower case PRU_PROTOSEND: 109721496Ssklower error = EOPNOTSUPP; 109821496Ssklower break; 109921496Ssklower 110021496Ssklower default: 110121496Ssklower panic("sp_usrreq"); 110221496Ssklower } 110321496Ssklower if (cb && (so->so_options & SO_DEBUG || traceallspps)) 110424225Ssklower spp_trace(SA_USER, (u_char)ostate, cb, (struct spidp *)0, req); 110521496Ssklower release: 110621496Ssklower if (m != NULL) 110721496Ssklower m_freem(m); 110821496Ssklower splx(s); 110921496Ssklower return (error); 111021496Ssklower } 111121496Ssklower 111221496Ssklower spp_usrreq_sp(so, req, m, nam, rights) 111321496Ssklower struct socket *so; 111421496Ssklower int req; 111521496Ssklower struct mbuf *m, *nam, *rights; 111621496Ssklower { 111721496Ssklower int error = spp_usrreq(so, req, m, nam, rights); 111821496Ssklower 111924330Ssklower if (req == PRU_ATTACH && error == 0) { 112021496Ssklower struct nspcb *nsp = sotonspcb(so); 112121496Ssklower ((struct sppcb *)nsp->nsp_pcb)->s_flags |= 112221496Ssklower (SF_HI | SF_HO | SF_PI); 112321496Ssklower } 112423515Ssklower return (error); 112521496Ssklower } 112621496Ssklower 112721496Ssklower /* 112821496Ssklower * Create template to be used to send spp packets on a connection. 112921496Ssklower * Called after host entry created, fills 113021496Ssklower * in a skeletal spp header (choosing connection id), 113121496Ssklower * minimizing the amount of work necessary when the connection is used. 113221496Ssklower */ 113321496Ssklower spp_template(cb) 113421496Ssklower struct sppcb *cb; 113521496Ssklower { 113621496Ssklower register struct nspcb *nsp = cb->s_nspcb; 113721496Ssklower register struct spidp *n = &(cb->s_shdr); 113821496Ssklower 113924615Ssklower cb->s_mtu = 576 - sizeof (struct spidp); 114021496Ssklower n->si_pt = NSPROTO_SPP; 114121496Ssklower n->si_sna = nsp->nsp_laddr; 114221496Ssklower n->si_dna = nsp->nsp_faddr; 114321496Ssklower n->si_sid = htons(spp_iss); 114421496Ssklower spp_iss += SPP_ISSINCR/2; 114521496Ssklower n->si_alo = 1; 114621496Ssklower } 114721496Ssklower 114821496Ssklower /* 114921496Ssklower * Close a SPIP control block: 115021496Ssklower * discard spp control block itself 115121496Ssklower * discard ns protocol control block 115221496Ssklower * wake up any sleepers 115321496Ssklower */ 115421496Ssklower struct sppcb * 115521496Ssklower spp_close(cb) 115621496Ssklower register struct sppcb *cb; 115721496Ssklower { 115821496Ssklower register struct spidp_q *s; 115921496Ssklower struct nspcb *nsp = cb->s_nspcb; 116021496Ssklower struct socket *so = nsp->nsp_socket; 116121496Ssklower register struct mbuf *m; 116221496Ssklower 116321496Ssklower s = cb->s_q.si_next; 116421496Ssklower while (s != &(cb->s_q)) { 116521496Ssklower s = s->si_next; 116621496Ssklower m = dtom(s->si_prev); 116721496Ssklower remque(s->si_prev); 116821496Ssklower m_freem(m); 116921496Ssklower } 117021496Ssklower (void) m_free(dtom(cb)); 117121496Ssklower nsp->nsp_pcb = 0; 117221496Ssklower soisdisconnected(so); 117321496Ssklower ns_pcbdetach(nsp); 117423515Ssklower return ((struct sppcb *)0); 117521496Ssklower } 117621496Ssklower /* 117721496Ssklower * Someday we may do level 3 handshaking 117821496Ssklower * to close a connection or send a xerox style error. 117921496Ssklower * For now, just close. 118021496Ssklower */ 118121496Ssklower struct sppcb * 118221496Ssklower spp_usrclosed(cb) 118321496Ssklower register struct sppcb *cb; 118421496Ssklower { 118523515Ssklower return (spp_close(cb)); 118621496Ssklower } 118721496Ssklower struct sppcb * 118821496Ssklower spp_disconnect(cb) 118921496Ssklower register struct sppcb *cb; 119021496Ssklower { 119123515Ssklower return (spp_close(cb)); 119221496Ssklower } 119321496Ssklower /* 119421496Ssklower * Drop connection, reporting 119521496Ssklower * the specified error. 119621496Ssklower */ 119721496Ssklower struct sppcb * 119821496Ssklower spp_drop(cb, errno) 119921496Ssklower register struct sppcb *cb; 120021496Ssklower int errno; 120121496Ssklower { 120221496Ssklower struct socket *so = cb->s_nspcb->nsp_socket; 120321496Ssklower 120421496Ssklower /* 120521496Ssklower * someday, in the xerox world 120621496Ssklower * we will generate error protocol packets 120721496Ssklower * announcing that the socket has gone away. 120821496Ssklower */ 120921496Ssklower /*if (TCPS_HAVERCVDSYN(tp->t_state)) { 121021496Ssklower tp->t_state = TCPS_CLOSED; 121121496Ssklower (void) tcp_output(tp); 121221496Ssklower }*/ 121321496Ssklower so->so_error = errno; 121421496Ssklower return (spp_close(cb)); 121521496Ssklower } 121621496Ssklower 121721496Ssklower spp_abort(nsp) 121821496Ssklower struct nspcb *nsp; 121921496Ssklower { 122021496Ssklower 122124225Ssklower (void) spp_close((struct sppcb *)nsp->nsp_pcb); 122221496Ssklower } 122321496Ssklower 122421496Ssklower spp_setpersist(cb) 122521496Ssklower register struct sppcb *cb; 122621496Ssklower { 122721496Ssklower 122821496Ssklower /*if (cb->s_timer[TCPT_REXMT]) 122921496Ssklower panic("spp_output REXMT");*/ 123021496Ssklower /* 123121496Ssklower * Start/restart persistance timer. 123221496Ssklower */ 123321496Ssklower TCPT_RANGESET(cb->s_timer[TCPT_PERSIST], 123421496Ssklower ((int)(tcp_beta * cb->s_srtt)) << cb->s_rxtshift, 123521496Ssklower TCPTV_PERSMIN, TCPTV_MAX); 123621496Ssklower cb->s_rxtshift++; 123721496Ssklower if (cb->s_rxtshift >= TCP_MAXRXTSHIFT) 123821496Ssklower cb->s_rxtshift = 0; 123921496Ssklower } 124021496Ssklower /* 124121496Ssklower * Fast timeout routine for processing delayed acks 124221496Ssklower */ 124321496Ssklower int spp_ftcnt; 124421496Ssklower spp_fasttimo() 124521496Ssklower { 124621496Ssklower register struct nspcb *nsp; 124721496Ssklower register struct sppcb *cb; 124821496Ssklower int s = splnet(); 124921496Ssklower 125021496Ssklower nsp = nspcb.nsp_next; 125121496Ssklower spp_ftcnt++; 125221496Ssklower if (nsp) 125321496Ssklower for (; nsp != &nspcb; nsp = nsp->nsp_next) 125421496Ssklower if ((cb = (struct sppcb *)nsp->nsp_pcb) && 125521496Ssklower (cb->s_flags & SF_DELACK)) { 125621496Ssklower cb->s_flags &= ~SF_DELACK; 125721496Ssklower cb->s_flags |= SF_AK; 125821496Ssklower (void) spp_output(cb, (struct mbuf *) 0); 125921496Ssklower } 126021496Ssklower splx(s); 126121496Ssklower } 126221496Ssklower 126321496Ssklower /* 126421496Ssklower * spp protocol timeout routine called every 500 ms. 126521496Ssklower * Updates the timers in all active pcb's and 126621496Ssklower * causes finite state machine actions if timers expire. 126721496Ssklower */ 126821496Ssklower spp_slowtimo() 126921496Ssklower { 127021496Ssklower register struct nspcb *ip, *ipnxt; 127121496Ssklower register struct sppcb *cb; 127221496Ssklower int s = splnet(); 127321496Ssklower register int i; 127421496Ssklower 127521496Ssklower /* 127621496Ssklower * Search through tcb's and update active timers. 127721496Ssklower */ 127821496Ssklower ip = nspcb.nsp_next; 127921496Ssklower if (ip == 0) { 128021496Ssklower splx(s); 128121496Ssklower return; 128221496Ssklower } 128321496Ssklower while (ip != &nspcb) { 128421496Ssklower cb = nstosppcb(ip); 128521496Ssklower ipnxt = ip->nsp_next; 128621496Ssklower if (cb == 0) 128721496Ssklower goto tpgone; 128821496Ssklower for (i = 0; i < TCPT_NTIMERS; i++) { 128921496Ssklower if (cb->s_timer[i] && --cb->s_timer[i] == 0) { 129021496Ssklower (void) spp_usrreq(cb->s_nspcb->nsp_socket, 129121496Ssklower PRU_SLOWTIMO, (struct mbuf *)0, 129221496Ssklower (struct mbuf *)i, (struct mbuf *)0); 129321496Ssklower if (ipnxt->nsp_prev != ip) 129421496Ssklower goto tpgone; 129521496Ssklower } 129621496Ssklower } 129721496Ssklower cb->s_idle++; 129821496Ssklower if (cb->s_rtt) 129921496Ssklower cb->s_rtt++; 130021496Ssklower tpgone: 130121496Ssklower ip = ipnxt; 130221496Ssklower } 130321496Ssklower spp_iss += SPP_ISSINCR/PR_SLOWHZ; /* increment iss */ 130421496Ssklower splx(s); 130521496Ssklower } 130621496Ssklower 130721496Ssklower float spp_backoff[TCP_MAXRXTSHIFT] = 130821496Ssklower { 1.0, 1.2, 1.4, 1.7, 2.0, 3.0, 5.0, 8.0, 16.0, 32.0 }; 130924412Swalsh int sppexprexmtbackoff = 0; 131021496Ssklower /* 131124615Ssklower * SPP timer processing. 131221496Ssklower */ 131321496Ssklower struct sppcb * 131421496Ssklower spp_timers(cb, timer) 131521496Ssklower register struct sppcb *cb; 131621496Ssklower int timer; 131721496Ssklower { 131821496Ssklower 131921496Ssklower cb->s_force = 1 + timer; 132021496Ssklower switch (timer) { 132121496Ssklower 132221496Ssklower /* 132321496Ssklower * 2 MSL timeout in shutdown went off. Delete connection 132421496Ssklower * control block. 132521496Ssklower */ 132621496Ssklower case TCPT_2MSL: 132721496Ssklower cb = spp_close(cb); 132821496Ssklower break; 132921496Ssklower 133021496Ssklower /* 133121496Ssklower * Retransmission timer went off. Message has not 133221496Ssklower * been acked within retransmit interval. Back off 133321496Ssklower * to a longer retransmit interval and retransmit all 133421496Ssklower * unacknowledged messages in the window. 133521496Ssklower */ 133621496Ssklower case TCPT_REXMT: 133721496Ssklower cb->s_rxtshift++; 133821496Ssklower if (cb->s_rxtshift > TCP_MAXRXTSHIFT) { 133921496Ssklower cb = spp_drop(cb, ETIMEDOUT); 134021496Ssklower break; 134121496Ssklower } 134221496Ssklower (void) spp_output(cb, (struct mbuf *) 0); 134321496Ssklower TCPT_RANGESET(cb->s_timer[TCPT_REXMT], 134421496Ssklower (int)cb->s_srtt, TCPTV_MIN, TCPTV_MAX); 134524412Swalsh if (sppexprexmtbackoff) { 134621496Ssklower TCPT_RANGESET(cb->s_timer[TCPT_REXMT], 134721496Ssklower cb->s_timer[TCPT_REXMT] << cb->s_rxtshift, 134821496Ssklower TCPTV_MIN, TCPTV_MAX); 134921496Ssklower } else { 135021496Ssklower TCPT_RANGESET(cb->s_timer[TCPT_REXMT], 135121496Ssklower cb->s_timer[TCPT_REXMT] * 135221496Ssklower spp_backoff[cb->s_rxtshift - 1], 135321496Ssklower TCPTV_MIN, TCPTV_MAX); 135421496Ssklower } 135521496Ssklower break; 135621496Ssklower 135721496Ssklower /* 135821496Ssklower * Persistance timer into zero window. 135921496Ssklower * Force a probe to be sent. 136021496Ssklower */ 136121496Ssklower case TCPT_PERSIST: 136221496Ssklower (void) spp_output(cb, (struct mbuf *) 0); 136321496Ssklower spp_setpersist(cb); 136421496Ssklower break; 136521496Ssklower 136621496Ssklower /* 136721496Ssklower * Keep-alive timer went off; send something 136821496Ssklower * or drop connection if idle for too long. 136921496Ssklower */ 137021496Ssklower case TCPT_KEEP: 137121496Ssklower if (cb->s_state < TCPS_ESTABLISHED) 137221496Ssklower goto dropit; 137321496Ssklower if (cb->s_nspcb->nsp_socket->so_options & SO_KEEPALIVE) { 137421496Ssklower if (cb->s_idle >= TCPTV_MAXIDLE) 137521496Ssklower goto dropit; 137621496Ssklower (void) spp_output(cb, (struct mbuf *) 0); 137721496Ssklower } else 137821496Ssklower cb->s_idle = 0; 137921496Ssklower cb->s_timer[TCPT_KEEP] = TCPTV_KEEP; 138021496Ssklower break; 138121496Ssklower dropit: 138221496Ssklower cb = spp_drop(cb, ETIMEDOUT); 138321496Ssklower break; 138421496Ssklower } 138521496Ssklower return (cb); 138621496Ssklower } 1387