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