123215Smckusick /* 229171Smckusick * Copyright (c) 1984, 1985, 1986 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*29925Skarels * @(#)spp_usrreq.c 7.2 (Berkeley) 10/28/86 723215Smckusick */ 821496Ssklower 921496Ssklower #include "param.h" 10*29925Skarels #include "systm.h" 1121496Ssklower #include "dir.h" 1221496Ssklower #include "user.h" 1321496Ssklower #include "mbuf.h" 1421496Ssklower #include "protosw.h" 1521496Ssklower #include "socket.h" 1621496Ssklower #include "socketvar.h" 1721496Ssklower #include "errno.h" 1821496Ssklower 1921496Ssklower #include "../net/if.h" 2021496Ssklower #include "../net/route.h" 2121496Ssklower #include "../netinet/tcp_fsm.h" 2221496Ssklower #include "../netinet/tcp_timer.h" 2321496Ssklower 2421496Ssklower #include "ns.h" 2521496Ssklower #include "ns_pcb.h" 2621496Ssklower #include "idp.h" 2721496Ssklower #include "idp_var.h" 2821496Ssklower #include "ns_error.h" 2921496Ssklower #include "sp.h" 3021496Ssklower #include "spidp.h" 3121496Ssklower #include "spp_var.h" 3221496Ssklower #include "spp_debug.h" 3321496Ssklower 3421496Ssklower /* 3521496Ssklower * SP protocol implementation. 3621496Ssklower */ 3721496Ssklower spp_init() 3821496Ssklower { 3921496Ssklower 4021496Ssklower spp_iss = 1; /* WRONG !! should fish it out of TODR */ 4121496Ssklower } 4221496Ssklower struct spidp spp_savesi; 4321496Ssklower int traceallspps = 0; 4421496Ssklower extern int sppconsdebug; 4524615Ssklower int spp_hardnosed; 4625037Ssklower int spp_use_delack = 0; 4721496Ssklower 4824615Ssklower /*ARGSUSED*/ 4924615Ssklower spp_input(m, nsp, ifp) 5021496Ssklower register struct mbuf *m; 5124047Ssklower register struct nspcb *nsp; 5224615Ssklower struct ifnet *ifp; 5321496Ssklower { 5421496Ssklower register struct sppcb *cb; 5521496Ssklower register struct spidp *si = mtod(m, struct spidp *); 5621496Ssklower register struct socket *so; 5724225Ssklower short ostate; 5821496Ssklower int dropsocket = 0; 5921496Ssklower 6021496Ssklower 6124330Ssklower if (nsp == 0) { 6224047Ssklower panic("No nspcb in spp_input\n"); 6323979Ssklower return; 6423979Ssklower } 6521496Ssklower 6621496Ssklower cb = nstosppcb(nsp); 6721496Ssklower if (cb == 0) goto bad; 6821496Ssklower 6924047Ssklower if (m->m_len < sizeof(*si)) { 7024330Ssklower if ((m = m_pullup(m, sizeof(*si))) == 0) { 7124047Ssklower spp_istat.hdrops++; 7224047Ssklower return; 7324047Ssklower } 7424047Ssklower si = mtod(m, struct spidp *); 7524047Ssklower } 7621496Ssklower si->si_seq = ntohs(si->si_seq); 7721496Ssklower si->si_ack = ntohs(si->si_ack); 7821496Ssklower si->si_alo = ntohs(si->si_alo); 7921496Ssklower 8021496Ssklower so = nsp->nsp_socket; 8121496Ssklower if (so->so_options & SO_DEBUG || traceallspps) { 8221496Ssklower ostate = cb->s_state; 8321496Ssklower spp_savesi = *si; 8421496Ssklower } 8521496Ssklower if (so->so_options & SO_ACCEPTCONN) { 8621496Ssklower so = sonewconn(so); 8721496Ssklower if (so == 0) { 8821496Ssklower spp_istat.nonucn++; 8921496Ssklower goto drop; 9021496Ssklower } 9121496Ssklower /* 9221496Ssklower * This is ugly, but .... 9321496Ssklower * 9421496Ssklower * Mark socket as temporary until we're 9521496Ssklower * committed to keeping it. The code at 9621496Ssklower * ``drop'' and ``dropwithreset'' check the 9721496Ssklower * flag dropsocket to see if the temporary 9821496Ssklower * socket created here should be discarded. 9921496Ssklower * We mark the socket as discardable until 10021496Ssklower * we're committed to it below in TCPS_LISTEN. 10121496Ssklower */ 10221496Ssklower dropsocket++; 10321496Ssklower nsp = (struct nspcb *)so->so_pcb; 10421496Ssklower nsp->nsp_laddr = si->si_dna; 10521496Ssklower cb = nstosppcb(nsp); 10621496Ssklower cb->s_state = TCPS_LISTEN; 10721496Ssklower } 10821496Ssklower 10921496Ssklower /* 11021496Ssklower * Packet received on connection. 11121496Ssklower * reset idle time and keep-alive timer; 11221496Ssklower */ 11321496Ssklower cb->s_idle = 0; 11421496Ssklower cb->s_timer[TCPT_KEEP] = TCPTV_KEEP; 11521496Ssklower 11621496Ssklower switch (cb->s_state) { 11723515Ssklower 11821496Ssklower case TCPS_LISTEN:{ 11921496Ssklower struct mbuf *am; 12021496Ssklower register struct sockaddr_ns *sns; 12121496Ssklower struct ns_addr laddr; 12221496Ssklower 12321496Ssklower /* 12421496Ssklower * If somebody here was carying on a conversation 12521496Ssklower * and went away, and his pen pal thinks he can 12621496Ssklower * still talk, we get the misdirected packet. 12721496Ssklower */ 12821496Ssklower if (spp_hardnosed && (si->si_did != 0 || si->si_seq != 0)) { 12921496Ssklower spp_istat.gonawy++; 13021496Ssklower goto dropwithreset; 13121496Ssklower } 13221496Ssklower am = m_get(M_DONTWAIT, MT_SONAME); 13321496Ssklower if (am == NULL) 13421496Ssklower goto drop; 13521496Ssklower am->m_len = sizeof (struct sockaddr_ns); 13621496Ssklower sns = mtod(am, struct sockaddr_ns *); 13721496Ssklower sns->sns_family = AF_NS; 13821496Ssklower sns->sns_addr = si->si_sna; 13921496Ssklower laddr = nsp->nsp_laddr; 14021496Ssklower if (ns_nullhost(laddr)) 14121496Ssklower nsp->nsp_laddr = si->si_dna; 14221496Ssklower if (ns_pcbconnect(nsp, am)) { 14321496Ssklower nsp->nsp_laddr = laddr; 14421496Ssklower (void) m_free(am); 14521496Ssklower spp_istat.noconn++; 14621496Ssklower goto drop; 14721496Ssklower } 14821496Ssklower (void) m_free(am); 14921496Ssklower spp_template(cb); 15024732Ssklower dropsocket = 0; /* committed to socket */ 15121496Ssklower cb->s_did = si->si_sid; 15221496Ssklower cb->s_rack = si->si_ack; 15321496Ssklower cb->s_ralo = si->si_alo; 15424732Ssklower #define THREEWAYSHAKE 15524732Ssklower #ifdef THREEWAYSHAKE 15624732Ssklower cb->s_state = TCPS_SYN_RECEIVED; 15724732Ssklower cb->s_force = 1 + TCPT_REXMT; 15824732Ssklower cb->s_timer[TCPT_REXMT] = 2 * TCPTV_MIN; 15921496Ssklower } 16021496Ssklower break; 16124732Ssklower /* 16224732Ssklower * This state means that we have heard a response 16324732Ssklower * to our acceptance of their connection 16424732Ssklower * It is probably logically unnecessary in this 16524732Ssklower * implementation. 16624732Ssklower */ 16724732Ssklower case TCPS_SYN_RECEIVED: 16824732Ssklower if (si->si_did!=cb->s_sid) { 16924732Ssklower spp_istat.wrncon++; 17024732Ssklower goto drop; 17124732Ssklower } 17224732Ssklower #endif 17324732Ssklower nsp->nsp_fport = si->si_sport; 17424732Ssklower cb->s_timer[TCPT_REXMT] = 0; 17524732Ssklower cb->s_timer[TCPT_KEEP] = TCPTV_KEEP; 17624732Ssklower soisconnected(so); 17724732Ssklower cb->s_state = TCPS_ESTABLISHED; 17824732Ssklower break; 17921496Ssklower 18021496Ssklower /* 18121496Ssklower * This state means that we have gotten a response 18221496Ssklower * to our attempt to establish a connection. 18323979Ssklower * We fill in the data from the other side, 18423979Ssklower * telling us which port to respond to, instead of the well- 18523979Ssklower * known one we might have sent to in the first place. 18621496Ssklower * We also require that this is a response to our 18723979Ssklower * connection id. 18821496Ssklower */ 18921496Ssklower case TCPS_SYN_SENT: 19021496Ssklower if (si->si_did!=cb->s_sid) { 19121496Ssklower spp_istat.notme++; 19221496Ssklower goto drop; 19321496Ssklower } 19421496Ssklower cb->s_did = si->si_sid; 19521496Ssklower cb->s_rack = si->si_ack; 19621496Ssklower cb->s_ralo = si->si_alo; 19721496Ssklower cb->s_dport = nsp->nsp_fport = si->si_sport; 19821496Ssklower cb->s_timer[TCPT_REXMT] = 0; 19921496Ssklower cb->s_flags |= SF_AK; 20021496Ssklower soisconnected(so); 20121496Ssklower cb->s_state = TCPS_ESTABLISHED; 20221496Ssklower } 20321496Ssklower if (so->so_options & SO_DEBUG || traceallspps) 20424225Ssklower spp_trace(SA_INPUT, (u_char)ostate, cb, &spp_savesi, 0); 20521496Ssklower 20621496Ssklower m->m_len -= sizeof (struct idp); 20721496Ssklower m->m_off += sizeof (struct idp); 20821496Ssklower 20925037Ssklower if (spp_reass(cb, si)) { 21025334Ssklower m_freem(m); 21121496Ssklower } 21225037Ssklower (void) spp_output(cb, (struct mbuf *)0); 21321496Ssklower return; 21421496Ssklower 21521496Ssklower dropwithreset: 21621496Ssklower if (dropsocket) 21721496Ssklower (void) soabort(so); 21821496Ssklower si->si_seq = ntohs(si->si_seq); 21921496Ssklower si->si_ack = ntohs(si->si_ack); 22021496Ssklower si->si_alo = ntohs(si->si_alo); 22121496Ssklower ns_error(dtom(si), NS_ERR_NOSOCK, 0); 22221496Ssklower if (cb->s_nspcb->nsp_socket->so_options & SO_DEBUG || traceallspps) 22324225Ssklower spp_trace(SA_DROP, (u_char)ostate, cb, &spp_savesi, 0); 22421496Ssklower return; 22521496Ssklower 22621496Ssklower drop: 22721496Ssklower bad: 22824330Ssklower if (cb == 0 || cb->s_nspcb->nsp_socket->so_options & SO_DEBUG || traceallspps) 22924225Ssklower spp_trace(SA_DROP, (u_char)ostate, cb, &spp_savesi, 0); 23021496Ssklower m_freem(m); 23121496Ssklower } 23221496Ssklower 23321496Ssklower /* 23421496Ssklower * This is structurally similar to the tcp reassembly routine 23521496Ssklower * but its function is somewhat different: It merely queues 23621496Ssklower * packets up, and suppresses duplicates. 23721496Ssklower */ 23825037Ssklower spp_reass(cb, si) 23921496Ssklower register struct sppcb *cb; 24021496Ssklower register struct spidp *si; 24121496Ssklower { 24221496Ssklower register struct spidp_q *q; 24321496Ssklower register struct mbuf *m; 24421496Ssklower struct socket *so = cb->s_nspcb->nsp_socket; 24521496Ssklower struct sockbuf *sb = & (so->so_rcv); 24621496Ssklower char packetp = cb->s_flags & SF_HI; 24721496Ssklower char wakeup = 0; 24821496Ssklower 24921496Ssklower 25024330Ssklower if (si == SI(0)) 25121496Ssklower goto present; 25221496Ssklower /* 25321496Ssklower * Update our news from them. 25421496Ssklower */ 25521496Ssklower if (si->si_cc & SP_SA) 25625037Ssklower cb->s_flags |= (spp_use_delack ? SF_DELACK : SF_AK); 25725037Ssklower if (SSEQ_GT(si->si_ack, cb->s_rack)) { 25821496Ssklower cb->s_rack = si->si_ack; 25921496Ssklower /* 26025037Ssklower * If there are other packets outstanding, 26125037Ssklower * restart the timer for them. 26225037Ssklower */ 26325037Ssklower if (SSEQ_GEQ(cb->s_snt, si->si_ack)) { 26425037Ssklower TCPT_RANGESET(cb->s_timer[TCPT_REXMT], 26525037Ssklower tcp_beta * cb->s_srtt, TCPTV_MIN, 26625037Ssklower TCPTV_MAX); 26725037Ssklower cb->s_rxtshift = 0; 26825037Ssklower } else 26925037Ssklower cb->s_timer[TCPT_REXMT] = 0; 27025037Ssklower /* 27121496Ssklower * If transmit timer is running and timed sequence 27221496Ssklower * number was acked, update smoothed round trip time. 27321496Ssklower */ 27421496Ssklower if (cb->s_rtt && SSEQ_GT(si->si_ack, cb->s_rtseq)) { 27521496Ssklower if (cb->s_srtt == 0) 27621496Ssklower cb->s_srtt = cb->s_rtt; 27721496Ssklower else 27821496Ssklower cb->s_srtt = 27921496Ssklower tcp_alpha * cb->s_srtt + 28021496Ssklower (1 - tcp_alpha) * cb->s_rtt; 28121496Ssklower cb->s_rtt = 0; 28221496Ssklower } 28321496Ssklower } 28425037Ssklower if (SSEQ_GT(si->si_alo, cb->s_ralo)) { 28521496Ssklower cb->s_ralo = si->si_alo; 28621496Ssklower cb->s_timer[TCPT_PERSIST] = 0; 28721496Ssklower } 28821496Ssklower /* 28921496Ssklower * If this is a system packet, we don't need to 29021496Ssklower * queue it up, and won't update acknowledge # 29121496Ssklower */ 29223561Ssklower if (si->si_cc & SP_SP) { 29323561Ssklower m_freem(dtom(si)); 29423515Ssklower return (0); 29523561Ssklower } 29621496Ssklower 29721496Ssklower /* 29821496Ssklower * If this packet number has a sequence number less 29921496Ssklower * than that of the first packet not yet seen coming 30021496Ssklower * from them, this must be a duplicate, so drop. 30121496Ssklower */ 30225037Ssklower if (SSEQ_LT(si->si_seq, cb->s_ack)) { 30323979Ssklower spp_istat.bdreas++; 30424330Ssklower if (si->si_seq == cb->s_ack-1) 30523979Ssklower spp_istat.lstdup++; 30623515Ssklower return (1); 30723979Ssklower } 30821496Ssklower /* 30921496Ssklower * If this packet number is higher than that which 31021496Ssklower * we have allocated refuse it, unless urgent 31121496Ssklower */ 31225037Ssklower if (SSEQ_GT(si->si_seq, cb->s_alo)) { 31325037Ssklower if (si->si_cc & SP_OB) { 31425037Ssklower if (SSEQ_GT(si->si_seq, cb->s_alo + 60)) { 31525037Ssklower ns_error(dtom(si), NS_ERR_FULLUP, 0); 31625037Ssklower return (0); 31725037Ssklower } /* else queue this packet; */ 31825037Ssklower } else { 31925037Ssklower spp_istat.notyet++; 32025037Ssklower return (1); 32125037Ssklower } 32221496Ssklower } 32321496Ssklower 32421496Ssklower /* 32521496Ssklower * Loop through all packets queued up to insert in 32621496Ssklower * appropriate sequence. 32721496Ssklower */ 32821496Ssklower 32921496Ssklower for (q = cb->s_q.si_next; q!=&cb->s_q; q = q->si_next) { 33024330Ssklower if (si->si_seq == SI(q)->si_seq) return (1); /*duplicate */ 33125037Ssklower if (SSEQ_LT(si->si_seq, SI(q)->si_seq)) break; 33221496Ssklower } 33325037Ssklower insque(si, q->si_prev); 33425037Ssklower /* 33525037Ssklower * If this packet is urgent, inform process 33625037Ssklower */ 33725037Ssklower if (si->si_cc & SP_OB) { 33825037Ssklower cb->s_iobc = ((char *)si)[1 + sizeof(*si)]; 33925037Ssklower sohasoutofband(so); 34025037Ssklower cb->s_oobflags |= SF_IOOB; 34125037Ssklower } 34221496Ssklower present: 34321496Ssklower #define SPINC sizeof(struct sphdr) 34421496Ssklower /* 34521496Ssklower * Loop through all packets queued up to update acknowledge 34621496Ssklower * number, and present all acknowledged data to user; 34721496Ssklower * If in packet interface mode, show packet headers. 34821496Ssklower */ 34921496Ssklower for (q = cb->s_q.si_next; q!=&cb->s_q; q = q->si_next) { 35024330Ssklower if (SI(q)->si_seq == cb->s_ack) { 35121496Ssklower cb->s_ack++; 35221496Ssklower m = dtom(q); 35321496Ssklower if (SI(q)->si_cc & SP_OB) { 35425037Ssklower cb->s_oobflags &= ~SF_IOOB; 35521496Ssklower if (sb->sb_cc) 35621496Ssklower so->so_oobmark = sb->sb_cc; 35721496Ssklower else 35821496Ssklower so->so_state |= SS_RCVATMARK; 35921496Ssklower } 36021496Ssklower q = q->si_prev; 36121496Ssklower remque(q->si_next); 36221496Ssklower wakeup = 1; 36321496Ssklower if (packetp) { 36425037Ssklower sbappendrecord(sb, m); 36521496Ssklower } else { 36621496Ssklower cb->s_rhdr = *mtod(m, struct sphdr *); 36721496Ssklower m->m_off += SPINC; 36821496Ssklower m->m_len -= SPINC; 36925037Ssklower sbappend(sb, m); 37021496Ssklower } 37121496Ssklower } else 37221496Ssklower break; 37321496Ssklower } 37421496Ssklower if (wakeup) sorwakeup(so); 37523515Ssklower return (0); 37621496Ssklower } 37721496Ssklower 37821496Ssklower spp_ctlinput(cmd, arg) 37921496Ssklower int cmd; 38021496Ssklower caddr_t arg; 38121496Ssklower { 38221496Ssklower struct ns_addr *na; 38321496Ssklower extern u_char nsctlerrmap[]; 38421496Ssklower extern spp_abort(); 38524225Ssklower extern struct nspcb *idp_drop(); 38623979Ssklower struct ns_errp *errp; 38723979Ssklower struct nspcb *nsp; 38824615Ssklower struct sockaddr_ns *sns; 38921496Ssklower int type; 39021496Ssklower 39121496Ssklower if (cmd < 0 || cmd > PRC_NCMDS) 39221496Ssklower return; 39321496Ssklower type = NS_ERR_UNREACH_HOST; 39421496Ssklower 39521496Ssklower switch (cmd) { 39623515Ssklower 39721496Ssklower case PRC_ROUTEDEAD: 39821496Ssklower case PRC_QUENCH: 39921496Ssklower break; 40021496Ssklower 40121496Ssklower case PRC_IFDOWN: 40221496Ssklower case PRC_HOSTDEAD: 40321496Ssklower case PRC_HOSTUNREACH: 40424615Ssklower sns = (struct sockaddr_ns *)arg; 40524615Ssklower if (sns->sns_family != AF_NS) 40624615Ssklower return; 40724615Ssklower na = &sns->sns_addr; 40821496Ssklower break; 40921496Ssklower 41021496Ssklower default: 41123979Ssklower errp = (struct ns_errp *)arg; 41223979Ssklower na = &errp->ns_err_idp.idp_dna; 41323979Ssklower type = errp->ns_err_num; 41424225Ssklower type = ntohs((u_short)type); 41521496Ssklower } 41621496Ssklower switch (type) { 41723515Ssklower 41821496Ssklower case NS_ERR_UNREACH_HOST: 41923979Ssklower ns_pcbnotify(na, (int)nsctlerrmap[cmd], spp_abort, (long) 0); 42021496Ssklower break; 42123515Ssklower 42221496Ssklower case NS_ERR_TOO_BIG: 42323979Ssklower case NS_ERR_NOSOCK: 42423979Ssklower nsp = ns_pcblookup(na, errp->ns_err_idp.idp_sna.x_port, 42523979Ssklower NS_WILDCARD); 42623979Ssklower if (nsp) { 42723979Ssklower if(nsp->nsp_pcb) 42824225Ssklower (void) spp_drop((struct sppcb *)nsp->nsp_pcb, 42924225Ssklower (int)nsctlerrmap[cmd]); 43023979Ssklower else 43124225Ssklower (void) idp_drop(nsp, (int)nsctlerrmap[cmd]); 43223979Ssklower } 43321496Ssklower } 43421496Ssklower } 43521496Ssklower 43624225Ssklower #ifdef notdef 43721496Ssklower int 43821496Ssklower spp_fixmtu(nsp) 43921496Ssklower register struct nspcb *nsp; 44021496Ssklower { 44121496Ssklower register struct sppcb *cb = (struct sppcb *)(nsp->nsp_pcb); 44221496Ssklower register struct mbuf *m; 44321496Ssklower register struct spidp *si; 44421496Ssklower struct ns_errp *ep; 44521496Ssklower struct sockbuf *sb; 44621496Ssklower int badseq, len; 44721496Ssklower struct mbuf *firstbad, *m0; 44821496Ssklower 44921496Ssklower if (cb) { 45021496Ssklower /* 45121496Ssklower * The notification that we have sent 45221496Ssklower * too much is bad news -- we will 45321496Ssklower * have to go through queued up so far 45421496Ssklower * splitting ones which are too big and 45521496Ssklower * reassigning sequence numbers and checksums. 45621496Ssklower * we should then retransmit all packets from 45721496Ssklower * one above the offending packet to the last one 45821496Ssklower * we had sent (or our allocation) 45921496Ssklower * then the offending one so that the any queued 46021496Ssklower * data at our destination will be discarded. 46121496Ssklower */ 46221496Ssklower ep = (struct ns_errp *)nsp->nsp_notify_param; 46321496Ssklower sb = &nsp->nsp_socket->so_snd; 46421496Ssklower cb->s_mtu = ep->ns_err_param; 46521496Ssklower badseq = SI(&ep->ns_err_idp)->si_seq; 46621496Ssklower for (m = sb->sb_mb; m; m = m->m_act) { 46721496Ssklower si = mtod(m, struct spidp *); 46821496Ssklower if (si->si_seq == badseq) 46921496Ssklower break; 47021496Ssklower } 47124330Ssklower if (m == 0) return; 47221496Ssklower firstbad = m; 47321496Ssklower /*for (;;) {*/ 47421496Ssklower /* calculate length */ 47521496Ssklower for (m0 = m, len = 0; m ; m = m->m_next) 47621496Ssklower len += m->m_len; 47721496Ssklower if (len > cb->s_mtu) { 47821496Ssklower } 47921496Ssklower /* FINISH THIS 48021496Ssklower } */ 48121496Ssklower } 48221496Ssklower } 48324225Ssklower #endif 48421496Ssklower 48521496Ssklower int spp_output_cnt = 0; 48623979Ssklower 48721496Ssklower spp_output(cb, m0) 48821496Ssklower register struct sppcb *cb; 48921496Ssklower struct mbuf *m0; 49021496Ssklower { 49121496Ssklower struct socket *so = cb->s_nspcb->nsp_socket; 49221496Ssklower register struct mbuf *m; 49321496Ssklower register struct spidp *si = (struct spidp *) 0; 49421496Ssklower register struct sockbuf *sb = &(so->so_snd); 49521496Ssklower register int len = 0; 49624330Ssklower int error = 0; 49724330Ssklower u_short lookfor = 0; 49821496Ssklower struct mbuf *mprev; 49921496Ssklower extern int idpcksum; 50021496Ssklower 50124330Ssklower if (m0) { 50224615Ssklower int mtu = cb->s_mtu; 50324615Ssklower int datalen; 50424615Ssklower /* 50524615Ssklower * Make sure that packet isn't too big. 50624615Ssklower */ 50721496Ssklower for (m = m0; m ; m = m->m_next) { 50821496Ssklower mprev = m; 50921496Ssklower len += m->m_len; 51021496Ssklower } 51124615Ssklower datalen = (cb->s_flags & SF_HO) ? 51224615Ssklower len - sizeof (struct sphdr) : len; 51324615Ssklower if (datalen > mtu) { 51421496Ssklower if (cb->s_flags & SF_PI) { 51521496Ssklower m_freem(m0); 51623515Ssklower return (EMSGSIZE); 51721496Ssklower } else { 51821496Ssklower int off = 0; 51924615Ssklower int oldEM = cb->s_cc & SP_EM; 52024615Ssklower 52124615Ssklower cb->s_cc &= ~SP_EM; 52221496Ssklower while (len > mtu) { 52321496Ssklower m = m_copy(m0, off, mtu); 52424330Ssklower if (m == NULL) { 52524615Ssklower error = ENOBUFS; 52624615Ssklower goto bad_copy; 52723515Ssklower } 52821496Ssklower error = spp_output(cb, m); 52921496Ssklower if (error) { 53024615Ssklower bad_copy: 53124615Ssklower cb->s_cc |= oldEM; 53221496Ssklower m_freem(m0); 53324615Ssklower return(error); 53421496Ssklower } 53521496Ssklower m_adj(m0, mtu); 53621496Ssklower len -= mtu; 53721496Ssklower } 53824615Ssklower cb->s_cc |= oldEM; 53921496Ssklower } 54021496Ssklower } 54124330Ssklower /* 54224330Ssklower * Force length even, by adding a "garbage byte" if 54324330Ssklower * necessary. 54424330Ssklower */ 54521496Ssklower if (len & 1) { 54623979Ssklower m = mprev; 54724330Ssklower if (m->m_len + m->m_off < MMAXOFF) 54821496Ssklower m->m_len++; 54924330Ssklower else { 55021496Ssklower struct mbuf *m1 = m_get(M_DONTWAIT, MT_DATA); 55121496Ssklower 55221496Ssklower if (m1 == 0) { 55321496Ssklower m_freem(m0); 55421496Ssklower return (ENOBUFS); 55521496Ssklower } 55621496Ssklower m1->m_len = 1; 55721496Ssklower m1->m_off = MMAXOFF - 1; 55824330Ssklower m->m_next = m1; 55921496Ssklower } 56021496Ssklower } 56121496Ssklower m = m_get(M_DONTWAIT, MT_HEADER); 56221496Ssklower if (m == 0) { 56321496Ssklower m_freem(m0); 56423515Ssklower return (ENOBUFS); 56521496Ssklower } 56621496Ssklower /* 56721496Ssklower * Fill in mbuf with extended SP header 56821496Ssklower * and addresses and length put into network format. 56925623Ssklower * Long align so prepended ip headers will work on Gould. 57021496Ssklower */ 57125623Ssklower m->m_off = MMAXOFF - sizeof (struct spidp) - 2; 57221496Ssklower m->m_len = sizeof (struct spidp); 57321496Ssklower m->m_next = m0; 57421496Ssklower si = mtod(m, struct spidp *); 57521496Ssklower *si = cb->s_shdr; 57621496Ssklower if ((cb->s_flags & SF_PI) && (cb->s_flags & SF_HO)) { 57724330Ssklower register struct sphdr *sh; 57824330Ssklower if (m0->m_len < sizeof (*sh)) { 57924330Ssklower if((m0 = m_pullup(m0, sizeof(*sh))) == NULL) { 58024330Ssklower (void) m_free(m); 58124330Ssklower m_freem(m0); 58224330Ssklower return (EINVAL); 58324330Ssklower } 58424330Ssklower m->m_next = m0; 58524330Ssklower } 58624330Ssklower sh = mtod(m0, struct sphdr *); 58721496Ssklower si->si_dt = sh->sp_dt; 58821496Ssklower si->si_cc |= sh->sp_cc & SP_EM; 58921496Ssklower m0->m_len -= sizeof (*sh); 59021496Ssklower m0->m_off += sizeof (*sh); 59121496Ssklower len -= sizeof (*sh); 59221496Ssklower } 59321496Ssklower len += sizeof(*si); 59423979Ssklower if (cb->s_oobflags & SF_SOOB) { 59523979Ssklower /* 59623979Ssklower * Per jqj@cornell: 59723979Ssklower * make sure OB packets convey exactly 1 byte. 59823979Ssklower * If the packet is 1 byte or larger, we 59923979Ssklower * have already guaranted there to be at least 60023979Ssklower * one garbage byte for the checksum, and 60123979Ssklower * extra bytes shouldn't hurt! 60223979Ssklower */ 60323979Ssklower if (len > sizeof(*si)) { 60423979Ssklower si->si_cc |= SP_OB; 60523979Ssklower len = (1 + sizeof(*si)); 60623979Ssklower } 60723979Ssklower } 60824225Ssklower si->si_len = htons((u_short)len); 60921496Ssklower /* 61021496Ssklower * queue stuff up for output 61121496Ssklower */ 61225037Ssklower sbappendrecord(sb, m); 61321496Ssklower cb->s_seq++; 61421496Ssklower } 61521496Ssklower /* 61621496Ssklower * update window 61721496Ssklower */ 61821496Ssklower { 61924225Ssklower register struct sockbuf *sb2 = &so->so_rcv; 62025623Ssklower int credit = ((((int)sb2->sb_mbmax) - (int)sb2->sb_mbcnt) / 62124732Ssklower ((short)cb->s_mtu)); 62224732Ssklower int alo = cb->s_ack + (credit > 0 ? credit : 0) - 1; 62321496Ssklower 62424732Ssklower if (cb->s_alo < alo) { 62524732Ssklower /* If the amount we are raising the window 62624732Ssklower is more than his remaining headroom, tell 62724732Ssklower him about it. In particular, if he is at 62824732Ssklower his limit, any amount at all will do! */ 62924732Ssklower u_short raise = alo - cb->s_alo; 63024732Ssklower u_short headroom = 1 + cb->s_alo - cb->s_ack; 63124732Ssklower 63224732Ssklower if(SSEQ_LT(headroom, raise)) 63324732Ssklower cb->s_flags |= SF_AK; 63424330Ssklower cb->s_alo = alo; 63524732Ssklower } 63621496Ssklower } 63721496Ssklower 63821496Ssklower if (cb->s_oobflags & SF_SOOB) { 63921496Ssklower /* 64021496Ssklower * must transmit this out of band packet 64121496Ssklower */ 64221496Ssklower cb->s_oobflags &= ~ SF_SOOB; 64321496Ssklower } else { 64421496Ssklower /* 64521496Ssklower * Decide what to transmit: 64625168Ssklower * If it is time to retransmit a packet, 64725168Ssklower * send that. 64821496Ssklower * If we have a new packet, send that 64921496Ssklower * (So long as it is in our allocation) 65021496Ssklower * Otherwise, see if it time to bang on them 65121496Ssklower * to ask for our current allocation. 65221496Ssklower */ 65325168Ssklower if (cb->s_force == (1+TCPT_REXMT)) { 65425168Ssklower lookfor = cb->s_rack; 65525168Ssklower } else if (SSEQ_LT(cb->s_snt, cb->s_ralo)) { 65621496Ssklower lookfor = cb->s_snt + 1; 65721496Ssklower } else if (SSEQ_LT(cb->s_ralo, cb->s_seq)) { 65821496Ssklower lookfor = 0; 65924330Ssklower if (cb->s_timer[TCPT_PERSIST] == 0) { 66021496Ssklower spp_setpersist(cb); 66124330Ssklower /* tcp has cb->s_rxtshift = 0; here */ 66221496Ssklower } 66321496Ssklower } 66421496Ssklower m = sb->sb_mb; 66524330Ssklower while (m) { 66621496Ssklower si = mtod(m, struct spidp *); 66721496Ssklower m = m->m_act; 66821496Ssklower if (SSEQ_LT(si->si_seq, cb->s_rack)) { 66921496Ssklower if ((sb->sb_flags & SB_WAIT) 67021496Ssklower || so->so_snd.sb_sel) 67121496Ssklower sowwakeup(so); 67221496Ssklower sbdroprecord(sb); 67321496Ssklower si = 0; 67421496Ssklower continue; 67521496Ssklower } 67621496Ssklower if (SSEQ_LT(si->si_seq, lookfor)) 67721496Ssklower continue; 67821496Ssklower break; 67921496Ssklower } 68024330Ssklower if (si && (si->si_seq != lookfor)) 68124330Ssklower si = 0; 68221496Ssklower } 68321496Ssklower cb->s_want = lookfor; 68421496Ssklower 68521496Ssklower if (si) { 68621496Ssklower /* 68721496Ssklower * must make a copy of this packet for 68821496Ssklower * idp_output to monkey with 68921496Ssklower */ 69024330Ssklower m = m_copy(dtom(si), 0, (int)M_COPYALL); 69124330Ssklower if (m == NULL) 69223515Ssklower return (ENOBUFS); 69323515Ssklower m0 = m; 69421496Ssklower si = mtod(m, struct spidp *); 69521496Ssklower } else if (cb->s_force || cb->s_flags & SF_AK) { 69621496Ssklower /* 69721496Ssklower * Must send an acknowledgement or a probe 69821496Ssklower */ 69921496Ssklower m = m_get(M_DONTWAIT, MT_HEADER); 70021496Ssklower if (m == 0) 70123515Ssklower return (ENOBUFS); 70221496Ssklower /* 70321496Ssklower * Fill in mbuf with extended SP header 70421496Ssklower * and addresses and length put into network format. 70521496Ssklower */ 70621496Ssklower m->m_off = MMAXOFF - sizeof (struct spidp); 70721496Ssklower m->m_len = sizeof (*si); 70821496Ssklower m->m_next = 0; 70921496Ssklower si = mtod(m, struct spidp *); 71021496Ssklower *si = cb->s_shdr; 71121496Ssklower si->si_seq = cb->s_snt + 1; 71223979Ssklower si->si_len = htons(sizeof (*si)); 71321496Ssklower si->si_cc |= SP_SP; 71421496Ssklower } 71521496Ssklower /* 71621496Ssklower * Stuff checksum and output datagram. 71721496Ssklower */ 71821496Ssklower if (si) { 71925037Ssklower if (cb->s_flags & (SF_AK|SF_DELACK)) 72025037Ssklower cb->s_flags &= ~(SF_AK|SF_DELACK); 72121496Ssklower /* 72221496Ssklower * If we are almost out of allocation 72321496Ssklower * or one of the timers has gone off 72421496Ssklower * request an ack. 72521496Ssklower */ 72624330Ssklower if (SSEQ_GEQ(cb->s_seq, cb->s_ralo)) 72721496Ssklower si->si_cc |= SP_SA; 72821496Ssklower if (cb->s_force) { 72921496Ssklower si->si_cc |= SP_SA; 73021496Ssklower cb->s_force = 0; 73121496Ssklower } 73224330Ssklower /* 73324330Ssklower * If this is a new packet (and not a system packet), 73423979Ssklower * and we are not currently timing anything, 73523979Ssklower * time this one and ask for an ack. 73621496Ssklower */ 73724330Ssklower if (SSEQ_LT(cb->s_snt, si->si_seq) && (!(si->si_cc & SP_SP))) { 73821496Ssklower cb->s_snt = si->si_seq; 73924330Ssklower if (cb->s_rtt == 0) { 74021496Ssklower cb->s_rtseq = si->si_seq; 74121496Ssklower cb->s_rtt = 1; 74221496Ssklower si->si_cc |= SP_SA; 74321496Ssklower } 74421496Ssklower /* 74521496Ssklower * If the retransmit timer has not been set 74621496Ssklower * and this is a real packet 74721496Ssklower * then start the retransmit timer 74821496Ssklower */ 74924330Ssklower if (cb->s_timer[TCPT_REXMT] == 0) { 75021496Ssklower TCPT_RANGESET(cb->s_timer[TCPT_REXMT], 75121496Ssklower tcp_beta * cb->s_srtt, TCPTV_MIN, 75221496Ssklower TCPTV_MAX); 75321496Ssklower cb->s_rxtshift = 0; 75421496Ssklower } 75521496Ssklower } 75621496Ssklower si->si_seq = htons(si->si_seq); 75721496Ssklower si->si_alo = htons(cb->s_alo); 75821496Ssklower si->si_ack = htons(cb->s_ack); 75921496Ssklower 76021496Ssklower if (idpcksum) { 76121496Ssklower si->si_sum = 0; 76223979Ssklower len = ntohs(si->si_len); 76324330Ssklower if (len & 1) 76424330Ssklower len++; 76521496Ssklower si->si_sum = ns_cksum(dtom(si), len); 76621496Ssklower } else 76721496Ssklower si->si_sum = 0xffff; 76821496Ssklower 76921496Ssklower if (so->so_options & SO_DEBUG || traceallspps) 77021496Ssklower spp_trace(SA_OUTPUT, cb->s_state, cb, si, 0); 77121496Ssklower spp_output_cnt++; 77221496Ssklower if (so->so_options & SO_DONTROUTE) 77321496Ssklower error = ns_output(m, (struct route *)0, NS_ROUTETOIF); 77421496Ssklower else 77521496Ssklower error = ns_output(m, &cb->s_nspcb->nsp_route, 0); 77621496Ssklower if (traceallspps && sppconsdebug) { 77721496Ssklower printf("spp_out: %x\n", error); 77821496Ssklower } 77925168Ssklower if (so->so_options & SO_DEBUG || traceallspps) 78025168Ssklower spp_trace(SA_OUTPUT, cb->s_state, cb, si, 0); 78121496Ssklower } 78223515Ssklower return (error); 78321496Ssklower } 78421496Ssklower 78521496Ssklower /*ARGSUSED*/ 78621496Ssklower spp_ctloutput(req, so, level, name, value) 78721496Ssklower int req; 78821496Ssklower struct socket *so; 78921496Ssklower int name; 79021496Ssklower struct mbuf **value; 79121496Ssklower { 79221496Ssklower register struct mbuf *m; 79321496Ssklower struct nspcb *nsp = sotonspcb(so); 79421496Ssklower register struct sppcb *cb; 79521496Ssklower int mask, error = 0; 79621496Ssklower 79721496Ssklower if (level != NSPROTO_SPP) { 79821496Ssklower /* This will have to be changed when we do more general 79921496Ssklower stacking of protocols */ 80023515Ssklower return (idp_ctloutput(req, so, level, name, value)); 80121496Ssklower } 80221496Ssklower if (nsp == NULL) { 80321496Ssklower error = EINVAL; 80421496Ssklower goto release; 80521496Ssklower } else 80621496Ssklower cb = nstosppcb(nsp); 80721496Ssklower 80821496Ssklower switch (req) { 80923515Ssklower 81021496Ssklower case PRCO_GETOPT: 81124330Ssklower if (value == NULL) 81223515Ssklower return (EINVAL); 81321496Ssklower m = m_get(M_DONTWAIT, MT_DATA); 81424330Ssklower if (m == NULL) 81523515Ssklower return (ENOBUFS); 81621496Ssklower switch (name) { 81723515Ssklower 81821496Ssklower case SO_HEADERS_ON_INPUT: 81921496Ssklower mask = SF_HI; 82021496Ssklower goto get_flags; 82123515Ssklower 82221496Ssklower case SO_HEADERS_ON_OUTPUT: 82321496Ssklower mask = SF_HO; 82421496Ssklower get_flags: 82521496Ssklower m->m_len = sizeof(short); 82621496Ssklower m->m_off = MMAXOFF - sizeof(short); 82721496Ssklower *mtod(m, short *) = cb->s_flags & mask; 82821496Ssklower break; 82923515Ssklower 83024615Ssklower case SO_MTU: 83124615Ssklower m->m_len = sizeof(u_short); 83224615Ssklower m->m_off = MMAXOFF - sizeof(short); 83324615Ssklower *mtod(m, short *) = cb->s_mtu; 83424615Ssklower break; 83524615Ssklower 83621496Ssklower case SO_LAST_HEADER: 83721496Ssklower m->m_len = sizeof(struct sphdr); 83821496Ssklower m->m_off = MMAXOFF - sizeof(struct sphdr); 83921496Ssklower *mtod(m, struct sphdr *) = cb->s_rhdr; 84021496Ssklower break; 84123515Ssklower 84221496Ssklower case SO_DEFAULT_HEADERS: 84321496Ssklower m->m_len = sizeof(struct spidp); 84421496Ssklower m->m_off = MMAXOFF - sizeof(struct sphdr); 84521496Ssklower *mtod(m, struct sphdr *) = cb->s_shdr.si_s; 84625334Ssklower break; 84725334Ssklower 84825334Ssklower default: 84925334Ssklower error = EINVAL; 85021496Ssklower } 85121496Ssklower *value = m; 85221496Ssklower break; 85323515Ssklower 85421496Ssklower case PRCO_SETOPT: 85524615Ssklower if (value == 0 || *value == 0) { 85624615Ssklower error = EINVAL; 85724615Ssklower break; 85824615Ssklower } 85921496Ssklower switch (name) { 86024225Ssklower int *ok; 86121496Ssklower 86221496Ssklower case SO_HEADERS_ON_INPUT: 86321496Ssklower mask = SF_HI; 86421496Ssklower goto set_head; 86523515Ssklower 86621496Ssklower case SO_HEADERS_ON_OUTPUT: 86721496Ssklower mask = SF_HO; 86821496Ssklower set_head: 86924615Ssklower if (cb->s_flags & SF_PI) { 87021496Ssklower ok = mtod(*value, int *); 87121496Ssklower if (*ok) 87221496Ssklower cb->s_flags |= mask; 87321496Ssklower else 87421496Ssklower cb->s_flags &= ~mask; 87521496Ssklower } else error = EINVAL; 87621496Ssklower break; 87723515Ssklower 87824615Ssklower case SO_MTU: 87924615Ssklower cb->s_mtu = *(mtod(*value, u_short *)); 88024615Ssklower break; 88124615Ssklower 88221496Ssklower case SO_DEFAULT_HEADERS: 88321496Ssklower { 88421496Ssklower register struct sphdr *sp 88521496Ssklower = mtod(*value, struct sphdr *); 88621496Ssklower cb->s_dt = sp->sp_dt; 88721496Ssklower cb->s_cc = sp->sp_cc & SP_EM; 88821496Ssklower } 88925334Ssklower break; 89025334Ssklower 89125334Ssklower default: 89225334Ssklower error = EINVAL; 89321496Ssklower } 89424615Ssklower m_freem(*value); 89521496Ssklower break; 89621496Ssklower } 89721496Ssklower release: 89823515Ssklower return (error); 89921496Ssklower } 90021496Ssklower 90121496Ssklower /*ARGSUSED*/ 90221496Ssklower spp_usrreq(so, req, m, nam, rights) 90321496Ssklower struct socket *so; 90421496Ssklower int req; 90521496Ssklower struct mbuf *m, *nam, *rights; 90621496Ssklower { 90721496Ssklower struct nspcb *nsp = sotonspcb(so); 90821496Ssklower register struct sppcb *cb; 90921496Ssklower int s = splnet(); 91021496Ssklower int error = 0, ostate; 91121496Ssklower 91221496Ssklower if (req == PRU_CONTROL) 91321496Ssklower return (ns_control(so, (int)m, (caddr_t)nam, 91421496Ssklower (struct ifnet *)rights)); 91521496Ssklower if (rights && rights->m_len) { 91621496Ssklower error = EINVAL; 91721496Ssklower goto release; 91821496Ssklower } 91921496Ssklower if (nsp == NULL) { 92021496Ssklower if (req != PRU_ATTACH) { 92121496Ssklower error = EINVAL; 92221496Ssklower goto release; 92321496Ssklower } 92421496Ssklower } else 92521496Ssklower cb = nstosppcb(nsp); 92621496Ssklower 92721496Ssklower ostate = cb ? cb->s_state : 0; 92821496Ssklower 92921496Ssklower switch (req) { 93023515Ssklower 93121496Ssklower case PRU_ATTACH: 93221496Ssklower if (nsp != NULL) { 93321496Ssklower error = EISCONN; 93421496Ssklower break; 93521496Ssklower } 93621496Ssklower error = ns_pcballoc(so, &nspcb); 93721496Ssklower if (error) 93821496Ssklower break; 93921496Ssklower error = soreserve(so, 2048, 2048); 94021496Ssklower if (error) 94121496Ssklower break; 94221496Ssklower nsp = sotonspcb(so); 94321496Ssklower { 94425037Ssklower struct mbuf *mm = m_getclr(M_DONTWAIT, MT_PCB); 94521496Ssklower 94624330Ssklower if (mm == NULL) { 94721496Ssklower error = ENOBUFS; 94821496Ssklower break; 94921496Ssklower } 95021496Ssklower cb = mtod(mm, struct sppcb *); 95121496Ssklower cb->s_state = TCPS_LISTEN; 95221496Ssklower cb->s_snt = -1; 95321496Ssklower cb->s_q.si_next = cb->s_q.si_prev = &cb->s_q; 95421496Ssklower cb->s_nspcb = nsp; 95521496Ssklower nsp->nsp_pcb = (caddr_t) cb; 95621496Ssklower } 95721496Ssklower break; 95821496Ssklower 95921496Ssklower case PRU_DETACH: 96021496Ssklower if (nsp == NULL) { 96121496Ssklower error = ENOTCONN; 96221496Ssklower break; 96321496Ssklower } 96421496Ssklower if (cb->s_state > TCPS_LISTEN) 96521496Ssklower cb = spp_disconnect(cb); 96621496Ssklower else 96721496Ssklower cb = spp_close(cb); 96821496Ssklower break; 96921496Ssklower 97021496Ssklower case PRU_BIND: 97121496Ssklower error = ns_pcbbind(nsp, nam); 97221496Ssklower break; 97321496Ssklower 97421496Ssklower case PRU_LISTEN: 97521496Ssklower if (nsp->nsp_lport == 0) 97621496Ssklower error = ns_pcbbind(nsp, (struct mbuf *)0); 97721496Ssklower if (error == 0) 97821496Ssklower cb->s_state = TCPS_LISTEN; 97921496Ssklower break; 98021496Ssklower 98121496Ssklower /* 98221496Ssklower * Initiate connection to peer. 98321496Ssklower * Enter SYN_SENT state, and mark socket as connecting. 98421496Ssklower * Start keep-alive timer, setup prototype header, 98521496Ssklower * Send initial system packet requesting connection. 98621496Ssklower */ 98721496Ssklower case PRU_CONNECT: 98821496Ssklower if (nsp->nsp_lport == 0) { 98921496Ssklower error = ns_pcbbind(nsp, (struct mbuf *)0); 99021496Ssklower if (error) 99121496Ssklower break; 99221496Ssklower } 99321496Ssklower error = ns_pcbconnect(nsp, nam); 99421496Ssklower if (error) 99521496Ssklower break; 99621496Ssklower soisconnecting(so); 99721496Ssklower cb->s_state = TCPS_SYN_SENT; 99821496Ssklower cb->s_did = 0; 99921496Ssklower spp_template(cb); 100021496Ssklower cb->s_timer[TCPT_KEEP] = TCPTV_KEEP; 100121496Ssklower cb->s_force = 1 + TCPTV_KEEP; 100221496Ssklower /* 100321496Ssklower * Other party is required to respond to 100421496Ssklower * the port I send from, but he is not 100521496Ssklower * required to answer from where I am sending to, 100621496Ssklower * so allow wildcarding. 100721496Ssklower * original port I am sending to is still saved in 100821496Ssklower * cb->s_dport. 100921496Ssklower */ 101021496Ssklower nsp->nsp_fport = 0; 101121496Ssklower error = spp_output(cb, (struct mbuf *) 0); 101221496Ssklower break; 101321496Ssklower 101421496Ssklower case PRU_CONNECT2: 101521496Ssklower error = EOPNOTSUPP; 101621496Ssklower break; 101721496Ssklower 101821496Ssklower /* 101921496Ssklower * We may decide later to implement connection closing 102021496Ssklower * handshaking at the spp level optionally. 102121496Ssklower * here is the hook to do it: 102221496Ssklower */ 102321496Ssklower case PRU_DISCONNECT: 102421496Ssklower cb = spp_disconnect(cb); 102521496Ssklower break; 102621496Ssklower 102721496Ssklower /* 102821496Ssklower * Accept a connection. Essentially all the work is 102921496Ssklower * done at higher levels; just return the address 103021496Ssklower * of the peer, storing through addr. 103121496Ssklower */ 103221496Ssklower case PRU_ACCEPT: { 103321496Ssklower struct sockaddr_ns *sns = mtod(nam, struct sockaddr_ns *); 103421496Ssklower 103521496Ssklower nam->m_len = sizeof (struct sockaddr_ns); 103621496Ssklower sns->sns_family = AF_NS; 103721496Ssklower sns->sns_addr = nsp->nsp_faddr; 103821496Ssklower break; 103921496Ssklower } 104021496Ssklower 104121496Ssklower case PRU_SHUTDOWN: 104221496Ssklower socantsendmore(so); 104321496Ssklower cb = spp_usrclosed(cb); 104421496Ssklower if (cb) 104521496Ssklower error = spp_output(cb, (struct mbuf *) 0); 104621496Ssklower break; 104721496Ssklower 104821496Ssklower /* 104921496Ssklower * After a receive, possibly send acknowledgment 105021496Ssklower * updating allocation. 105121496Ssklower */ 105221496Ssklower case PRU_RCVD: 105321496Ssklower (void) spp_output(cb, (struct mbuf *) 0); 105421496Ssklower break; 105521496Ssklower 105621496Ssklower case PRU_ABORT: 105724225Ssklower (void) spp_drop(cb, ECONNABORTED); 105821496Ssklower break; 105921496Ssklower 106021496Ssklower case PRU_SENSE: 106121496Ssklower case PRU_CONTROL: 106221496Ssklower m = NULL; 106321496Ssklower error = EOPNOTSUPP; 106421496Ssklower break; 106521496Ssklower 106621496Ssklower case PRU_RCVOOB: 106725037Ssklower if ((cb->s_oobflags & SF_IOOB) || so->so_oobmark || 106825037Ssklower (so->so_state & SS_RCVATMARK)) { 106925037Ssklower m->m_len = 1; 107025037Ssklower *mtod(m, caddr_t) = cb->s_iobc; 107124732Ssklower break; 107224732Ssklower } 107325037Ssklower error = EINVAL; 107421496Ssklower break; 107521496Ssklower 107621496Ssklower case PRU_SENDOOB: 107721496Ssklower if (sbspace(&so->so_snd) < -512) { 107821496Ssklower error = ENOBUFS; 107921496Ssklower break; 108021496Ssklower } 108121496Ssklower cb->s_oobflags |= SF_SOOB; 108225623Ssklower /* fall into */ 108325623Ssklower case PRU_SEND: 108421496Ssklower error = spp_output(cb, m); 108521496Ssklower m = NULL; 108621496Ssklower break; 108721496Ssklower 108821496Ssklower case PRU_SOCKADDR: 108921496Ssklower ns_setsockaddr(nsp, nam); 109021496Ssklower break; 109121496Ssklower 109221496Ssklower case PRU_PEERADDR: 109321496Ssklower ns_setpeeraddr(nsp, nam); 109421496Ssklower break; 109521496Ssklower 109621496Ssklower case PRU_SLOWTIMO: 109721496Ssklower cb = spp_timers(cb, (int)nam); 109821496Ssklower break; 109921496Ssklower 110021496Ssklower case PRU_FASTTIMO: 110121496Ssklower case PRU_PROTORCV: 110221496Ssklower case PRU_PROTOSEND: 110321496Ssklower error = EOPNOTSUPP; 110421496Ssklower break; 110521496Ssklower 110621496Ssklower default: 110721496Ssklower panic("sp_usrreq"); 110821496Ssklower } 110921496Ssklower if (cb && (so->so_options & SO_DEBUG || traceallspps)) 111024225Ssklower spp_trace(SA_USER, (u_char)ostate, cb, (struct spidp *)0, req); 111121496Ssklower release: 111221496Ssklower if (m != NULL) 111321496Ssklower m_freem(m); 111421496Ssklower splx(s); 111521496Ssklower return (error); 111621496Ssklower } 111721496Ssklower 111821496Ssklower spp_usrreq_sp(so, req, m, nam, rights) 111921496Ssklower struct socket *so; 112021496Ssklower int req; 112121496Ssklower struct mbuf *m, *nam, *rights; 112221496Ssklower { 112321496Ssklower int error = spp_usrreq(so, req, m, nam, rights); 112421496Ssklower 112524330Ssklower if (req == PRU_ATTACH && error == 0) { 112621496Ssklower struct nspcb *nsp = sotonspcb(so); 112721496Ssklower ((struct sppcb *)nsp->nsp_pcb)->s_flags |= 112821496Ssklower (SF_HI | SF_HO | SF_PI); 112921496Ssklower } 113023515Ssklower return (error); 113121496Ssklower } 113221496Ssklower 113321496Ssklower /* 113421496Ssklower * Create template to be used to send spp packets on a connection. 113521496Ssklower * Called after host entry created, fills 113621496Ssklower * in a skeletal spp header (choosing connection id), 113721496Ssklower * minimizing the amount of work necessary when the connection is used. 113821496Ssklower */ 113921496Ssklower spp_template(cb) 114021496Ssklower struct sppcb *cb; 114121496Ssklower { 114221496Ssklower register struct nspcb *nsp = cb->s_nspcb; 114321496Ssklower register struct spidp *n = &(cb->s_shdr); 114421496Ssklower 114524615Ssklower cb->s_mtu = 576 - sizeof (struct spidp); 114621496Ssklower n->si_pt = NSPROTO_SPP; 114721496Ssklower n->si_sna = nsp->nsp_laddr; 114821496Ssklower n->si_dna = nsp->nsp_faddr; 114921496Ssklower n->si_sid = htons(spp_iss); 115021496Ssklower spp_iss += SPP_ISSINCR/2; 115121496Ssklower n->si_alo = 1; 115221496Ssklower } 115321496Ssklower 115421496Ssklower /* 115521496Ssklower * Close a SPIP control block: 115621496Ssklower * discard spp control block itself 115721496Ssklower * discard ns protocol control block 115821496Ssklower * wake up any sleepers 115921496Ssklower */ 116021496Ssklower struct sppcb * 116121496Ssklower spp_close(cb) 116221496Ssklower register struct sppcb *cb; 116321496Ssklower { 116421496Ssklower register struct spidp_q *s; 116521496Ssklower struct nspcb *nsp = cb->s_nspcb; 116621496Ssklower struct socket *so = nsp->nsp_socket; 116721496Ssklower register struct mbuf *m; 116821496Ssklower 116921496Ssklower s = cb->s_q.si_next; 117021496Ssklower while (s != &(cb->s_q)) { 117121496Ssklower s = s->si_next; 117221496Ssklower m = dtom(s->si_prev); 117321496Ssklower remque(s->si_prev); 117421496Ssklower m_freem(m); 117521496Ssklower } 117621496Ssklower (void) m_free(dtom(cb)); 117721496Ssklower nsp->nsp_pcb = 0; 117821496Ssklower soisdisconnected(so); 117921496Ssklower ns_pcbdetach(nsp); 118023515Ssklower return ((struct sppcb *)0); 118121496Ssklower } 118221496Ssklower /* 118321496Ssklower * Someday we may do level 3 handshaking 118421496Ssklower * to close a connection or send a xerox style error. 118521496Ssklower * For now, just close. 118621496Ssklower */ 118721496Ssklower struct sppcb * 118821496Ssklower spp_usrclosed(cb) 118921496Ssklower register struct sppcb *cb; 119021496Ssklower { 119123515Ssklower return (spp_close(cb)); 119221496Ssklower } 119321496Ssklower struct sppcb * 119421496Ssklower spp_disconnect(cb) 119521496Ssklower register struct sppcb *cb; 119621496Ssklower { 119723515Ssklower return (spp_close(cb)); 119821496Ssklower } 119921496Ssklower /* 120021496Ssklower * Drop connection, reporting 120121496Ssklower * the specified error. 120221496Ssklower */ 120321496Ssklower struct sppcb * 120421496Ssklower spp_drop(cb, errno) 120521496Ssklower register struct sppcb *cb; 120621496Ssklower int errno; 120721496Ssklower { 120821496Ssklower struct socket *so = cb->s_nspcb->nsp_socket; 120921496Ssklower 121021496Ssklower /* 121121496Ssklower * someday, in the xerox world 121221496Ssklower * we will generate error protocol packets 121321496Ssklower * announcing that the socket has gone away. 121421496Ssklower */ 121521496Ssklower /*if (TCPS_HAVERCVDSYN(tp->t_state)) { 121621496Ssklower tp->t_state = TCPS_CLOSED; 121721496Ssklower (void) tcp_output(tp); 121821496Ssklower }*/ 121921496Ssklower so->so_error = errno; 122021496Ssklower return (spp_close(cb)); 122121496Ssklower } 122221496Ssklower 122321496Ssklower spp_abort(nsp) 122421496Ssklower struct nspcb *nsp; 122521496Ssklower { 122621496Ssklower 122724225Ssklower (void) spp_close((struct sppcb *)nsp->nsp_pcb); 122821496Ssklower } 122921496Ssklower 123021496Ssklower spp_setpersist(cb) 123121496Ssklower register struct sppcb *cb; 123221496Ssklower { 123321496Ssklower 123421496Ssklower /*if (cb->s_timer[TCPT_REXMT]) 123521496Ssklower panic("spp_output REXMT");*/ 123621496Ssklower /* 123721496Ssklower * Start/restart persistance timer. 123821496Ssklower */ 123921496Ssklower TCPT_RANGESET(cb->s_timer[TCPT_PERSIST], 124021496Ssklower ((int)(tcp_beta * cb->s_srtt)) << cb->s_rxtshift, 124121496Ssklower TCPTV_PERSMIN, TCPTV_MAX); 124221496Ssklower cb->s_rxtshift++; 124321496Ssklower if (cb->s_rxtshift >= TCP_MAXRXTSHIFT) 124421496Ssklower cb->s_rxtshift = 0; 124521496Ssklower } 124621496Ssklower /* 124721496Ssklower * Fast timeout routine for processing delayed acks 124821496Ssklower */ 124921496Ssklower int spp_ftcnt; 125021496Ssklower spp_fasttimo() 125121496Ssklower { 125221496Ssklower register struct nspcb *nsp; 125321496Ssklower register struct sppcb *cb; 125421496Ssklower int s = splnet(); 125521496Ssklower 125621496Ssklower nsp = nspcb.nsp_next; 125721496Ssklower spp_ftcnt++; 125821496Ssklower if (nsp) 125921496Ssklower for (; nsp != &nspcb; nsp = nsp->nsp_next) 126021496Ssklower if ((cb = (struct sppcb *)nsp->nsp_pcb) && 126121496Ssklower (cb->s_flags & SF_DELACK)) { 126221496Ssklower cb->s_flags &= ~SF_DELACK; 126321496Ssklower cb->s_flags |= SF_AK; 126421496Ssklower (void) spp_output(cb, (struct mbuf *) 0); 126521496Ssklower } 126621496Ssklower splx(s); 126721496Ssklower } 126821496Ssklower 126921496Ssklower /* 127021496Ssklower * spp protocol timeout routine called every 500 ms. 127121496Ssklower * Updates the timers in all active pcb's and 127221496Ssklower * causes finite state machine actions if timers expire. 127321496Ssklower */ 127421496Ssklower spp_slowtimo() 127521496Ssklower { 127621496Ssklower register struct nspcb *ip, *ipnxt; 127721496Ssklower register struct sppcb *cb; 127821496Ssklower int s = splnet(); 127921496Ssklower register int i; 128021496Ssklower 128121496Ssklower /* 128221496Ssklower * Search through tcb's and update active timers. 128321496Ssklower */ 128421496Ssklower ip = nspcb.nsp_next; 128521496Ssklower if (ip == 0) { 128621496Ssklower splx(s); 128721496Ssklower return; 128821496Ssklower } 128921496Ssklower while (ip != &nspcb) { 129021496Ssklower cb = nstosppcb(ip); 129121496Ssklower ipnxt = ip->nsp_next; 129221496Ssklower if (cb == 0) 129321496Ssklower goto tpgone; 129421496Ssklower for (i = 0; i < TCPT_NTIMERS; i++) { 129521496Ssklower if (cb->s_timer[i] && --cb->s_timer[i] == 0) { 129621496Ssklower (void) spp_usrreq(cb->s_nspcb->nsp_socket, 129721496Ssklower PRU_SLOWTIMO, (struct mbuf *)0, 129821496Ssklower (struct mbuf *)i, (struct mbuf *)0); 129921496Ssklower if (ipnxt->nsp_prev != ip) 130021496Ssklower goto tpgone; 130121496Ssklower } 130221496Ssklower } 130321496Ssklower cb->s_idle++; 130421496Ssklower if (cb->s_rtt) 130521496Ssklower cb->s_rtt++; 130621496Ssklower tpgone: 130721496Ssklower ip = ipnxt; 130821496Ssklower } 130921496Ssklower spp_iss += SPP_ISSINCR/PR_SLOWHZ; /* increment iss */ 131021496Ssklower splx(s); 131121496Ssklower } 131221496Ssklower 131321496Ssklower float spp_backoff[TCP_MAXRXTSHIFT] = 131421496Ssklower { 1.0, 1.2, 1.4, 1.7, 2.0, 3.0, 5.0, 8.0, 16.0, 32.0 }; 131524412Swalsh int sppexprexmtbackoff = 0; 131621496Ssklower /* 131724615Ssklower * SPP timer processing. 131821496Ssklower */ 131921496Ssklower struct sppcb * 132021496Ssklower spp_timers(cb, timer) 132121496Ssklower register struct sppcb *cb; 132221496Ssklower int timer; 132321496Ssklower { 132421496Ssklower 132521496Ssklower cb->s_force = 1 + timer; 132621496Ssklower switch (timer) { 132721496Ssklower 132821496Ssklower /* 132921496Ssklower * 2 MSL timeout in shutdown went off. Delete connection 133021496Ssklower * control block. 133121496Ssklower */ 133221496Ssklower case TCPT_2MSL: 133321496Ssklower cb = spp_close(cb); 133421496Ssklower break; 133521496Ssklower 133621496Ssklower /* 133721496Ssklower * Retransmission timer went off. Message has not 133821496Ssklower * been acked within retransmit interval. Back off 133921496Ssklower * to a longer retransmit interval and retransmit all 134021496Ssklower * unacknowledged messages in the window. 134121496Ssklower */ 134221496Ssklower case TCPT_REXMT: 134321496Ssklower cb->s_rxtshift++; 134421496Ssklower if (cb->s_rxtshift > TCP_MAXRXTSHIFT) { 134521496Ssklower cb = spp_drop(cb, ETIMEDOUT); 134621496Ssklower break; 134721496Ssklower } 134821496Ssklower (void) spp_output(cb, (struct mbuf *) 0); 134921496Ssklower TCPT_RANGESET(cb->s_timer[TCPT_REXMT], 135021496Ssklower (int)cb->s_srtt, TCPTV_MIN, TCPTV_MAX); 135124412Swalsh if (sppexprexmtbackoff) { 135221496Ssklower TCPT_RANGESET(cb->s_timer[TCPT_REXMT], 135321496Ssklower cb->s_timer[TCPT_REXMT] << cb->s_rxtshift, 135421496Ssklower TCPTV_MIN, TCPTV_MAX); 135521496Ssklower } else { 135621496Ssklower TCPT_RANGESET(cb->s_timer[TCPT_REXMT], 135721496Ssklower cb->s_timer[TCPT_REXMT] * 135821496Ssklower spp_backoff[cb->s_rxtshift - 1], 135921496Ssklower TCPTV_MIN, TCPTV_MAX); 136021496Ssklower } 136121496Ssklower break; 136221496Ssklower 136321496Ssklower /* 136421496Ssklower * Persistance timer into zero window. 136521496Ssklower * Force a probe to be sent. 136621496Ssklower */ 136721496Ssklower case TCPT_PERSIST: 136821496Ssklower (void) spp_output(cb, (struct mbuf *) 0); 136921496Ssklower spp_setpersist(cb); 137021496Ssklower break; 137121496Ssklower 137221496Ssklower /* 137321496Ssklower * Keep-alive timer went off; send something 137421496Ssklower * or drop connection if idle for too long. 137521496Ssklower */ 137621496Ssklower case TCPT_KEEP: 137721496Ssklower if (cb->s_state < TCPS_ESTABLISHED) 137821496Ssklower goto dropit; 137921496Ssklower if (cb->s_nspcb->nsp_socket->so_options & SO_KEEPALIVE) { 138021496Ssklower if (cb->s_idle >= TCPTV_MAXIDLE) 138121496Ssklower goto dropit; 138221496Ssklower (void) spp_output(cb, (struct mbuf *) 0); 138321496Ssklower } else 138421496Ssklower cb->s_idle = 0; 138521496Ssklower cb->s_timer[TCPT_KEEP] = TCPTV_KEEP; 138621496Ssklower break; 138721496Ssklower dropit: 138821496Ssklower cb = spp_drop(cb, ETIMEDOUT); 138921496Ssklower break; 139021496Ssklower } 139121496Ssklower return (cb); 139221496Ssklower } 1393