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*23515Ssklower * @(#)spp_usrreq.c 6.3 (Berkeley) 06/17/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; 4421496Ssklower 4521496Ssklower int spp_hardnosed; 4621496Ssklower spp_input(m, nsp) 4721496Ssklower register struct nspcb *nsp; 4821496Ssklower register struct mbuf *m; 4921496Ssklower { 5021496Ssklower register struct sppcb *cb; 5121496Ssklower register struct spidp *si = mtod(m, struct spidp *); 5221496Ssklower register struct socket *so; 5321496Ssklower int len; short ostate; 5421496Ssklower int dropsocket = 0; 5521496Ssklower 5621496Ssklower 5721496Ssklower 5821496Ssklower cb = nstosppcb(nsp); 5921496Ssklower if (cb == 0) goto bad; 6021496Ssklower 6121496Ssklower si->si_seq = ntohs(si->si_seq); 6221496Ssklower si->si_ack = ntohs(si->si_ack); 6321496Ssklower si->si_alo = ntohs(si->si_alo); 6421496Ssklower 6521496Ssklower so = nsp->nsp_socket; 6621496Ssklower if (so->so_options & SO_DEBUG || traceallspps) { 6721496Ssklower ostate = cb->s_state; 6821496Ssklower spp_savesi = *si; 6921496Ssklower } 7021496Ssklower if (so->so_options & SO_ACCEPTCONN) { 7121496Ssklower so = sonewconn(so); 7221496Ssklower if (so == 0) { 7321496Ssklower spp_istat.nonucn++; 7421496Ssklower goto drop; 7521496Ssklower } 7621496Ssklower /* 7721496Ssklower * This is ugly, but .... 7821496Ssklower * 7921496Ssklower * Mark socket as temporary until we're 8021496Ssklower * committed to keeping it. The code at 8121496Ssklower * ``drop'' and ``dropwithreset'' check the 8221496Ssklower * flag dropsocket to see if the temporary 8321496Ssklower * socket created here should be discarded. 8421496Ssklower * We mark the socket as discardable until 8521496Ssklower * we're committed to it below in TCPS_LISTEN. 8621496Ssklower */ 8721496Ssklower dropsocket++; 8821496Ssklower nsp = (struct nspcb *)so->so_pcb; 8921496Ssklower nsp->nsp_laddr = si->si_dna; 9021496Ssklower cb = nstosppcb(nsp); 9121496Ssklower cb->s_state = TCPS_LISTEN; 9221496Ssklower } 9321496Ssklower 9421496Ssklower /* 9521496Ssklower * Packet received on connection. 9621496Ssklower * reset idle time and keep-alive timer; 9721496Ssklower */ 9821496Ssklower cb->s_idle = 0; 9921496Ssklower cb->s_timer[TCPT_KEEP] = TCPTV_KEEP; 10021496Ssklower 10121496Ssklower switch (cb->s_state) { 102*23515Ssklower 10321496Ssklower case TCPS_LISTEN:{ 10421496Ssklower struct mbuf *am; 10521496Ssklower register struct sockaddr_ns *sns; 10621496Ssklower struct ns_addr laddr; 10721496Ssklower 10821496Ssklower /* 10921496Ssklower * If somebody here was carying on a conversation 11021496Ssklower * and went away, and his pen pal thinks he can 11121496Ssklower * still talk, we get the misdirected packet. 11221496Ssklower */ 11321496Ssklower if (spp_hardnosed && (si->si_did != 0 || si->si_seq != 0)) { 11421496Ssklower spp_istat.gonawy++; 11521496Ssklower goto dropwithreset; 11621496Ssklower } 11721496Ssklower am = m_get(M_DONTWAIT, MT_SONAME); 11821496Ssklower if (am == NULL) 11921496Ssklower goto drop; 12021496Ssklower am->m_len = sizeof (struct sockaddr_ns); 12121496Ssklower sns = mtod(am, struct sockaddr_ns *); 12221496Ssklower sns->sns_family = AF_NS; 12321496Ssklower sns->sns_addr = si->si_sna; 12421496Ssklower laddr = nsp->nsp_laddr; 12521496Ssklower if (ns_nullhost(laddr)) 12621496Ssklower nsp->nsp_laddr = si->si_dna; 12721496Ssklower if (ns_pcbconnect(nsp, am)) { 12821496Ssklower nsp->nsp_laddr = laddr; 12921496Ssklower (void) m_free(am); 13021496Ssklower spp_istat.noconn++; 13121496Ssklower goto drop; 13221496Ssklower } 13321496Ssklower (void) m_free(am); 13421496Ssklower cb->s_state = TCPS_SYN_RECEIVED; 13521496Ssklower spp_template(cb); 13621496Ssklower cb->s_did = si->si_sid; 13721496Ssklower cb->s_rack = si->si_ack; 13821496Ssklower cb->s_ralo = si->si_alo; 13921496Ssklower cb->s_flags |= SF_AK; 14021496Ssklower cb->s_timer[TCPT_KEEP] = TCPTV_KEEP; 14121496Ssklower dropsocket = 0; /* committed to socket */ 14221496Ssklower } 14321496Ssklower break; 14421496Ssklower 14521496Ssklower /* 14621496Ssklower * This state means that we have gotten a response 14721496Ssklower * to our attempt to establish a connection. 14821496Ssklower * We fill in the data from the other side 14921496Ssklower * (Telling which port to send to instead of the well- 15021496Ssklower * known one we might have to in the first place ) 15121496Ssklower * We also require that this is a response to our 15221496Ssklower * connection id, and that it should be a system packet, 15321496Ssklower * containing no data. 15421496Ssklower */ 15521496Ssklower case TCPS_SYN_SENT: 15621496Ssklower if (si->si_did!=cb->s_sid) { 15721496Ssklower spp_istat.notme++; 15821496Ssklower goto drop; 15921496Ssklower } 16021496Ssklower cb->s_did = si->si_sid; 16121496Ssklower cb->s_rack = si->si_ack; 16221496Ssklower cb->s_ralo = si->si_alo; 16321496Ssklower cb->s_dport = nsp->nsp_fport = si->si_sport; 16421496Ssklower cb->s_timer[TCPT_REXMT] = 0; 16521496Ssklower cb->s_flags |= SF_AK; 16621496Ssklower soisconnected(so); 16721496Ssklower cb->s_state = TCPS_ESTABLISHED; 16821496Ssklower break; 16921496Ssklower /* 17021496Ssklower * This state means that we have heard a response 17121496Ssklower * to our acceptance of their connection 17221496Ssklower * It is probably logically unnecessary in this 17321496Ssklower * implementation. 17421496Ssklower */ 17521496Ssklower case TCPS_SYN_RECEIVED: 17621496Ssklower if (si->si_did!=cb->s_sid) { 17721496Ssklower spp_istat.wrncon++; 17821496Ssklower goto drop; 17921496Ssklower } 18021496Ssklower nsp->nsp_fport = si->si_sport; 18121496Ssklower cb->s_timer[TCPT_REXMT] = 0; 18221496Ssklower cb->s_timer[TCPT_KEEP] = TCPTV_KEEP; 18321496Ssklower soisconnected(so); 18421496Ssklower cb->s_state = TCPS_ESTABLISHED; 18521496Ssklower } 18621496Ssklower if (so->so_options & SO_DEBUG || traceallspps) 18721496Ssklower spp_trace(SA_INPUT, ostate, cb, &spp_savesi, 0); 18821496Ssklower 18921496Ssklower m->m_len -= sizeof (struct idp); 19021496Ssklower m->m_off += sizeof (struct idp); 19121496Ssklower 19221496Ssklower if (spp_reass(cb,si)) { 19321496Ssklower spp_istat.bdreas++; 19421496Ssklower goto drop; 19521496Ssklower } 19621496Ssklower spp_output(cb,(struct mbuf *)0); 19721496Ssklower return; 19821496Ssklower 19921496Ssklower dropwithreset: 20021496Ssklower if (dropsocket) 20121496Ssklower (void) soabort(so); 20221496Ssklower si->si_seq = ntohs(si->si_seq); 20321496Ssklower si->si_ack = ntohs(si->si_ack); 20421496Ssklower si->si_alo = ntohs(si->si_alo); 20521496Ssklower ns_error(dtom(si), NS_ERR_NOSOCK, 0); 20621496Ssklower if (cb->s_nspcb->nsp_socket->so_options & SO_DEBUG || traceallspps) 20721496Ssklower spp_trace(SA_DROP, ostate, cb, &spp_savesi, 0); 20821496Ssklower return; 20921496Ssklower 21021496Ssklower drop: 21121496Ssklower bad: 21221496Ssklower if (cb->s_nspcb->nsp_socket->so_options & SO_DEBUG || traceallspps) 21321496Ssklower spp_trace(SA_DROP, ostate, cb, &spp_savesi, 0); 21421496Ssklower m_freem(m); 21521496Ssklower } 21621496Ssklower 21721496Ssklower /* 21821496Ssklower * This is structurally similar to the tcp reassembly routine 21921496Ssklower * but its function is somewhat different: It merely queues 22021496Ssklower * packets up, and suppresses duplicates. 22121496Ssklower */ 22221496Ssklower spp_reass(cb,si) 22321496Ssklower register struct sppcb *cb; 22421496Ssklower register struct spidp *si; 22521496Ssklower { 22621496Ssklower register struct spidp_q *q; 22721496Ssklower register struct mbuf *m; 22821496Ssklower struct socket *so = cb->s_nspcb->nsp_socket; 22921496Ssklower struct sockbuf *sb = & (so->so_rcv); 23021496Ssklower char packetp = cb->s_flags & SF_HI; 23121496Ssklower char wakeup = 0; 23221496Ssklower 23321496Ssklower 23421496Ssklower if (si==SI(0)) 23521496Ssklower goto present; 23621496Ssklower /* 23721496Ssklower * Update our news from them. 23821496Ssklower */ 23921496Ssklower if (si->si_cc & SP_SA) 24021496Ssklower cb->s_flags |= SF_DELACK; 24121496Ssklower if (SSEQ_GT(si->si_ack,cb->s_rack)) { 24221496Ssklower cb->s_rack = si->si_ack; 24321496Ssklower cb->s_timer[TCPT_REXMT] = 0; 24421496Ssklower 24521496Ssklower /* 24621496Ssklower * If transmit timer is running and timed sequence 24721496Ssklower * number was acked, update smoothed round trip time. 24821496Ssklower */ 24921496Ssklower if (cb->s_rtt && SSEQ_GT(si->si_ack, cb->s_rtseq)) { 25021496Ssklower if (cb->s_srtt == 0) 25121496Ssklower cb->s_srtt = cb->s_rtt; 25221496Ssklower else 25321496Ssklower cb->s_srtt = 25421496Ssklower tcp_alpha * cb->s_srtt + 25521496Ssklower (1 - tcp_alpha) * cb->s_rtt; 25621496Ssklower cb->s_rtt = 0; 25721496Ssklower } 25821496Ssklower } 25921496Ssklower if (SSEQ_GT(si->si_alo,cb->s_ralo)) { 26021496Ssklower cb->s_ralo = si->si_alo; 26121496Ssklower cb->s_timer[TCPT_PERSIST] = 0; 26221496Ssklower } 26321496Ssklower /* 26421496Ssklower * If this is a system packet, we don't need to 26521496Ssklower * queue it up, and won't update acknowledge # 26621496Ssklower */ 26721496Ssklower if (si->si_cc & SP_SP) 268*23515Ssklower return (0); 26921496Ssklower 27021496Ssklower /* 27121496Ssklower * If this packet number has a sequence number less 27221496Ssklower * than that of the first packet not yet seen coming 27321496Ssklower * from them, this must be a duplicate, so drop. 27421496Ssklower */ 27521496Ssklower if (SSEQ_LT(si->si_seq,cb->s_ack)) 276*23515Ssklower return (1); 27721496Ssklower /* 27821496Ssklower * If this packet number is higher than that which 27921496Ssklower * we have allocated refuse it, unless urgent 28021496Ssklower */ 28121496Ssklower if (SSEQ_GT(si->si_seq,cb->s_alo) && (!(si->si_cc & SP_OB))) { 282*23515Ssklower return (1); 28321496Ssklower } 28421496Ssklower /* 28521496Ssklower * If this packet is urgent, inform process 28621496Ssklower */ 28721496Ssklower if (si->si_cc & SP_OB) { 28821496Ssklower cb->s_iobc = ((char *)si)[1 + sizeof(*si)]; 28921496Ssklower sohasoutofband(so); 29021496Ssklower } 29121496Ssklower 29221496Ssklower /* 29321496Ssklower * Loop through all packets queued up to insert in 29421496Ssklower * appropriate sequence. 29521496Ssklower */ 29621496Ssklower 29721496Ssklower for (q = cb->s_q.si_next; q!=&cb->s_q; q = q->si_next) { 298*23515Ssklower if (si->si_seq==SI(q)->si_seq) return (1); /*duplicate */ 29921496Ssklower if (SSEQ_LT(si->si_seq,SI(q)->si_seq)) break; 30021496Ssklower } 30121496Ssklower insque(si,q->si_prev); 30221496Ssklower 30321496Ssklower present: 30421496Ssklower #define SPINC sizeof(struct sphdr) 30521496Ssklower /* 30621496Ssklower * Loop through all packets queued up to update acknowledge 30721496Ssklower * number, and present all acknowledged data to user; 30821496Ssklower * If in packet interface mode, show packet headers. 30921496Ssklower */ 31021496Ssklower for (q = cb->s_q.si_next; q!=&cb->s_q; q = q->si_next) { 31121496Ssklower if (SI(q)->si_seq==cb->s_ack) { 31221496Ssklower cb->s_ack++; 31321496Ssklower m = dtom(q); 31421496Ssklower if (SI(q)->si_cc & SP_OB) { 31521496Ssklower if (sb->sb_cc) 31621496Ssklower so->so_oobmark = sb->sb_cc; 31721496Ssklower else 31821496Ssklower so->so_state |= SS_RCVATMARK; 31921496Ssklower } 32021496Ssklower q = q->si_prev; 32121496Ssklower remque(q->si_next); 32221496Ssklower wakeup = 1; 32321496Ssklower if (packetp) { 32421496Ssklower sbappendrecord(sb,m); 32521496Ssklower } else { 32621496Ssklower cb->s_rhdr = *mtod(m, struct sphdr *); 32721496Ssklower m->m_off += SPINC; 32821496Ssklower m->m_len -= SPINC; 32921496Ssklower sbappend(sb,m); 33021496Ssklower } 33121496Ssklower } else 33221496Ssklower break; 33321496Ssklower } 33421496Ssklower if (wakeup) sorwakeup(so); 335*23515Ssklower return (0); 33621496Ssklower } 33721496Ssklower 33821496Ssklower spp_ctlinput(cmd, arg) 33921496Ssklower int cmd; 34021496Ssklower caddr_t arg; 34121496Ssklower { 34221496Ssklower struct ns_addr *na; 34321496Ssklower extern u_char nsctlerrmap[]; 34421496Ssklower extern spp_abort(); 34521496Ssklower int type; 34621496Ssklower 34721496Ssklower if (cmd < 0 || cmd > PRC_NCMDS) 34821496Ssklower return; 34921496Ssklower type = NS_ERR_UNREACH_HOST; 35021496Ssklower 35121496Ssklower switch (cmd) { 352*23515Ssklower 35321496Ssklower case PRC_ROUTEDEAD: 35421496Ssklower case PRC_QUENCH: 35521496Ssklower break; 35621496Ssklower 35721496Ssklower case PRC_IFDOWN: 35821496Ssklower na = &((struct sockaddr_ns *)arg)->sns_addr; 35921496Ssklower break; 36021496Ssklower 36121496Ssklower case PRC_HOSTDEAD: 36221496Ssklower case PRC_HOSTUNREACH: 36321496Ssklower na = (struct ns_addr *)arg; 36421496Ssklower break; 36521496Ssklower 36621496Ssklower default: 36721496Ssklower na = &((struct ns_errp *)arg)->ns_err_idp.idp_dna; 36821496Ssklower type = ((struct ns_errp *)arg)->ns_err_num; 36921496Ssklower type = ntohs(type); 37021496Ssklower } 37121496Ssklower switch (type) { 372*23515Ssklower 37321496Ssklower case NS_ERR_UNREACH_HOST: 37421496Ssklower case NS_ERR_NOSOCK: 37521496Ssklower ns_pcbnotify(na, (int)nsctlerrmap[cmd], 37621496Ssklower spp_abort, (long) 0); 37721496Ssklower break; 378*23515Ssklower 37921496Ssklower case NS_ERR_TOO_BIG: 38021496Ssklower ns_pcbnotify(na, 0, spp_abort, (long)arg); 38121496Ssklower } 38221496Ssklower } 38321496Ssklower 38421496Ssklower int 38521496Ssklower spp_fixmtu(nsp) 38621496Ssklower register struct nspcb *nsp; 38721496Ssklower { 38821496Ssklower register struct sppcb *cb = (struct sppcb *)(nsp->nsp_pcb); 38921496Ssklower register struct mbuf *m; 39021496Ssklower register struct spidp *si; 39121496Ssklower struct ns_errp *ep; 39221496Ssklower struct sockbuf *sb; 39321496Ssklower int badseq, len; 39421496Ssklower struct mbuf *firstbad, *m0; 39521496Ssklower 39621496Ssklower if (cb) { 39721496Ssklower /* 39821496Ssklower * The notification that we have sent 39921496Ssklower * too much is bad news -- we will 40021496Ssklower * have to go through queued up so far 40121496Ssklower * splitting ones which are too big and 40221496Ssklower * reassigning sequence numbers and checksums. 40321496Ssklower * we should then retransmit all packets from 40421496Ssklower * one above the offending packet to the last one 40521496Ssklower * we had sent (or our allocation) 40621496Ssklower * then the offending one so that the any queued 40721496Ssklower * data at our destination will be discarded. 40821496Ssklower */ 40921496Ssklower ep = (struct ns_errp *)nsp->nsp_notify_param; 41021496Ssklower sb = &nsp->nsp_socket->so_snd; 41121496Ssklower cb->s_mtu = ep->ns_err_param; 41221496Ssklower badseq = SI(&ep->ns_err_idp)->si_seq; 41321496Ssklower for (m = sb->sb_mb; m; m = m->m_act) { 41421496Ssklower si = mtod(m, struct spidp *); 41521496Ssklower if (si->si_seq == badseq) 41621496Ssklower break; 41721496Ssklower } 41821496Ssklower if (m==0) return; 41921496Ssklower firstbad = m; 42021496Ssklower /*for (;;) {*/ 42121496Ssklower /* calculate length */ 42221496Ssklower for (m0 = m, len = 0; m ; m = m->m_next) 42321496Ssklower len += m->m_len; 42421496Ssklower if (len > cb->s_mtu) { 42521496Ssklower } 42621496Ssklower /* FINISH THIS 42721496Ssklower } */ 42821496Ssklower } 42921496Ssklower } 43021496Ssklower 43121496Ssklower int spp_output_cnt = 0; 43221496Ssklower spp_output(cb, m0) 43321496Ssklower register struct sppcb *cb; 43421496Ssklower struct mbuf *m0; 43521496Ssklower { 43621496Ssklower struct socket *so = cb->s_nspcb->nsp_socket; 43721496Ssklower register struct mbuf *m; 43821496Ssklower register struct spidp *si = (struct spidp *) 0; 43921496Ssklower register struct sockbuf *sb = &(so->so_snd); 44021496Ssklower register int len = 0; 44121496Ssklower int flags, debit, mtu = cb->s_mtu; 44221496Ssklower int error = 0; u_short lookfor = 0; 44321496Ssklower struct mbuf *mprev; 44421496Ssklower extern int idpcksum; 44521496Ssklower 44621496Ssklower if (m0) 44721496Ssklower { 44821496Ssklower for (m = m0; m ; m = m->m_next) { 44921496Ssklower mprev = m; 45021496Ssklower len += m->m_len; 45121496Ssklower } 45221496Ssklower if (len > mtu) { 45321496Ssklower if (cb->s_flags & SF_PI) { 45421496Ssklower m_freem(m0); 455*23515Ssklower return (EMSGSIZE); 45621496Ssklower } else { 45721496Ssklower int off = 0; 45821496Ssklower while (len > mtu) { 45921496Ssklower m = m_copy(m0, off, mtu); 460*23515Ssklower if (m==NULL) { 461*23515Ssklower m_freem(m0); 462*23515Ssklower return (ENOBUFS); 463*23515Ssklower } 46421496Ssklower error = spp_output(cb, m); 46521496Ssklower if (error) { 46621496Ssklower m_freem(m0); 467*23515Ssklower return (error); 46821496Ssklower } 46921496Ssklower m_adj(m0, mtu); 47021496Ssklower len -= mtu; 47121496Ssklower } 47221496Ssklower } 47321496Ssklower } 47421496Ssklower if (len & 1) { 47521496Ssklower if (m->m_len + m->m_off < MMAXOFF) { 47621496Ssklower m->m_len++; 47721496Ssklower } else { 47821496Ssklower struct mbuf *m1 = m_get(M_DONTWAIT, MT_DATA); 47921496Ssklower 48021496Ssklower if (m1 == 0) { 48121496Ssklower m_freem(m0); 48221496Ssklower return (ENOBUFS); 48321496Ssklower } 48421496Ssklower m1->m_len = 1; 48521496Ssklower m1->m_off = MMAXOFF - 1; 48621496Ssklower mprev->m_next = m1; 48721496Ssklower } 48821496Ssklower } 48921496Ssklower m = m_get(M_DONTWAIT, MT_HEADER); 49021496Ssklower if (m == 0) { 49121496Ssklower m_freem(m0); 492*23515Ssklower return (ENOBUFS); 49321496Ssklower } 49421496Ssklower 49521496Ssklower /* 49621496Ssklower * Fill in mbuf with extended SP header 49721496Ssklower * and addresses and length put into network format. 49821496Ssklower */ 49921496Ssklower m->m_off = MMAXOFF - sizeof (struct spidp); 50021496Ssklower m->m_len = sizeof (struct spidp); 50121496Ssklower m->m_next = m0; 50221496Ssklower si = mtod(m, struct spidp *); 50321496Ssklower *si = cb->s_shdr; 50421496Ssklower if ((cb->s_flags & SF_PI) && (cb->s_flags & SF_HO)) { 50521496Ssklower register struct sphdr *sh = mtod(m0, struct sphdr *); 50621496Ssklower si->si_dt = sh->sp_dt; 50721496Ssklower si->si_cc |= sh->sp_cc & SP_EM; 50821496Ssklower m0->m_len -= sizeof (*sh); 50921496Ssklower m0->m_off += sizeof (*sh); 51021496Ssklower len -= sizeof (*sh); 51121496Ssklower } 51221496Ssklower len += sizeof(*si); 51321496Ssklower si->si_len = htons(len); 51421496Ssklower /* 51521496Ssklower * queue stuff up for output 51621496Ssklower */ 51721496Ssklower sbappendrecord(sb,m); 51821496Ssklower cb->s_seq++; 51921496Ssklower } 52021496Ssklower output: 52121496Ssklower /* 52221496Ssklower * update window 52321496Ssklower */ 52421496Ssklower { 52521496Ssklower register struct sockbuf *sb = &so->so_rcv; 52621496Ssklower int credit = ((sb->sb_mbmax - sb->sb_mbcnt) / cb->s_mtu); 52721496Ssklower int alo = cb->s_ack + credit; 52821496Ssklower 52921496Ssklower if (cb->s_alo < alo) cb->s_alo = alo; 53021496Ssklower } 53121496Ssklower 53221496Ssklower if (cb->s_oobflags & SF_SOOB) { 53321496Ssklower /* 53421496Ssklower * must transmit this out of band packet 53521496Ssklower */ 53621496Ssklower cb->s_oobflags &= ~ SF_SOOB; 53721496Ssklower } else { 53821496Ssklower /* 53921496Ssklower * Decide what to transmit: 54021496Ssklower * If we have a new packet, send that 54121496Ssklower * (So long as it is in our allocation) 54221496Ssklower * If it is time to retransmit a packet, 54321496Ssklower * send that. 54421496Ssklower * Otherwise, see if it time to bang on them 54521496Ssklower * to ask for our current allocation. 54621496Ssklower */ 54721496Ssklower if (SSEQ_LT(cb->s_snt, cb->s_ralo)) 54821496Ssklower lookfor = cb->s_snt + 1; 54921496Ssklower else if (cb->s_force==(1+TCPT_REXMT)) { 55021496Ssklower lookfor = cb->s_rack; 55121496Ssklower } else if (SSEQ_LT(cb->s_ralo, cb->s_seq)) { 55221496Ssklower lookfor = 0; 55321496Ssklower if (cb->s_timer[TCPT_PERSIST]==0) { 55421496Ssklower spp_setpersist(cb); 55521496Ssklower } 55621496Ssklower } 55721496Ssklower m = sb->sb_mb; 55821496Ssklower while( m ) { 55921496Ssklower si = mtod(m, struct spidp *); 56021496Ssklower m = m->m_act; 56121496Ssklower if (SSEQ_LT(si->si_seq, cb->s_rack)) { 56221496Ssklower if ((sb->sb_flags & SB_WAIT) 56321496Ssklower || so->so_snd.sb_sel) 56421496Ssklower sowwakeup(so); 56521496Ssklower sbdroprecord(sb); 56621496Ssklower si = 0; 56721496Ssklower continue; 56821496Ssklower } 56921496Ssklower if (SSEQ_LT(si->si_seq, lookfor)) 57021496Ssklower continue; 57121496Ssklower break; 57221496Ssklower } 57321496Ssklower if (si && (si->si_seq != lookfor)) si = 0; 57421496Ssklower } 57521496Ssklower cb->s_want = lookfor; 57621496Ssklower 57721496Ssklower if (si) { 57821496Ssklower /* 57921496Ssklower * must make a copy of this packet for 58021496Ssklower * idp_output to monkey with 58121496Ssklower */ 58221496Ssklower m = dtom(si); 583*23515Ssklower m = m_copy(m, 0, M_COPYALL); 584*23515Ssklower if (m==NULL) 585*23515Ssklower return (ENOBUFS); 586*23515Ssklower m0 = m; 58721496Ssklower si = mtod(m, struct spidp *); 58821496Ssklower } else if (cb->s_force || cb->s_flags & SF_AK) { 58921496Ssklower /* 59021496Ssklower * Must send an acknowledgement or a probe 59121496Ssklower */ 59221496Ssklower m = m_get(M_DONTWAIT, MT_HEADER); 59321496Ssklower if (m == 0) 594*23515Ssklower return (ENOBUFS); 59521496Ssklower /* 59621496Ssklower * Fill in mbuf with extended SP header 59721496Ssklower * and addresses and length put into network format. 59821496Ssklower */ 59921496Ssklower m->m_off = MMAXOFF - sizeof (struct spidp); 60021496Ssklower m->m_len = sizeof (*si); 60121496Ssklower m->m_next = 0; 60221496Ssklower si = mtod(m, struct spidp *); 60321496Ssklower *si = cb->s_shdr; 60421496Ssklower si->si_seq = cb->s_snt + 1; 60521496Ssklower len = sizeof (*si); 60621496Ssklower si->si_len = htons((u_short)len); 60721496Ssklower si->si_cc |= SP_SP; 60821496Ssklower cb->s_flags &= ~SF_AK; 60921496Ssklower } 61021496Ssklower /* 61121496Ssklower * Stuff checksum and output datagram. 61221496Ssklower */ 61321496Ssklower if (si) { 61421496Ssklower /* 61521496Ssklower * If we are almost out of allocation 61621496Ssklower * or one of the timers has gone off 61721496Ssklower * request an ack. 61821496Ssklower */ 61921496Ssklower if (SSEQ_GEQ(cb->s_seq,cb->s_ralo)) 62021496Ssklower si->si_cc |= SP_SA; 62121496Ssklower if (cb->s_force) { 62221496Ssklower si->si_cc |= SP_SA; 62321496Ssklower cb->s_force = 0; 62421496Ssklower } 62521496Ssklower /* if this is a new packet (and not a system packet) 62621496Ssklower * and we are not currently timing anything 62721496Ssklower * time this one and ask for an ack 62821496Ssklower */ 62921496Ssklower if (SSEQ_LT(cb->s_snt,si->si_seq) && 63021496Ssklower (!(si->si_cc & SP_SP))) { 63121496Ssklower cb->s_snt = si->si_seq; 63221496Ssklower if (cb->s_rtt==0) { 63321496Ssklower cb->s_rtseq = si->si_seq; 63421496Ssklower cb->s_rtt = 1; 63521496Ssklower si->si_cc |= SP_SA; 63621496Ssklower } 63721496Ssklower /* 63821496Ssklower * If the retransmit timer has not been set 63921496Ssklower * and this is a real packet 64021496Ssklower * then start the retransmit timer 64121496Ssklower */ 64221496Ssklower if (cb->s_timer[TCPT_REXMT]==0) { 64321496Ssklower TCPT_RANGESET(cb->s_timer[TCPT_REXMT], 64421496Ssklower tcp_beta * cb->s_srtt, TCPTV_MIN, 64521496Ssklower TCPTV_MAX); 64621496Ssklower cb->s_rxtshift = 0; 64721496Ssklower } 64821496Ssklower } 64921496Ssklower si->si_seq = htons(si->si_seq); 65021496Ssklower si->si_alo = htons(cb->s_alo); 65121496Ssklower si->si_ack = htons(cb->s_ack); 65221496Ssklower 65321496Ssklower if (idpcksum) { 65421496Ssklower si->si_sum = 0; 65521496Ssklower len = ((len - 1) | 1) + 1; 65621496Ssklower si->si_sum = ns_cksum(dtom(si), len); 65721496Ssklower } else 65821496Ssklower si->si_sum = 0xffff; 65921496Ssklower 66021496Ssklower if (so->so_options & SO_DEBUG || traceallspps) 66121496Ssklower spp_trace(SA_OUTPUT, cb->s_state, cb, si, 0); 66221496Ssklower spp_output_cnt++; 66321496Ssklower if (so->so_options & SO_DONTROUTE) 66421496Ssklower error = ns_output(m, (struct route *)0, NS_ROUTETOIF); 66521496Ssklower else 66621496Ssklower error = ns_output(m, &cb->s_nspcb->nsp_route, 0); 66721496Ssklower if (traceallspps && sppconsdebug) { 66821496Ssklower printf("spp_out: %x\n", error); 66921496Ssklower } 670*23515Ssklower return (error); 67121496Ssklower } 67221496Ssklower if (so->so_options & SO_DEBUG || traceallspps) 67321496Ssklower spp_trace(SA_OUTPUT, cb->s_state, cb, si, 0); 674*23515Ssklower return (error); 67521496Ssklower } 67621496Ssklower 67721496Ssklower /*ARGSUSED*/ 67821496Ssklower spp_ctloutput(req, so, level, name, value) 67921496Ssklower int req; 68021496Ssklower struct socket *so; 68121496Ssklower int name; 68221496Ssklower struct mbuf **value; 68321496Ssklower { 68421496Ssklower register struct mbuf *m; 68521496Ssklower struct nspcb *nsp = sotonspcb(so); 68621496Ssklower register struct sppcb *cb; 68721496Ssklower int mask, error = 0; 68821496Ssklower 68921496Ssklower if (level != NSPROTO_SPP) { 69021496Ssklower /* This will have to be changed when we do more general 69121496Ssklower stacking of protocols */ 692*23515Ssklower return (idp_ctloutput(req, so, level, name, value)); 69321496Ssklower } 69421496Ssklower if (nsp == NULL) { 69521496Ssklower error = EINVAL; 69621496Ssklower goto release; 69721496Ssklower } else 69821496Ssklower cb = nstosppcb(nsp); 69921496Ssklower 70021496Ssklower switch (req) { 701*23515Ssklower 70221496Ssklower case PRCO_GETOPT: 703*23515Ssklower if (value==NULL) 704*23515Ssklower return (EINVAL); 70521496Ssklower m = m_get(M_DONTWAIT, MT_DATA); 706*23515Ssklower if (m==NULL) 707*23515Ssklower return (ENOBUFS); 70821496Ssklower switch (name) { 709*23515Ssklower 71021496Ssklower case SO_HEADERS_ON_INPUT: 71121496Ssklower mask = SF_HI; 71221496Ssklower goto get_flags; 713*23515Ssklower 71421496Ssklower case SO_HEADERS_ON_OUTPUT: 71521496Ssklower mask = SF_HO; 71621496Ssklower get_flags: 71721496Ssklower m->m_len = sizeof(short); 71821496Ssklower m->m_off = MMAXOFF - sizeof(short); 71921496Ssklower *mtod(m, short *) = cb->s_flags & mask; 72021496Ssklower break; 721*23515Ssklower 72221496Ssklower case SO_LAST_HEADER: 72321496Ssklower m->m_len = sizeof(struct sphdr); 72421496Ssklower m->m_off = MMAXOFF - sizeof(struct sphdr); 72521496Ssklower *mtod(m, struct sphdr *) = cb->s_rhdr; 72621496Ssklower break; 727*23515Ssklower 72821496Ssklower case SO_DEFAULT_HEADERS: 72921496Ssklower m->m_len = sizeof(struct spidp); 73021496Ssklower m->m_off = MMAXOFF - sizeof(struct sphdr); 73121496Ssklower *mtod(m, struct sphdr *) = cb->s_shdr.si_s; 73221496Ssklower } 73321496Ssklower *value = m; 73421496Ssklower break; 735*23515Ssklower 73621496Ssklower case PRCO_SETOPT: 73721496Ssklower switch (name) { 73821496Ssklower int mask, *ok; 73921496Ssklower 74021496Ssklower case SO_HEADERS_ON_INPUT: 74121496Ssklower mask = SF_HI; 74221496Ssklower goto set_head; 743*23515Ssklower 74421496Ssklower case SO_HEADERS_ON_OUTPUT: 74521496Ssklower mask = SF_HO; 74621496Ssklower set_head: 74721496Ssklower if (value && *value) { 74821496Ssklower ok = mtod(*value, int *); 74921496Ssklower if (*ok) 75021496Ssklower cb->s_flags |= mask; 75121496Ssklower else 75221496Ssklower cb->s_flags &= ~mask; 75321496Ssklower } else error = EINVAL; 75421496Ssklower break; 755*23515Ssklower 75621496Ssklower case SO_DEFAULT_HEADERS: 75721496Ssklower { 75821496Ssklower register struct sphdr *sp 75921496Ssklower = mtod(*value, struct sphdr *); 76021496Ssklower cb->s_dt = sp->sp_dt; 76121496Ssklower cb->s_cc = sp->sp_cc & SP_EM; 76221496Ssklower } 76321496Ssklower } 76421496Ssklower if (value && *value) 76521496Ssklower m_freem(*value); 76621496Ssklower break; 76721496Ssklower } 76821496Ssklower release: 769*23515Ssklower return (error); 77021496Ssklower } 77121496Ssklower 77221496Ssklower /*ARGSUSED*/ 77321496Ssklower spp_usrreq(so, req, m, nam, rights) 77421496Ssklower struct socket *so; 77521496Ssklower int req; 77621496Ssklower struct mbuf *m, *nam, *rights; 77721496Ssklower { 77821496Ssklower struct nspcb *nsp = sotonspcb(so); 77921496Ssklower register struct sppcb *cb; 78021496Ssklower int s = splnet(); 78121496Ssklower int error = 0, ostate; 78221496Ssklower 78321496Ssklower if (req == PRU_CONTROL) 78421496Ssklower return (ns_control(so, (int)m, (caddr_t)nam, 78521496Ssklower (struct ifnet *)rights)); 78621496Ssklower if (rights && rights->m_len) { 78721496Ssklower error = EINVAL; 78821496Ssklower goto release; 78921496Ssklower } 79021496Ssklower if (nsp == NULL) { 79121496Ssklower if (req != PRU_ATTACH) { 79221496Ssklower error = EINVAL; 79321496Ssklower goto release; 79421496Ssklower } 79521496Ssklower } else 79621496Ssklower cb = nstosppcb(nsp); 79721496Ssklower 79821496Ssklower ostate = cb ? cb->s_state : 0; 79921496Ssklower 80021496Ssklower switch (req) { 801*23515Ssklower 80221496Ssklower case PRU_ATTACH: 80321496Ssklower if (nsp != NULL) { 80421496Ssklower error = EISCONN; 80521496Ssklower break; 80621496Ssklower } 80721496Ssklower error = ns_pcballoc(so, &nspcb); 80821496Ssklower if (error) 80921496Ssklower break; 81021496Ssklower error = soreserve(so, 2048, 2048); 81121496Ssklower if (error) 81221496Ssklower break; 81321496Ssklower nsp = sotonspcb(so); 81421496Ssklower { 81521496Ssklower struct mbuf *mm = m_getclr(M_DONTWAIT,MT_PCB); 81621496Ssklower 81721496Ssklower if (mm==NULL) { 81821496Ssklower error = ENOBUFS; 81921496Ssklower break; 82021496Ssklower } 82121496Ssklower cb = mtod(mm, struct sppcb *); 82221496Ssklower cb->s_state = TCPS_LISTEN; 82321496Ssklower cb->s_flags = SF_HI | SF_HO; 82421496Ssklower cb->s_snt = -1; 82521496Ssklower cb->s_q.si_next = cb->s_q.si_prev = &cb->s_q; 82621496Ssklower cb->s_nspcb = nsp; 82721496Ssklower nsp->nsp_pcb = (caddr_t) cb; 82821496Ssklower } 82921496Ssklower break; 83021496Ssklower 83121496Ssklower case PRU_DETACH: 83221496Ssklower if (nsp == NULL) { 83321496Ssklower error = ENOTCONN; 83421496Ssklower break; 83521496Ssklower } 83621496Ssklower if (cb->s_state > TCPS_LISTEN) 83721496Ssklower cb = spp_disconnect(cb); 83821496Ssklower else 83921496Ssklower cb = spp_close(cb); 84021496Ssklower break; 84121496Ssklower 84221496Ssklower case PRU_BIND: 84321496Ssklower error = ns_pcbbind(nsp, nam); 84421496Ssklower break; 84521496Ssklower 84621496Ssklower case PRU_LISTEN: 84721496Ssklower if (nsp->nsp_lport == 0) 84821496Ssklower error = ns_pcbbind(nsp, (struct mbuf *)0); 84921496Ssklower if (error == 0) 85021496Ssklower cb->s_state = TCPS_LISTEN; 85121496Ssklower break; 85221496Ssklower 85321496Ssklower /* 85421496Ssklower * Initiate connection to peer. 85521496Ssklower * Enter SYN_SENT state, and mark socket as connecting. 85621496Ssklower * Start keep-alive timer, setup prototype header, 85721496Ssklower * Send initial system packet requesting connection. 85821496Ssklower */ 85921496Ssklower case PRU_CONNECT: 86021496Ssklower if (nsp->nsp_lport == 0) { 86121496Ssklower error = ns_pcbbind(nsp, (struct mbuf *)0); 86221496Ssklower if (error) 86321496Ssklower break; 86421496Ssklower } 86521496Ssklower error = ns_pcbconnect(nsp, nam); 86621496Ssklower if (error) 86721496Ssklower break; 86821496Ssklower soisconnecting(so); 86921496Ssklower cb->s_state = TCPS_SYN_SENT; 87021496Ssklower cb->s_did = 0; 87121496Ssklower spp_template(cb); 87221496Ssklower cb->s_timer[TCPT_KEEP] = TCPTV_KEEP; 87321496Ssklower cb->s_force = 1 + TCPTV_KEEP; 87421496Ssklower /* 87521496Ssklower * Other party is required to respond to 87621496Ssklower * the port I send from, but he is not 87721496Ssklower * required to answer from where I am sending to, 87821496Ssklower * so allow wildcarding. 87921496Ssklower * original port I am sending to is still saved in 88021496Ssklower * cb->s_dport. 88121496Ssklower */ 88221496Ssklower nsp->nsp_fport = 0; 88321496Ssklower error = spp_output(cb, (struct mbuf *) 0); 88421496Ssklower break; 88521496Ssklower 88621496Ssklower case PRU_CONNECT2: 88721496Ssklower error = EOPNOTSUPP; 88821496Ssklower break; 88921496Ssklower 89021496Ssklower /* 89121496Ssklower * We may decide later to implement connection closing 89221496Ssklower * handshaking at the spp level optionally. 89321496Ssklower * here is the hook to do it: 89421496Ssklower */ 89521496Ssklower case PRU_DISCONNECT: 89621496Ssklower cb = spp_disconnect(cb); 89721496Ssklower break; 89821496Ssklower 89921496Ssklower /* 90021496Ssklower * Accept a connection. Essentially all the work is 90121496Ssklower * done at higher levels; just return the address 90221496Ssklower * of the peer, storing through addr. 90321496Ssklower */ 90421496Ssklower case PRU_ACCEPT: { 90521496Ssklower struct sockaddr_ns *sns = mtod(nam, struct sockaddr_ns *); 90621496Ssklower 90721496Ssklower nam->m_len = sizeof (struct sockaddr_ns); 90821496Ssklower sns->sns_family = AF_NS; 90921496Ssklower sns->sns_addr = nsp->nsp_faddr; 91021496Ssklower break; 91121496Ssklower } 91221496Ssklower 91321496Ssklower case PRU_SHUTDOWN: 91421496Ssklower socantsendmore(so); 91521496Ssklower cb = spp_usrclosed(cb); 91621496Ssklower if (cb) 91721496Ssklower error = spp_output(cb, (struct mbuf *) 0); 91821496Ssklower break; 91921496Ssklower 92021496Ssklower /* 92121496Ssklower * After a receive, possibly send acknowledgment 92221496Ssklower * updating allocation. 92321496Ssklower */ 92421496Ssklower case PRU_RCVD: 92521496Ssklower (void) spp_output(cb, (struct mbuf *) 0); 92621496Ssklower break; 92721496Ssklower 92821496Ssklower case PRU_SEND: 92921496Ssklower error = spp_output(cb, m); 93021496Ssklower m = NULL; 93121496Ssklower break; 93221496Ssklower 93321496Ssklower case PRU_ABORT: 93421496Ssklower spp_drop(cb, ECONNABORTED); 93521496Ssklower break; 93621496Ssklower 93721496Ssklower case PRU_SENSE: 93821496Ssklower case PRU_CONTROL: 93921496Ssklower m = NULL; 94021496Ssklower error = EOPNOTSUPP; 94121496Ssklower break; 94221496Ssklower 94321496Ssklower case PRU_RCVOOB: 94421496Ssklower if ( ! (cb->s_oobflags & SF_IOOB) ) { 94521496Ssklower error = EWOULDBLOCK; 94621496Ssklower break; 94721496Ssklower } 94821496Ssklower m->m_len = 1; 94921496Ssklower *mtod(m, caddr_t) = cb->s_iobc; 95021496Ssklower cb->s_oobflags &= ~ SF_IOOB; 95121496Ssklower break; 95221496Ssklower 95321496Ssklower case PRU_SENDOOB: 95421496Ssklower if (sbspace(&so->so_snd) < -512) { 95521496Ssklower m_freem(m); 95621496Ssklower error = ENOBUFS; 95721496Ssklower break; 95821496Ssklower } 95921496Ssklower cb->s_oobflags |= SF_SOOB; 96021496Ssklower error = spp_output(cb, m); 96121496Ssklower m = NULL; 96221496Ssklower cb->s_oobflags &= ~SF_SOOB; 96321496Ssklower break; 96421496Ssklower 96521496Ssklower case PRU_SOCKADDR: 96621496Ssklower ns_setsockaddr(nsp, nam); 96721496Ssklower break; 96821496Ssklower 96921496Ssklower case PRU_PEERADDR: 97021496Ssklower ns_setpeeraddr(nsp, nam); 97121496Ssklower break; 97221496Ssklower 97321496Ssklower case PRU_SLOWTIMO: 97421496Ssklower cb = spp_timers(cb, (int)nam); 97521496Ssklower break; 97621496Ssklower 97721496Ssklower case PRU_FASTTIMO: 97821496Ssklower case PRU_PROTORCV: 97921496Ssklower case PRU_PROTOSEND: 98021496Ssklower error = EOPNOTSUPP; 98121496Ssklower break; 98221496Ssklower 98321496Ssklower default: 98421496Ssklower panic("sp_usrreq"); 98521496Ssklower } 98621496Ssklower if (cb && (so->so_options & SO_DEBUG || traceallspps)) 98721496Ssklower spp_trace(SA_USER, ostate, cb, (struct sphdr *)0, req); 98821496Ssklower release: 98921496Ssklower if (m != NULL) 99021496Ssklower m_freem(m); 99121496Ssklower splx(s); 99221496Ssklower return (error); 99321496Ssklower } 99421496Ssklower 99521496Ssklower spp_usrreq_sp(so, req, m, nam, rights) 99621496Ssklower struct socket *so; 99721496Ssklower int req; 99821496Ssklower struct mbuf *m, *nam, *rights; 99921496Ssklower { 100021496Ssklower int error = spp_usrreq(so, req, m, nam, rights); 100121496Ssklower 100221496Ssklower if (req==PRU_ATTACH && error==0) { 100321496Ssklower struct nspcb *nsp = sotonspcb(so); 100421496Ssklower ((struct sppcb *)nsp->nsp_pcb)->s_flags |= 100521496Ssklower (SF_HI | SF_HO | SF_PI); 100621496Ssklower } 1007*23515Ssklower return (error); 100821496Ssklower } 100921496Ssklower 101021496Ssklower /* 101121496Ssklower * Create template to be used to send spp packets on a connection. 101221496Ssklower * Called after host entry created, fills 101321496Ssklower * in a skeletal spp header (choosing connection id), 101421496Ssklower * minimizing the amount of work necessary when the connection is used. 101521496Ssklower */ 101621496Ssklower spp_template(cb) 101721496Ssklower struct sppcb *cb; 101821496Ssklower { 101921496Ssklower register struct nspcb *nsp = cb->s_nspcb; 102021496Ssklower register struct spidp *n = &(cb->s_shdr); 102121496Ssklower 102221496Ssklower cb->s_mtu = 1024; 102321496Ssklower n->si_pt = NSPROTO_SPP; 102421496Ssklower n->si_sna = nsp->nsp_laddr; 102521496Ssklower n->si_dna = nsp->nsp_faddr; 102621496Ssklower n->si_sid = htons(spp_iss); 102721496Ssklower spp_iss += SPP_ISSINCR/2; 102821496Ssklower n->si_alo = 1; 102921496Ssklower } 103021496Ssklower 103121496Ssklower /* 103221496Ssklower * Close a SPIP control block: 103321496Ssklower * discard spp control block itself 103421496Ssklower * discard ns protocol control block 103521496Ssklower * wake up any sleepers 103621496Ssklower */ 103721496Ssklower struct sppcb * 103821496Ssklower spp_close(cb) 103921496Ssklower register struct sppcb *cb; 104021496Ssklower { 104121496Ssklower register struct spidp_q *s; 104221496Ssklower struct nspcb *nsp = cb->s_nspcb; 104321496Ssklower struct socket *so = nsp->nsp_socket; 104421496Ssklower register struct mbuf *m; 104521496Ssklower 104621496Ssklower s = cb->s_q.si_next; 104721496Ssklower while (s != &(cb->s_q)) { 104821496Ssklower s = s->si_next; 104921496Ssklower m = dtom(s->si_prev); 105021496Ssklower remque(s->si_prev); 105121496Ssklower m_freem(m); 105221496Ssklower } 105321496Ssklower (void) m_free(dtom(cb)); 105421496Ssklower nsp->nsp_pcb = 0; 105521496Ssklower soisdisconnected(so); 105621496Ssklower ns_pcbdetach(nsp); 1057*23515Ssklower return ((struct sppcb *)0); 105821496Ssklower } 105921496Ssklower /* 106021496Ssklower * Someday we may do level 3 handshaking 106121496Ssklower * to close a connection or send a xerox style error. 106221496Ssklower * For now, just close. 106321496Ssklower */ 106421496Ssklower struct sppcb * 106521496Ssklower spp_usrclosed(cb) 106621496Ssklower register struct sppcb *cb; 106721496Ssklower { 1068*23515Ssklower return (spp_close(cb)); 106921496Ssklower } 107021496Ssklower struct sppcb * 107121496Ssklower spp_disconnect(cb) 107221496Ssklower register struct sppcb *cb; 107321496Ssklower { 1074*23515Ssklower return (spp_close(cb)); 107521496Ssklower } 107621496Ssklower /* 107721496Ssklower * Drop connection, reporting 107821496Ssklower * the specified error. 107921496Ssklower */ 108021496Ssklower struct sppcb * 108121496Ssklower spp_drop(cb, errno) 108221496Ssklower register struct sppcb *cb; 108321496Ssklower int errno; 108421496Ssklower { 108521496Ssklower struct socket *so = cb->s_nspcb->nsp_socket; 108621496Ssklower 108721496Ssklower /* 108821496Ssklower * someday, in the xerox world 108921496Ssklower * we will generate error protocol packets 109021496Ssklower * announcing that the socket has gone away. 109121496Ssklower */ 109221496Ssklower /*if (TCPS_HAVERCVDSYN(tp->t_state)) { 109321496Ssklower tp->t_state = TCPS_CLOSED; 109421496Ssklower (void) tcp_output(tp); 109521496Ssklower }*/ 109621496Ssklower so->so_error = errno; 109721496Ssklower return (spp_close(cb)); 109821496Ssklower } 109921496Ssklower 110021496Ssklower spp_abort(nsp) 110121496Ssklower struct nspcb *nsp; 110221496Ssklower { 110321496Ssklower 110421496Ssklower spp_close((struct sppcb *)nsp->nsp_pcb); 110521496Ssklower } 110621496Ssklower 110721496Ssklower spp_setpersist(cb) 110821496Ssklower register struct sppcb *cb; 110921496Ssklower { 111021496Ssklower 111121496Ssklower /*if (cb->s_timer[TCPT_REXMT]) 111221496Ssklower panic("spp_output REXMT");*/ 111321496Ssklower /* 111421496Ssklower * Start/restart persistance timer. 111521496Ssklower */ 111621496Ssklower TCPT_RANGESET(cb->s_timer[TCPT_PERSIST], 111721496Ssklower ((int)(tcp_beta * cb->s_srtt)) << cb->s_rxtshift, 111821496Ssklower TCPTV_PERSMIN, TCPTV_MAX); 111921496Ssklower cb->s_rxtshift++; 112021496Ssklower if (cb->s_rxtshift >= TCP_MAXRXTSHIFT) 112121496Ssklower cb->s_rxtshift = 0; 112221496Ssklower } 112321496Ssklower /* 112421496Ssklower * Fast timeout routine for processing delayed acks 112521496Ssklower */ 112621496Ssklower int spp_ftcnt; 112721496Ssklower spp_fasttimo() 112821496Ssklower { 112921496Ssklower register struct nspcb *nsp; 113021496Ssklower register struct sppcb *cb; 113121496Ssklower int s = splnet(); 113221496Ssklower 113321496Ssklower nsp = nspcb.nsp_next; 113421496Ssklower spp_ftcnt++; 113521496Ssklower if (nsp) 113621496Ssklower for (; nsp != &nspcb; nsp = nsp->nsp_next) 113721496Ssklower if ((cb = (struct sppcb *)nsp->nsp_pcb) && 113821496Ssklower (cb->s_flags & SF_DELACK)) { 113921496Ssklower cb->s_flags &= ~SF_DELACK; 114021496Ssklower cb->s_flags |= SF_AK; 114121496Ssklower (void) spp_output(cb, (struct mbuf *) 0); 114221496Ssklower } 114321496Ssklower splx(s); 114421496Ssklower } 114521496Ssklower 114621496Ssklower /* 114721496Ssklower * spp protocol timeout routine called every 500 ms. 114821496Ssklower * Updates the timers in all active pcb's and 114921496Ssklower * causes finite state machine actions if timers expire. 115021496Ssklower */ 115121496Ssklower spp_slowtimo() 115221496Ssklower { 115321496Ssklower register struct nspcb *ip, *ipnxt; 115421496Ssklower register struct sppcb *cb; 115521496Ssklower int s = splnet(); 115621496Ssklower register int i; 115721496Ssklower 115821496Ssklower /* 115921496Ssklower * Search through tcb's and update active timers. 116021496Ssklower */ 116121496Ssklower ip = nspcb.nsp_next; 116221496Ssklower if (ip == 0) { 116321496Ssklower splx(s); 116421496Ssklower return; 116521496Ssklower } 116621496Ssklower while (ip != &nspcb) { 116721496Ssklower cb = nstosppcb(ip); 116821496Ssklower ipnxt = ip->nsp_next; 116921496Ssklower if (cb == 0) 117021496Ssklower goto tpgone; 117121496Ssklower for (i = 0; i < TCPT_NTIMERS; i++) { 117221496Ssklower if (cb->s_timer[i] && --cb->s_timer[i] == 0) { 117321496Ssklower (void) spp_usrreq(cb->s_nspcb->nsp_socket, 117421496Ssklower PRU_SLOWTIMO, (struct mbuf *)0, 117521496Ssklower (struct mbuf *)i, (struct mbuf *)0); 117621496Ssklower if (ipnxt->nsp_prev != ip) 117721496Ssklower goto tpgone; 117821496Ssklower } 117921496Ssklower } 118021496Ssklower cb->s_idle++; 118121496Ssklower if (cb->s_rtt) 118221496Ssklower cb->s_rtt++; 118321496Ssklower tpgone: 118421496Ssklower ip = ipnxt; 118521496Ssklower } 118621496Ssklower spp_iss += SPP_ISSINCR/PR_SLOWHZ; /* increment iss */ 118721496Ssklower splx(s); 118821496Ssklower } 118921496Ssklower 119021496Ssklower float spp_backoff[TCP_MAXRXTSHIFT] = 119121496Ssklower { 1.0, 1.2, 1.4, 1.7, 2.0, 3.0, 5.0, 8.0, 16.0, 32.0 }; 119221496Ssklower extern int tcpexprexmtbackoff; 119321496Ssklower /* 119421496Ssklower * TCP timer processing. 119521496Ssklower */ 119621496Ssklower struct sppcb * 119721496Ssklower spp_timers(cb, timer) 119821496Ssklower register struct sppcb *cb; 119921496Ssklower int timer; 120021496Ssklower { 120121496Ssklower 120221496Ssklower cb->s_force = 1 + timer; 120321496Ssklower switch (timer) { 120421496Ssklower 120521496Ssklower /* 120621496Ssklower * 2 MSL timeout in shutdown went off. Delete connection 120721496Ssklower * control block. 120821496Ssklower */ 120921496Ssklower case TCPT_2MSL: 121021496Ssklower cb = spp_close(cb); 121121496Ssklower break; 121221496Ssklower 121321496Ssklower /* 121421496Ssklower * Retransmission timer went off. Message has not 121521496Ssklower * been acked within retransmit interval. Back off 121621496Ssklower * to a longer retransmit interval and retransmit all 121721496Ssklower * unacknowledged messages in the window. 121821496Ssklower */ 121921496Ssklower case TCPT_REXMT: 122021496Ssklower cb->s_rxtshift++; 122121496Ssklower if (cb->s_rxtshift > TCP_MAXRXTSHIFT) { 122221496Ssklower cb = spp_drop(cb, ETIMEDOUT); 122321496Ssklower break; 122421496Ssklower } 122521496Ssklower (void) spp_output(cb, (struct mbuf *) 0); 122621496Ssklower TCPT_RANGESET(cb->s_timer[TCPT_REXMT], 122721496Ssklower (int)cb->s_srtt, TCPTV_MIN, TCPTV_MAX); 122821496Ssklower if (tcpexprexmtbackoff) { 122921496Ssklower TCPT_RANGESET(cb->s_timer[TCPT_REXMT], 123021496Ssklower cb->s_timer[TCPT_REXMT] << cb->s_rxtshift, 123121496Ssklower TCPTV_MIN, TCPTV_MAX); 123221496Ssklower } else { 123321496Ssklower TCPT_RANGESET(cb->s_timer[TCPT_REXMT], 123421496Ssklower cb->s_timer[TCPT_REXMT] * 123521496Ssklower spp_backoff[cb->s_rxtshift - 1], 123621496Ssklower TCPTV_MIN, TCPTV_MAX); 123721496Ssklower } 123821496Ssklower break; 123921496Ssklower 124021496Ssklower /* 124121496Ssklower * Persistance timer into zero window. 124221496Ssklower * Force a probe to be sent. 124321496Ssklower */ 124421496Ssklower case TCPT_PERSIST: 124521496Ssklower (void) spp_output(cb, (struct mbuf *) 0); 124621496Ssklower spp_setpersist(cb); 124721496Ssklower break; 124821496Ssklower 124921496Ssklower /* 125021496Ssklower * Keep-alive timer went off; send something 125121496Ssklower * or drop connection if idle for too long. 125221496Ssklower */ 125321496Ssklower case TCPT_KEEP: 125421496Ssklower if (cb->s_state < TCPS_ESTABLISHED) 125521496Ssklower goto dropit; 125621496Ssklower if (cb->s_nspcb->nsp_socket->so_options & SO_KEEPALIVE) { 125721496Ssklower if (cb->s_idle >= TCPTV_MAXIDLE) 125821496Ssklower goto dropit; 125921496Ssklower (void) spp_output(cb, (struct mbuf *) 0); 126021496Ssklower } else 126121496Ssklower cb->s_idle = 0; 126221496Ssklower cb->s_timer[TCPT_KEEP] = TCPTV_KEEP; 126321496Ssklower break; 126421496Ssklower dropit: 126521496Ssklower cb = spp_drop(cb, ETIMEDOUT); 126621496Ssklower break; 126721496Ssklower } 126821496Ssklower return (cb); 126921496Ssklower } 1270