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*24330Ssklower * @(#)spp_usrreq.c 6.8 (Berkeley) 08/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; 4624047Ssklower spp_input(m, nsp) 4721496Ssklower register struct mbuf *m; 4824047Ssklower register struct nspcb *nsp; 4921496Ssklower { 5021496Ssklower register struct sppcb *cb; 5121496Ssklower register struct spidp *si = mtod(m, struct spidp *); 5221496Ssklower register struct socket *so; 5324225Ssklower short ostate; 5421496Ssklower int dropsocket = 0; 5521496Ssklower 5621496Ssklower 57*24330Ssklower if (nsp == 0) { 5824047Ssklower panic("No nspcb in spp_input\n"); 5923979Ssklower return; 6023979Ssklower } 6121496Ssklower 6221496Ssklower cb = nstosppcb(nsp); 6321496Ssklower if (cb == 0) goto bad; 6421496Ssklower 6524047Ssklower if (m->m_len < sizeof(*si)) { 66*24330Ssklower if ((m = m_pullup(m, sizeof(*si))) == 0) { 6724047Ssklower spp_istat.hdrops++; 6824047Ssklower return; 6924047Ssklower } 7024047Ssklower si = mtod(m, struct spidp *); 7124047Ssklower } 7221496Ssklower si->si_seq = ntohs(si->si_seq); 7321496Ssklower si->si_ack = ntohs(si->si_ack); 7421496Ssklower si->si_alo = ntohs(si->si_alo); 7521496Ssklower 7621496Ssklower so = nsp->nsp_socket; 7721496Ssklower if (so->so_options & SO_DEBUG || traceallspps) { 7821496Ssklower ostate = cb->s_state; 7921496Ssklower spp_savesi = *si; 8021496Ssklower } 8121496Ssklower if (so->so_options & SO_ACCEPTCONN) { 8221496Ssklower so = sonewconn(so); 8321496Ssklower if (so == 0) { 8421496Ssklower spp_istat.nonucn++; 8521496Ssklower goto drop; 8621496Ssklower } 8721496Ssklower /* 8821496Ssklower * This is ugly, but .... 8921496Ssklower * 9021496Ssklower * Mark socket as temporary until we're 9121496Ssklower * committed to keeping it. The code at 9221496Ssklower * ``drop'' and ``dropwithreset'' check the 9321496Ssklower * flag dropsocket to see if the temporary 9421496Ssklower * socket created here should be discarded. 9521496Ssklower * We mark the socket as discardable until 9621496Ssklower * we're committed to it below in TCPS_LISTEN. 9721496Ssklower */ 9821496Ssklower dropsocket++; 9921496Ssklower nsp = (struct nspcb *)so->so_pcb; 10021496Ssklower nsp->nsp_laddr = si->si_dna; 10121496Ssklower cb = nstosppcb(nsp); 10221496Ssklower cb->s_state = TCPS_LISTEN; 10321496Ssklower } 10421496Ssklower 10521496Ssklower /* 10621496Ssklower * Packet received on connection. 10721496Ssklower * reset idle time and keep-alive timer; 10821496Ssklower */ 10921496Ssklower cb->s_idle = 0; 11021496Ssklower cb->s_timer[TCPT_KEEP] = TCPTV_KEEP; 11121496Ssklower 11221496Ssklower switch (cb->s_state) { 11323515Ssklower 11421496Ssklower case TCPS_LISTEN:{ 11521496Ssklower struct mbuf *am; 11621496Ssklower register struct sockaddr_ns *sns; 11721496Ssklower struct ns_addr laddr; 11821496Ssklower 11921496Ssklower /* 12021496Ssklower * If somebody here was carying on a conversation 12121496Ssklower * and went away, and his pen pal thinks he can 12221496Ssklower * still talk, we get the misdirected packet. 12321496Ssklower */ 12421496Ssklower if (spp_hardnosed && (si->si_did != 0 || si->si_seq != 0)) { 12521496Ssklower spp_istat.gonawy++; 12621496Ssklower goto dropwithreset; 12721496Ssklower } 12821496Ssklower am = m_get(M_DONTWAIT, MT_SONAME); 12921496Ssklower if (am == NULL) 13021496Ssklower goto drop; 13121496Ssklower am->m_len = sizeof (struct sockaddr_ns); 13221496Ssklower sns = mtod(am, struct sockaddr_ns *); 13321496Ssklower sns->sns_family = AF_NS; 13421496Ssklower sns->sns_addr = si->si_sna; 13521496Ssklower laddr = nsp->nsp_laddr; 13621496Ssklower if (ns_nullhost(laddr)) 13721496Ssklower nsp->nsp_laddr = si->si_dna; 13821496Ssklower if (ns_pcbconnect(nsp, am)) { 13921496Ssklower nsp->nsp_laddr = laddr; 14021496Ssklower (void) m_free(am); 14121496Ssklower spp_istat.noconn++; 14221496Ssklower goto drop; 14321496Ssklower } 14421496Ssklower (void) m_free(am); 14521496Ssklower cb->s_state = TCPS_SYN_RECEIVED; 14621496Ssklower spp_template(cb); 14721496Ssklower cb->s_did = si->si_sid; 14821496Ssklower cb->s_rack = si->si_ack; 14921496Ssklower cb->s_ralo = si->si_alo; 15021496Ssklower cb->s_flags |= SF_AK; 15121496Ssklower cb->s_timer[TCPT_KEEP] = TCPTV_KEEP; 15221496Ssklower dropsocket = 0; /* committed to socket */ 15321496Ssklower } 15421496Ssklower break; 15521496Ssklower 15621496Ssklower /* 15721496Ssklower * This state means that we have gotten a response 15821496Ssklower * to our attempt to establish a connection. 15923979Ssklower * We fill in the data from the other side, 16023979Ssklower * telling us which port to respond to, instead of the well- 16123979Ssklower * known one we might have sent to in the first place. 16221496Ssklower * We also require that this is a response to our 16323979Ssklower * connection id. 16421496Ssklower */ 16521496Ssklower case TCPS_SYN_SENT: 16621496Ssklower if (si->si_did!=cb->s_sid) { 16721496Ssklower spp_istat.notme++; 16821496Ssklower goto drop; 16921496Ssklower } 17021496Ssklower cb->s_did = si->si_sid; 17121496Ssklower cb->s_rack = si->si_ack; 17221496Ssklower cb->s_ralo = si->si_alo; 17321496Ssklower cb->s_dport = nsp->nsp_fport = si->si_sport; 17421496Ssklower cb->s_timer[TCPT_REXMT] = 0; 17521496Ssklower cb->s_flags |= SF_AK; 17621496Ssklower soisconnected(so); 17721496Ssklower cb->s_state = TCPS_ESTABLISHED; 17821496Ssklower break; 17921496Ssklower /* 18021496Ssklower * This state means that we have heard a response 18121496Ssklower * to our acceptance of their connection 18221496Ssklower * It is probably logically unnecessary in this 18321496Ssklower * implementation. 18421496Ssklower */ 18521496Ssklower case TCPS_SYN_RECEIVED: 18621496Ssklower if (si->si_did!=cb->s_sid) { 18721496Ssklower spp_istat.wrncon++; 18821496Ssklower goto drop; 18921496Ssklower } 19021496Ssklower nsp->nsp_fport = si->si_sport; 19121496Ssklower cb->s_timer[TCPT_REXMT] = 0; 19221496Ssklower cb->s_timer[TCPT_KEEP] = TCPTV_KEEP; 19321496Ssklower soisconnected(so); 19421496Ssklower cb->s_state = TCPS_ESTABLISHED; 19521496Ssklower } 19621496Ssklower if (so->so_options & SO_DEBUG || traceallspps) 19724225Ssklower spp_trace(SA_INPUT, (u_char)ostate, cb, &spp_savesi, 0); 19821496Ssklower 19921496Ssklower m->m_len -= sizeof (struct idp); 20021496Ssklower m->m_off += sizeof (struct idp); 20121496Ssklower 20221496Ssklower if (spp_reass(cb,si)) { 20321496Ssklower goto drop; 20421496Ssklower } 20524225Ssklower (void) spp_output(cb,(struct mbuf *)0); 20621496Ssklower return; 20721496Ssklower 20821496Ssklower dropwithreset: 20921496Ssklower if (dropsocket) 21021496Ssklower (void) soabort(so); 21121496Ssklower si->si_seq = ntohs(si->si_seq); 21221496Ssklower si->si_ack = ntohs(si->si_ack); 21321496Ssklower si->si_alo = ntohs(si->si_alo); 21421496Ssklower ns_error(dtom(si), NS_ERR_NOSOCK, 0); 21521496Ssklower if (cb->s_nspcb->nsp_socket->so_options & SO_DEBUG || traceallspps) 21624225Ssklower spp_trace(SA_DROP, (u_char)ostate, cb, &spp_savesi, 0); 21721496Ssklower return; 21821496Ssklower 21921496Ssklower drop: 22021496Ssklower bad: 221*24330Ssklower if (cb == 0 || cb->s_nspcb->nsp_socket->so_options & SO_DEBUG || traceallspps) 22224225Ssklower spp_trace(SA_DROP, (u_char)ostate, cb, &spp_savesi, 0); 22321496Ssklower m_freem(m); 22421496Ssklower } 22521496Ssklower 22621496Ssklower /* 22721496Ssklower * This is structurally similar to the tcp reassembly routine 22821496Ssklower * but its function is somewhat different: It merely queues 22921496Ssklower * packets up, and suppresses duplicates. 23021496Ssklower */ 23121496Ssklower spp_reass(cb,si) 23221496Ssklower register struct sppcb *cb; 23321496Ssklower register struct spidp *si; 23421496Ssklower { 23521496Ssklower register struct spidp_q *q; 23621496Ssklower register struct mbuf *m; 23721496Ssklower struct socket *so = cb->s_nspcb->nsp_socket; 23821496Ssklower struct sockbuf *sb = & (so->so_rcv); 23921496Ssklower char packetp = cb->s_flags & SF_HI; 24021496Ssklower char wakeup = 0; 24121496Ssklower 24221496Ssklower 243*24330Ssklower if (si == SI(0)) 24421496Ssklower goto present; 24521496Ssklower /* 24621496Ssklower * Update our news from them. 24721496Ssklower */ 24821496Ssklower if (si->si_cc & SP_SA) 24921496Ssklower cb->s_flags |= SF_DELACK; 25021496Ssklower if (SSEQ_GT(si->si_ack,cb->s_rack)) { 25121496Ssklower cb->s_rack = si->si_ack; 25221496Ssklower cb->s_timer[TCPT_REXMT] = 0; 25321496Ssklower 25421496Ssklower /* 25521496Ssklower * If transmit timer is running and timed sequence 25621496Ssklower * number was acked, update smoothed round trip time. 25721496Ssklower */ 25821496Ssklower if (cb->s_rtt && SSEQ_GT(si->si_ack, cb->s_rtseq)) { 25921496Ssklower if (cb->s_srtt == 0) 26021496Ssklower cb->s_srtt = cb->s_rtt; 26121496Ssklower else 26221496Ssklower cb->s_srtt = 26321496Ssklower tcp_alpha * cb->s_srtt + 26421496Ssklower (1 - tcp_alpha) * cb->s_rtt; 26521496Ssklower cb->s_rtt = 0; 26621496Ssklower } 26721496Ssklower } 26821496Ssklower if (SSEQ_GT(si->si_alo,cb->s_ralo)) { 26921496Ssklower cb->s_ralo = si->si_alo; 27021496Ssklower cb->s_timer[TCPT_PERSIST] = 0; 27121496Ssklower } 27221496Ssklower /* 27321496Ssklower * If this is a system packet, we don't need to 27421496Ssklower * queue it up, and won't update acknowledge # 27521496Ssklower */ 27623561Ssklower if (si->si_cc & SP_SP) { 27723561Ssklower m_freem(dtom(si)); 27823515Ssklower return (0); 27923561Ssklower } 28021496Ssklower 28121496Ssklower /* 28221496Ssklower * If this packet number has a sequence number less 28321496Ssklower * than that of the first packet not yet seen coming 28421496Ssklower * from them, this must be a duplicate, so drop. 28521496Ssklower */ 28623979Ssklower if (SSEQ_LT(si->si_seq,cb->s_ack)) { 28723979Ssklower spp_istat.bdreas++; 288*24330Ssklower if (si->si_seq == cb->s_ack-1) 28923979Ssklower spp_istat.lstdup++; 29023515Ssklower return (1); 29123979Ssklower } 29221496Ssklower /* 29321496Ssklower * If this packet number is higher than that which 29421496Ssklower * we have allocated refuse it, unless urgent 29521496Ssklower */ 29621496Ssklower if (SSEQ_GT(si->si_seq,cb->s_alo) && (!(si->si_cc & SP_OB))) { 29723979Ssklower spp_istat.notyet++; 29823515Ssklower return (1); 29921496Ssklower } 30021496Ssklower /* 30121496Ssklower * If this packet is urgent, inform process 30221496Ssklower */ 30321496Ssklower if (si->si_cc & SP_OB) { 30421496Ssklower cb->s_iobc = ((char *)si)[1 + sizeof(*si)]; 30521496Ssklower sohasoutofband(so); 30621496Ssklower } 30721496Ssklower 30821496Ssklower /* 30921496Ssklower * Loop through all packets queued up to insert in 31021496Ssklower * appropriate sequence. 31121496Ssklower */ 31221496Ssklower 31321496Ssklower for (q = cb->s_q.si_next; q!=&cb->s_q; q = q->si_next) { 314*24330Ssklower if (si->si_seq == SI(q)->si_seq) return (1); /*duplicate */ 31521496Ssklower if (SSEQ_LT(si->si_seq,SI(q)->si_seq)) break; 31621496Ssklower } 31721496Ssklower insque(si,q->si_prev); 31821496Ssklower 31921496Ssklower present: 32021496Ssklower #define SPINC sizeof(struct sphdr) 32121496Ssklower /* 32221496Ssklower * Loop through all packets queued up to update acknowledge 32321496Ssklower * number, and present all acknowledged data to user; 32421496Ssklower * If in packet interface mode, show packet headers. 32521496Ssklower */ 32621496Ssklower for (q = cb->s_q.si_next; q!=&cb->s_q; q = q->si_next) { 327*24330Ssklower if (SI(q)->si_seq == cb->s_ack) { 32821496Ssklower cb->s_ack++; 32921496Ssklower m = dtom(q); 33021496Ssklower if (SI(q)->si_cc & SP_OB) { 33121496Ssklower if (sb->sb_cc) 33221496Ssklower so->so_oobmark = sb->sb_cc; 33321496Ssklower else 33421496Ssklower so->so_state |= SS_RCVATMARK; 33521496Ssklower } 33621496Ssklower q = q->si_prev; 33721496Ssklower remque(q->si_next); 33821496Ssklower wakeup = 1; 33921496Ssklower if (packetp) { 34021496Ssklower sbappendrecord(sb,m); 34121496Ssklower } else { 34221496Ssklower cb->s_rhdr = *mtod(m, struct sphdr *); 34321496Ssklower m->m_off += SPINC; 34421496Ssklower m->m_len -= SPINC; 34521496Ssklower sbappend(sb,m); 34621496Ssklower } 34721496Ssklower } else 34821496Ssklower break; 34921496Ssklower } 35021496Ssklower if (wakeup) sorwakeup(so); 35123515Ssklower return (0); 35221496Ssklower } 35321496Ssklower 35421496Ssklower spp_ctlinput(cmd, arg) 35521496Ssklower int cmd; 35621496Ssklower caddr_t arg; 35721496Ssklower { 35821496Ssklower struct ns_addr *na; 35921496Ssklower extern u_char nsctlerrmap[]; 36021496Ssklower extern spp_abort(); 36124225Ssklower extern struct nspcb *idp_drop(); 36223979Ssklower struct ns_errp *errp; 36323979Ssklower struct nspcb *nsp; 36421496Ssklower int type; 36521496Ssklower 36621496Ssklower if (cmd < 0 || cmd > PRC_NCMDS) 36721496Ssklower return; 36821496Ssklower type = NS_ERR_UNREACH_HOST; 36921496Ssklower 37021496Ssklower switch (cmd) { 37123515Ssklower 37221496Ssklower case PRC_ROUTEDEAD: 37321496Ssklower case PRC_QUENCH: 37421496Ssklower break; 37521496Ssklower 37621496Ssklower case PRC_IFDOWN: 37721496Ssklower na = &((struct sockaddr_ns *)arg)->sns_addr; 37821496Ssklower break; 37921496Ssklower 38021496Ssklower case PRC_HOSTDEAD: 38121496Ssklower case PRC_HOSTUNREACH: 38221496Ssklower na = (struct ns_addr *)arg; 38321496Ssklower break; 38421496Ssklower 38521496Ssklower default: 38623979Ssklower errp = (struct ns_errp *)arg; 38723979Ssklower na = &errp->ns_err_idp.idp_dna; 38823979Ssklower type = errp->ns_err_num; 38924225Ssklower type = ntohs((u_short)type); 39021496Ssklower } 39121496Ssklower switch (type) { 39223515Ssklower 39321496Ssklower case NS_ERR_UNREACH_HOST: 39423979Ssklower ns_pcbnotify(na, (int)nsctlerrmap[cmd], spp_abort, (long) 0); 39521496Ssklower break; 39623515Ssklower 39721496Ssklower case NS_ERR_TOO_BIG: 39823979Ssklower case NS_ERR_NOSOCK: 39923979Ssklower nsp = ns_pcblookup(na, errp->ns_err_idp.idp_sna.x_port, 40023979Ssklower NS_WILDCARD); 40123979Ssklower if (nsp) { 40223979Ssklower if(nsp->nsp_pcb) 40324225Ssklower (void) spp_drop((struct sppcb *)nsp->nsp_pcb, 40424225Ssklower (int)nsctlerrmap[cmd]); 40523979Ssklower else 40624225Ssklower (void) idp_drop(nsp, (int)nsctlerrmap[cmd]); 40723979Ssklower } 40821496Ssklower } 40921496Ssklower } 41021496Ssklower 41124225Ssklower #ifdef notdef 41221496Ssklower int 41321496Ssklower spp_fixmtu(nsp) 41421496Ssklower register struct nspcb *nsp; 41521496Ssklower { 41621496Ssklower register struct sppcb *cb = (struct sppcb *)(nsp->nsp_pcb); 41721496Ssklower register struct mbuf *m; 41821496Ssklower register struct spidp *si; 41921496Ssklower struct ns_errp *ep; 42021496Ssklower struct sockbuf *sb; 42121496Ssklower int badseq, len; 42221496Ssklower struct mbuf *firstbad, *m0; 42321496Ssklower 42421496Ssklower if (cb) { 42521496Ssklower /* 42621496Ssklower * The notification that we have sent 42721496Ssklower * too much is bad news -- we will 42821496Ssklower * have to go through queued up so far 42921496Ssklower * splitting ones which are too big and 43021496Ssklower * reassigning sequence numbers and checksums. 43121496Ssklower * we should then retransmit all packets from 43221496Ssklower * one above the offending packet to the last one 43321496Ssklower * we had sent (or our allocation) 43421496Ssklower * then the offending one so that the any queued 43521496Ssklower * data at our destination will be discarded. 43621496Ssklower */ 43721496Ssklower ep = (struct ns_errp *)nsp->nsp_notify_param; 43821496Ssklower sb = &nsp->nsp_socket->so_snd; 43921496Ssklower cb->s_mtu = ep->ns_err_param; 44021496Ssklower badseq = SI(&ep->ns_err_idp)->si_seq; 44121496Ssklower for (m = sb->sb_mb; m; m = m->m_act) { 44221496Ssklower si = mtod(m, struct spidp *); 44321496Ssklower if (si->si_seq == badseq) 44421496Ssklower break; 44521496Ssklower } 446*24330Ssklower if (m == 0) return; 44721496Ssklower firstbad = m; 44821496Ssklower /*for (;;) {*/ 44921496Ssklower /* calculate length */ 45021496Ssklower for (m0 = m, len = 0; m ; m = m->m_next) 45121496Ssklower len += m->m_len; 45221496Ssklower if (len > cb->s_mtu) { 45321496Ssklower } 45421496Ssklower /* FINISH THIS 45521496Ssklower } */ 45621496Ssklower } 45721496Ssklower } 45824225Ssklower #endif 45921496Ssklower 46021496Ssklower int spp_output_cnt = 0; 46123979Ssklower 46221496Ssklower spp_output(cb, m0) 46321496Ssklower register struct sppcb *cb; 46421496Ssklower struct mbuf *m0; 46521496Ssklower { 46621496Ssklower struct socket *so = cb->s_nspcb->nsp_socket; 46721496Ssklower register struct mbuf *m; 46821496Ssklower register struct spidp *si = (struct spidp *) 0; 46921496Ssklower register struct sockbuf *sb = &(so->so_snd); 47021496Ssklower register int len = 0; 47124225Ssklower int mtu = cb->s_mtu; 472*24330Ssklower int error = 0; 473*24330Ssklower u_short lookfor = 0; 47421496Ssklower struct mbuf *mprev; 47521496Ssklower extern int idpcksum; 47621496Ssklower 477*24330Ssklower if (m0) { 47821496Ssklower for (m = m0; m ; m = m->m_next) { 47921496Ssklower mprev = m; 48021496Ssklower len += m->m_len; 48121496Ssklower } 48221496Ssklower if (len > mtu) { 48321496Ssklower if (cb->s_flags & SF_PI) { 48421496Ssklower m_freem(m0); 48523515Ssklower return (EMSGSIZE); 48621496Ssklower } else { 48721496Ssklower int off = 0; 48821496Ssklower while (len > mtu) { 48921496Ssklower m = m_copy(m0, off, mtu); 490*24330Ssklower if (m == NULL) { 49123515Ssklower m_freem(m0); 49223515Ssklower return (ENOBUFS); 49323515Ssklower } 49421496Ssklower error = spp_output(cb, m); 49521496Ssklower if (error) { 49621496Ssklower m_freem(m0); 49723515Ssklower return (error); 49821496Ssklower } 49921496Ssklower m_adj(m0, mtu); 50021496Ssklower len -= mtu; 50121496Ssklower } 50221496Ssklower } 50321496Ssklower } 504*24330Ssklower /* 505*24330Ssklower * Force length even, by adding a "garbage byte" if 506*24330Ssklower * necessary. 507*24330Ssklower */ 50821496Ssklower if (len & 1) { 50923979Ssklower m = mprev; 510*24330Ssklower if (m->m_len + m->m_off < MMAXOFF) 51121496Ssklower m->m_len++; 512*24330Ssklower else { 51321496Ssklower struct mbuf *m1 = m_get(M_DONTWAIT, MT_DATA); 51421496Ssklower 51521496Ssklower if (m1 == 0) { 51621496Ssklower m_freem(m0); 51721496Ssklower return (ENOBUFS); 51821496Ssklower } 51921496Ssklower m1->m_len = 1; 52021496Ssklower m1->m_off = MMAXOFF - 1; 521*24330Ssklower m->m_next = m1; 52221496Ssklower } 52321496Ssklower } 52421496Ssklower m = m_get(M_DONTWAIT, MT_HEADER); 52521496Ssklower if (m == 0) { 52621496Ssklower m_freem(m0); 52723515Ssklower return (ENOBUFS); 52821496Ssklower } 52921496Ssklower 53021496Ssklower /* 53121496Ssklower * Fill in mbuf with extended SP header 53221496Ssklower * and addresses and length put into network format. 53321496Ssklower */ 53421496Ssklower m->m_off = MMAXOFF - sizeof (struct spidp); 53521496Ssklower m->m_len = sizeof (struct spidp); 53621496Ssklower m->m_next = m0; 53721496Ssklower si = mtod(m, struct spidp *); 53821496Ssklower *si = cb->s_shdr; 53921496Ssklower if ((cb->s_flags & SF_PI) && (cb->s_flags & SF_HO)) { 540*24330Ssklower register struct sphdr *sh; 541*24330Ssklower if (m0->m_len < sizeof (*sh)) { 542*24330Ssklower if((m0 = m_pullup(m0, sizeof(*sh))) == NULL) { 543*24330Ssklower (void) m_free(m); 544*24330Ssklower m_freem(m0); 545*24330Ssklower return (EINVAL); 546*24330Ssklower } 547*24330Ssklower m->m_next = m0; 548*24330Ssklower } 549*24330Ssklower sh = mtod(m0, struct sphdr *); 55021496Ssklower si->si_dt = sh->sp_dt; 55121496Ssklower si->si_cc |= sh->sp_cc & SP_EM; 55221496Ssklower m0->m_len -= sizeof (*sh); 55321496Ssklower m0->m_off += sizeof (*sh); 55421496Ssklower len -= sizeof (*sh); 55521496Ssklower } 55621496Ssklower len += sizeof(*si); 55723979Ssklower if (cb->s_oobflags & SF_SOOB) { 55823979Ssklower /* 55923979Ssklower * Per jqj@cornell: 56023979Ssklower * make sure OB packets convey exactly 1 byte. 56123979Ssklower * If the packet is 1 byte or larger, we 56223979Ssklower * have already guaranted there to be at least 56323979Ssklower * one garbage byte for the checksum, and 56423979Ssklower * extra bytes shouldn't hurt! 56523979Ssklower */ 56623979Ssklower if (len > sizeof(*si)) { 56723979Ssklower si->si_cc |= SP_OB; 56823979Ssklower len = (1 + sizeof(*si)); 56923979Ssklower } 57023979Ssklower } 57124225Ssklower si->si_len = htons((u_short)len); 57221496Ssklower /* 57321496Ssklower * queue stuff up for output 57421496Ssklower */ 57521496Ssklower sbappendrecord(sb,m); 57621496Ssklower cb->s_seq++; 57721496Ssklower } 57821496Ssklower /* 57921496Ssklower * update window 58021496Ssklower */ 58121496Ssklower { 58224225Ssklower register struct sockbuf *sb2 = &so->so_rcv; 58324225Ssklower int credit = ((sb2->sb_mbmax - sb2->sb_mbcnt) / cb->s_mtu); 58421496Ssklower int alo = cb->s_ack + credit; 58521496Ssklower 586*24330Ssklower if (cb->s_alo < alo) 587*24330Ssklower cb->s_alo = alo; 58821496Ssklower } 58921496Ssklower 59021496Ssklower if (cb->s_oobflags & SF_SOOB) { 59121496Ssklower /* 59221496Ssklower * must transmit this out of band packet 59321496Ssklower */ 59421496Ssklower cb->s_oobflags &= ~ SF_SOOB; 59521496Ssklower } else { 59621496Ssklower /* 59721496Ssklower * Decide what to transmit: 59821496Ssklower * If we have a new packet, send that 59921496Ssklower * (So long as it is in our allocation) 60021496Ssklower * If it is time to retransmit a packet, 60121496Ssklower * send that. 60221496Ssklower * Otherwise, see if it time to bang on them 60321496Ssklower * to ask for our current allocation. 60421496Ssklower */ 60521496Ssklower if (SSEQ_LT(cb->s_snt, cb->s_ralo)) 60621496Ssklower lookfor = cb->s_snt + 1; 607*24330Ssklower else if (cb->s_force == (1+TCPT_REXMT)) { 60821496Ssklower lookfor = cb->s_rack; 60921496Ssklower } else if (SSEQ_LT(cb->s_ralo, cb->s_seq)) { 61021496Ssklower lookfor = 0; 611*24330Ssklower if (cb->s_timer[TCPT_PERSIST] == 0) { 61221496Ssklower spp_setpersist(cb); 613*24330Ssklower /* tcp has cb->s_rxtshift = 0; here */ 61421496Ssklower } 61521496Ssklower } 61621496Ssklower m = sb->sb_mb; 617*24330Ssklower while (m) { 61821496Ssklower si = mtod(m, struct spidp *); 61921496Ssklower m = m->m_act; 62021496Ssklower if (SSEQ_LT(si->si_seq, cb->s_rack)) { 62121496Ssklower if ((sb->sb_flags & SB_WAIT) 62221496Ssklower || so->so_snd.sb_sel) 62321496Ssklower sowwakeup(so); 62421496Ssklower sbdroprecord(sb); 62521496Ssklower si = 0; 62621496Ssklower continue; 62721496Ssklower } 62821496Ssklower if (SSEQ_LT(si->si_seq, lookfor)) 62921496Ssklower continue; 63021496Ssklower break; 63121496Ssklower } 632*24330Ssklower if (si && (si->si_seq != lookfor)) 633*24330Ssklower si = 0; 63421496Ssklower } 63521496Ssklower cb->s_want = lookfor; 63621496Ssklower 63721496Ssklower if (si) { 63821496Ssklower /* 63921496Ssklower * must make a copy of this packet for 64021496Ssklower * idp_output to monkey with 64121496Ssklower */ 642*24330Ssklower m = m_copy(dtom(si), 0, (int)M_COPYALL); 643*24330Ssklower if (m == NULL) 64423515Ssklower return (ENOBUFS); 64523515Ssklower m0 = m; 64621496Ssklower si = mtod(m, struct spidp *); 64721496Ssklower } else if (cb->s_force || cb->s_flags & SF_AK) { 64821496Ssklower /* 64921496Ssklower * Must send an acknowledgement or a probe 65021496Ssklower */ 65121496Ssklower m = m_get(M_DONTWAIT, MT_HEADER); 65221496Ssklower if (m == 0) 65323515Ssklower return (ENOBUFS); 65421496Ssklower /* 65521496Ssklower * Fill in mbuf with extended SP header 65621496Ssklower * and addresses and length put into network format. 65721496Ssklower */ 65821496Ssklower m->m_off = MMAXOFF - sizeof (struct spidp); 65921496Ssklower m->m_len = sizeof (*si); 66021496Ssklower m->m_next = 0; 66121496Ssklower si = mtod(m, struct spidp *); 66221496Ssklower *si = cb->s_shdr; 66321496Ssklower si->si_seq = cb->s_snt + 1; 66423979Ssklower si->si_len = htons(sizeof (*si)); 66521496Ssklower si->si_cc |= SP_SP; 66621496Ssklower cb->s_flags &= ~SF_AK; 66721496Ssklower } 66821496Ssklower /* 66921496Ssklower * Stuff checksum and output datagram. 67021496Ssklower */ 67121496Ssklower if (si) { 67221496Ssklower /* 67321496Ssklower * If we are almost out of allocation 67421496Ssklower * or one of the timers has gone off 67521496Ssklower * request an ack. 67621496Ssklower */ 677*24330Ssklower if (SSEQ_GEQ(cb->s_seq, cb->s_ralo)) 67821496Ssklower si->si_cc |= SP_SA; 67921496Ssklower if (cb->s_force) { 68021496Ssklower si->si_cc |= SP_SA; 68121496Ssklower cb->s_force = 0; 68221496Ssklower } 683*24330Ssklower /* 684*24330Ssklower * If this is a new packet (and not a system packet), 68523979Ssklower * and we are not currently timing anything, 68623979Ssklower * time this one and ask for an ack. 68721496Ssklower */ 688*24330Ssklower if (SSEQ_LT(cb->s_snt, si->si_seq) && (!(si->si_cc & SP_SP))) { 68921496Ssklower cb->s_snt = si->si_seq; 690*24330Ssklower if (cb->s_rtt == 0) { 69121496Ssklower cb->s_rtseq = si->si_seq; 69221496Ssklower cb->s_rtt = 1; 69321496Ssklower si->si_cc |= SP_SA; 69421496Ssklower } 69521496Ssklower /* 69621496Ssklower * If the retransmit timer has not been set 69721496Ssklower * and this is a real packet 69821496Ssklower * then start the retransmit timer 69921496Ssklower */ 700*24330Ssklower if (cb->s_timer[TCPT_REXMT] == 0) { 70121496Ssklower TCPT_RANGESET(cb->s_timer[TCPT_REXMT], 70221496Ssklower tcp_beta * cb->s_srtt, TCPTV_MIN, 70321496Ssklower TCPTV_MAX); 70421496Ssklower cb->s_rxtshift = 0; 70521496Ssklower } 70621496Ssklower } 70721496Ssklower si->si_seq = htons(si->si_seq); 70821496Ssklower si->si_alo = htons(cb->s_alo); 70921496Ssklower si->si_ack = htons(cb->s_ack); 71021496Ssklower 71121496Ssklower if (idpcksum) { 71221496Ssklower si->si_sum = 0; 71323979Ssklower len = ntohs(si->si_len); 714*24330Ssklower if (len & 1) 715*24330Ssklower len++; 71621496Ssklower si->si_sum = ns_cksum(dtom(si), len); 71721496Ssklower } else 71821496Ssklower si->si_sum = 0xffff; 71921496Ssklower 72021496Ssklower if (so->so_options & SO_DEBUG || traceallspps) 72121496Ssklower spp_trace(SA_OUTPUT, cb->s_state, cb, si, 0); 72221496Ssklower spp_output_cnt++; 72321496Ssklower if (so->so_options & SO_DONTROUTE) 72421496Ssklower error = ns_output(m, (struct route *)0, NS_ROUTETOIF); 72521496Ssklower else 72621496Ssklower error = ns_output(m, &cb->s_nspcb->nsp_route, 0); 72721496Ssklower if (traceallspps && sppconsdebug) { 72821496Ssklower printf("spp_out: %x\n", error); 72921496Ssklower } 73023515Ssklower return (error); 73121496Ssklower } 73221496Ssklower if (so->so_options & SO_DEBUG || traceallspps) 73321496Ssklower spp_trace(SA_OUTPUT, cb->s_state, cb, si, 0); 73423515Ssklower return (error); 73521496Ssklower } 73621496Ssklower 73721496Ssklower /*ARGSUSED*/ 73821496Ssklower spp_ctloutput(req, so, level, name, value) 73921496Ssklower int req; 74021496Ssklower struct socket *so; 74121496Ssklower int name; 74221496Ssklower struct mbuf **value; 74321496Ssklower { 74421496Ssklower register struct mbuf *m; 74521496Ssklower struct nspcb *nsp = sotonspcb(so); 74621496Ssklower register struct sppcb *cb; 74721496Ssklower int mask, error = 0; 74821496Ssklower 74921496Ssklower if (level != NSPROTO_SPP) { 75021496Ssklower /* This will have to be changed when we do more general 75121496Ssklower stacking of protocols */ 75223515Ssklower return (idp_ctloutput(req, so, level, name, value)); 75321496Ssklower } 75421496Ssklower if (nsp == NULL) { 75521496Ssklower error = EINVAL; 75621496Ssklower goto release; 75721496Ssklower } else 75821496Ssklower cb = nstosppcb(nsp); 75921496Ssklower 76021496Ssklower switch (req) { 76123515Ssklower 76221496Ssklower case PRCO_GETOPT: 763*24330Ssklower if (value == NULL) 76423515Ssklower return (EINVAL); 76521496Ssklower m = m_get(M_DONTWAIT, MT_DATA); 766*24330Ssklower if (m == NULL) 76723515Ssklower return (ENOBUFS); 76821496Ssklower switch (name) { 76923515Ssklower 77021496Ssklower case SO_HEADERS_ON_INPUT: 77121496Ssklower mask = SF_HI; 77221496Ssklower goto get_flags; 77323515Ssklower 77421496Ssklower case SO_HEADERS_ON_OUTPUT: 77521496Ssklower mask = SF_HO; 77621496Ssklower get_flags: 77721496Ssklower m->m_len = sizeof(short); 77821496Ssklower m->m_off = MMAXOFF - sizeof(short); 77921496Ssklower *mtod(m, short *) = cb->s_flags & mask; 78021496Ssklower break; 78123515Ssklower 78221496Ssklower case SO_LAST_HEADER: 78321496Ssklower m->m_len = sizeof(struct sphdr); 78421496Ssklower m->m_off = MMAXOFF - sizeof(struct sphdr); 78521496Ssklower *mtod(m, struct sphdr *) = cb->s_rhdr; 78621496Ssklower break; 78723515Ssklower 78821496Ssklower case SO_DEFAULT_HEADERS: 78921496Ssklower m->m_len = sizeof(struct spidp); 79021496Ssklower m->m_off = MMAXOFF - sizeof(struct sphdr); 79121496Ssklower *mtod(m, struct sphdr *) = cb->s_shdr.si_s; 79221496Ssklower } 79321496Ssklower *value = m; 79421496Ssklower break; 79523515Ssklower 79621496Ssklower case PRCO_SETOPT: 79721496Ssklower switch (name) { 79824225Ssklower int *ok; 79921496Ssklower 80021496Ssklower case SO_HEADERS_ON_INPUT: 80121496Ssklower mask = SF_HI; 80221496Ssklower goto set_head; 80323515Ssklower 80421496Ssklower case SO_HEADERS_ON_OUTPUT: 80521496Ssklower mask = SF_HO; 80621496Ssklower set_head: 80721496Ssklower if (value && *value) { 80821496Ssklower ok = mtod(*value, int *); 80921496Ssklower if (*ok) 81021496Ssklower cb->s_flags |= mask; 81121496Ssklower else 81221496Ssklower cb->s_flags &= ~mask; 81321496Ssklower } else error = EINVAL; 81421496Ssklower break; 81523515Ssklower 81621496Ssklower case SO_DEFAULT_HEADERS: 81721496Ssklower { 81821496Ssklower register struct sphdr *sp 81921496Ssklower = mtod(*value, struct sphdr *); 82021496Ssklower cb->s_dt = sp->sp_dt; 82121496Ssklower cb->s_cc = sp->sp_cc & SP_EM; 82221496Ssklower } 82321496Ssklower } 82421496Ssklower if (value && *value) 82521496Ssklower m_freem(*value); 82621496Ssklower break; 82721496Ssklower } 82821496Ssklower release: 82923515Ssklower return (error); 83021496Ssklower } 83121496Ssklower 83221496Ssklower /*ARGSUSED*/ 83321496Ssklower spp_usrreq(so, req, m, nam, rights) 83421496Ssklower struct socket *so; 83521496Ssklower int req; 83621496Ssklower struct mbuf *m, *nam, *rights; 83721496Ssklower { 83821496Ssklower struct nspcb *nsp = sotonspcb(so); 83921496Ssklower register struct sppcb *cb; 84021496Ssklower int s = splnet(); 84121496Ssklower int error = 0, ostate; 84221496Ssklower 84321496Ssklower if (req == PRU_CONTROL) 84421496Ssklower return (ns_control(so, (int)m, (caddr_t)nam, 84521496Ssklower (struct ifnet *)rights)); 84621496Ssklower if (rights && rights->m_len) { 84721496Ssklower error = EINVAL; 84821496Ssklower goto release; 84921496Ssklower } 85021496Ssklower if (nsp == NULL) { 85121496Ssklower if (req != PRU_ATTACH) { 85221496Ssklower error = EINVAL; 85321496Ssklower goto release; 85421496Ssklower } 85521496Ssklower } else 85621496Ssklower cb = nstosppcb(nsp); 85721496Ssklower 85821496Ssklower ostate = cb ? cb->s_state : 0; 85921496Ssklower 86021496Ssklower switch (req) { 86123515Ssklower 86221496Ssklower case PRU_ATTACH: 86321496Ssklower if (nsp != NULL) { 86421496Ssklower error = EISCONN; 86521496Ssklower break; 86621496Ssklower } 86721496Ssklower error = ns_pcballoc(so, &nspcb); 86821496Ssklower if (error) 86921496Ssklower break; 87021496Ssklower error = soreserve(so, 2048, 2048); 87121496Ssklower if (error) 87221496Ssklower break; 87321496Ssklower nsp = sotonspcb(so); 87421496Ssklower { 87521496Ssklower struct mbuf *mm = m_getclr(M_DONTWAIT,MT_PCB); 87621496Ssklower 877*24330Ssklower if (mm == NULL) { 87821496Ssklower error = ENOBUFS; 87921496Ssklower break; 88021496Ssklower } 88121496Ssklower cb = mtod(mm, struct sppcb *); 88221496Ssklower cb->s_state = TCPS_LISTEN; 88321496Ssklower cb->s_snt = -1; 88421496Ssklower cb->s_q.si_next = cb->s_q.si_prev = &cb->s_q; 88521496Ssklower cb->s_nspcb = nsp; 88621496Ssklower nsp->nsp_pcb = (caddr_t) cb; 88721496Ssklower } 88821496Ssklower break; 88921496Ssklower 89021496Ssklower case PRU_DETACH: 89121496Ssklower if (nsp == NULL) { 89221496Ssklower error = ENOTCONN; 89321496Ssklower break; 89421496Ssklower } 89521496Ssklower if (cb->s_state > TCPS_LISTEN) 89621496Ssklower cb = spp_disconnect(cb); 89721496Ssklower else 89821496Ssklower cb = spp_close(cb); 89921496Ssklower break; 90021496Ssklower 90121496Ssklower case PRU_BIND: 90221496Ssklower error = ns_pcbbind(nsp, nam); 90321496Ssklower break; 90421496Ssklower 90521496Ssklower case PRU_LISTEN: 90621496Ssklower if (nsp->nsp_lport == 0) 90721496Ssklower error = ns_pcbbind(nsp, (struct mbuf *)0); 90821496Ssklower if (error == 0) 90921496Ssklower cb->s_state = TCPS_LISTEN; 91021496Ssklower break; 91121496Ssklower 91221496Ssklower /* 91321496Ssklower * Initiate connection to peer. 91421496Ssklower * Enter SYN_SENT state, and mark socket as connecting. 91521496Ssklower * Start keep-alive timer, setup prototype header, 91621496Ssklower * Send initial system packet requesting connection. 91721496Ssklower */ 91821496Ssklower case PRU_CONNECT: 91921496Ssklower if (nsp->nsp_lport == 0) { 92021496Ssklower error = ns_pcbbind(nsp, (struct mbuf *)0); 92121496Ssklower if (error) 92221496Ssklower break; 92321496Ssklower } 92421496Ssklower error = ns_pcbconnect(nsp, nam); 92521496Ssklower if (error) 92621496Ssklower break; 92721496Ssklower soisconnecting(so); 92821496Ssklower cb->s_state = TCPS_SYN_SENT; 92921496Ssklower cb->s_did = 0; 93021496Ssklower spp_template(cb); 93121496Ssklower cb->s_timer[TCPT_KEEP] = TCPTV_KEEP; 93221496Ssklower cb->s_force = 1 + TCPTV_KEEP; 93321496Ssklower /* 93421496Ssklower * Other party is required to respond to 93521496Ssklower * the port I send from, but he is not 93621496Ssklower * required to answer from where I am sending to, 93721496Ssklower * so allow wildcarding. 93821496Ssklower * original port I am sending to is still saved in 93921496Ssklower * cb->s_dport. 94021496Ssklower */ 94121496Ssklower nsp->nsp_fport = 0; 94221496Ssklower error = spp_output(cb, (struct mbuf *) 0); 94321496Ssklower break; 94421496Ssklower 94521496Ssklower case PRU_CONNECT2: 94621496Ssklower error = EOPNOTSUPP; 94721496Ssklower break; 94821496Ssklower 94921496Ssklower /* 95021496Ssklower * We may decide later to implement connection closing 95121496Ssklower * handshaking at the spp level optionally. 95221496Ssklower * here is the hook to do it: 95321496Ssklower */ 95421496Ssklower case PRU_DISCONNECT: 95521496Ssklower cb = spp_disconnect(cb); 95621496Ssklower break; 95721496Ssklower 95821496Ssklower /* 95921496Ssklower * Accept a connection. Essentially all the work is 96021496Ssklower * done at higher levels; just return the address 96121496Ssklower * of the peer, storing through addr. 96221496Ssklower */ 96321496Ssklower case PRU_ACCEPT: { 96421496Ssklower struct sockaddr_ns *sns = mtod(nam, struct sockaddr_ns *); 96521496Ssklower 96621496Ssklower nam->m_len = sizeof (struct sockaddr_ns); 96721496Ssklower sns->sns_family = AF_NS; 96821496Ssklower sns->sns_addr = nsp->nsp_faddr; 96921496Ssklower break; 97021496Ssklower } 97121496Ssklower 97221496Ssklower case PRU_SHUTDOWN: 97321496Ssklower socantsendmore(so); 97421496Ssklower cb = spp_usrclosed(cb); 97521496Ssklower if (cb) 97621496Ssklower error = spp_output(cb, (struct mbuf *) 0); 97721496Ssklower break; 97821496Ssklower 97921496Ssklower /* 98021496Ssklower * After a receive, possibly send acknowledgment 98121496Ssklower * updating allocation. 98221496Ssklower */ 98321496Ssklower case PRU_RCVD: 98421496Ssklower (void) spp_output(cb, (struct mbuf *) 0); 98521496Ssklower break; 98621496Ssklower 98721496Ssklower case PRU_SEND: 98821496Ssklower error = spp_output(cb, m); 98921496Ssklower m = NULL; 99021496Ssklower break; 99121496Ssklower 99221496Ssklower case PRU_ABORT: 99324225Ssklower (void) spp_drop(cb, ECONNABORTED); 99421496Ssklower break; 99521496Ssklower 99621496Ssklower case PRU_SENSE: 99721496Ssklower case PRU_CONTROL: 99821496Ssklower m = NULL; 99921496Ssklower error = EOPNOTSUPP; 100021496Ssklower break; 100121496Ssklower 100221496Ssklower case PRU_RCVOOB: 100321496Ssklower if ( ! (cb->s_oobflags & SF_IOOB) ) { 100421496Ssklower error = EWOULDBLOCK; 100521496Ssklower break; 100621496Ssklower } 100721496Ssklower m->m_len = 1; 100821496Ssklower *mtod(m, caddr_t) = cb->s_iobc; 100921496Ssklower cb->s_oobflags &= ~ SF_IOOB; 101021496Ssklower break; 101121496Ssklower 101221496Ssklower case PRU_SENDOOB: 101321496Ssklower if (sbspace(&so->so_snd) < -512) { 101421496Ssklower m_freem(m); 101521496Ssklower error = ENOBUFS; 101621496Ssklower break; 101721496Ssklower } 101821496Ssklower cb->s_oobflags |= SF_SOOB; 101921496Ssklower error = spp_output(cb, m); 102021496Ssklower m = NULL; 102121496Ssklower cb->s_oobflags &= ~SF_SOOB; 102221496Ssklower break; 102321496Ssklower 102421496Ssklower case PRU_SOCKADDR: 102521496Ssklower ns_setsockaddr(nsp, nam); 102621496Ssklower break; 102721496Ssklower 102821496Ssklower case PRU_PEERADDR: 102921496Ssklower ns_setpeeraddr(nsp, nam); 103021496Ssklower break; 103121496Ssklower 103221496Ssklower case PRU_SLOWTIMO: 103321496Ssklower cb = spp_timers(cb, (int)nam); 103421496Ssklower break; 103521496Ssklower 103621496Ssklower case PRU_FASTTIMO: 103721496Ssklower case PRU_PROTORCV: 103821496Ssklower case PRU_PROTOSEND: 103921496Ssklower error = EOPNOTSUPP; 104021496Ssklower break; 104121496Ssklower 104221496Ssklower default: 104321496Ssklower panic("sp_usrreq"); 104421496Ssklower } 104521496Ssklower if (cb && (so->so_options & SO_DEBUG || traceallspps)) 104624225Ssklower spp_trace(SA_USER, (u_char)ostate, cb, (struct spidp *)0, req); 104721496Ssklower release: 104821496Ssklower if (m != NULL) 104921496Ssklower m_freem(m); 105021496Ssklower splx(s); 105121496Ssklower return (error); 105221496Ssklower } 105321496Ssklower 105421496Ssklower spp_usrreq_sp(so, req, m, nam, rights) 105521496Ssklower struct socket *so; 105621496Ssklower int req; 105721496Ssklower struct mbuf *m, *nam, *rights; 105821496Ssklower { 105921496Ssklower int error = spp_usrreq(so, req, m, nam, rights); 106021496Ssklower 1061*24330Ssklower if (req == PRU_ATTACH && error == 0) { 106221496Ssklower struct nspcb *nsp = sotonspcb(so); 106321496Ssklower ((struct sppcb *)nsp->nsp_pcb)->s_flags |= 106421496Ssklower (SF_HI | SF_HO | SF_PI); 106521496Ssklower } 106623515Ssklower return (error); 106721496Ssklower } 106821496Ssklower 106921496Ssklower /* 107021496Ssklower * Create template to be used to send spp packets on a connection. 107121496Ssklower * Called after host entry created, fills 107221496Ssklower * in a skeletal spp header (choosing connection id), 107321496Ssklower * minimizing the amount of work necessary when the connection is used. 107421496Ssklower */ 107521496Ssklower spp_template(cb) 107621496Ssklower struct sppcb *cb; 107721496Ssklower { 107821496Ssklower register struct nspcb *nsp = cb->s_nspcb; 107921496Ssklower register struct spidp *n = &(cb->s_shdr); 108021496Ssklower 108121496Ssklower cb->s_mtu = 1024; 108221496Ssklower n->si_pt = NSPROTO_SPP; 108321496Ssklower n->si_sna = nsp->nsp_laddr; 108421496Ssklower n->si_dna = nsp->nsp_faddr; 108521496Ssklower n->si_sid = htons(spp_iss); 108621496Ssklower spp_iss += SPP_ISSINCR/2; 108721496Ssklower n->si_alo = 1; 108821496Ssklower } 108921496Ssklower 109021496Ssklower /* 109121496Ssklower * Close a SPIP control block: 109221496Ssklower * discard spp control block itself 109321496Ssklower * discard ns protocol control block 109421496Ssklower * wake up any sleepers 109521496Ssklower */ 109621496Ssklower struct sppcb * 109721496Ssklower spp_close(cb) 109821496Ssklower register struct sppcb *cb; 109921496Ssklower { 110021496Ssklower register struct spidp_q *s; 110121496Ssklower struct nspcb *nsp = cb->s_nspcb; 110221496Ssklower struct socket *so = nsp->nsp_socket; 110321496Ssklower register struct mbuf *m; 110421496Ssklower 110521496Ssklower s = cb->s_q.si_next; 110621496Ssklower while (s != &(cb->s_q)) { 110721496Ssklower s = s->si_next; 110821496Ssklower m = dtom(s->si_prev); 110921496Ssklower remque(s->si_prev); 111021496Ssklower m_freem(m); 111121496Ssklower } 111221496Ssklower (void) m_free(dtom(cb)); 111321496Ssklower nsp->nsp_pcb = 0; 111421496Ssklower soisdisconnected(so); 111521496Ssklower ns_pcbdetach(nsp); 111623515Ssklower return ((struct sppcb *)0); 111721496Ssklower } 111821496Ssklower /* 111921496Ssklower * Someday we may do level 3 handshaking 112021496Ssklower * to close a connection or send a xerox style error. 112121496Ssklower * For now, just close. 112221496Ssklower */ 112321496Ssklower struct sppcb * 112421496Ssklower spp_usrclosed(cb) 112521496Ssklower register struct sppcb *cb; 112621496Ssklower { 112723515Ssklower return (spp_close(cb)); 112821496Ssklower } 112921496Ssklower struct sppcb * 113021496Ssklower spp_disconnect(cb) 113121496Ssklower register struct sppcb *cb; 113221496Ssklower { 113323515Ssklower return (spp_close(cb)); 113421496Ssklower } 113521496Ssklower /* 113621496Ssklower * Drop connection, reporting 113721496Ssklower * the specified error. 113821496Ssklower */ 113921496Ssklower struct sppcb * 114021496Ssklower spp_drop(cb, errno) 114121496Ssklower register struct sppcb *cb; 114221496Ssklower int errno; 114321496Ssklower { 114421496Ssklower struct socket *so = cb->s_nspcb->nsp_socket; 114521496Ssklower 114621496Ssklower /* 114721496Ssklower * someday, in the xerox world 114821496Ssklower * we will generate error protocol packets 114921496Ssklower * announcing that the socket has gone away. 115021496Ssklower */ 115121496Ssklower /*if (TCPS_HAVERCVDSYN(tp->t_state)) { 115221496Ssklower tp->t_state = TCPS_CLOSED; 115321496Ssklower (void) tcp_output(tp); 115421496Ssklower }*/ 115521496Ssklower so->so_error = errno; 115621496Ssklower return (spp_close(cb)); 115721496Ssklower } 115821496Ssklower 115921496Ssklower spp_abort(nsp) 116021496Ssklower struct nspcb *nsp; 116121496Ssklower { 116221496Ssklower 116324225Ssklower (void) spp_close((struct sppcb *)nsp->nsp_pcb); 116421496Ssklower } 116521496Ssklower 116621496Ssklower spp_setpersist(cb) 116721496Ssklower register struct sppcb *cb; 116821496Ssklower { 116921496Ssklower 117021496Ssklower /*if (cb->s_timer[TCPT_REXMT]) 117121496Ssklower panic("spp_output REXMT");*/ 117221496Ssklower /* 117321496Ssklower * Start/restart persistance timer. 117421496Ssklower */ 117521496Ssklower TCPT_RANGESET(cb->s_timer[TCPT_PERSIST], 117621496Ssklower ((int)(tcp_beta * cb->s_srtt)) << cb->s_rxtshift, 117721496Ssklower TCPTV_PERSMIN, TCPTV_MAX); 117821496Ssklower cb->s_rxtshift++; 117921496Ssklower if (cb->s_rxtshift >= TCP_MAXRXTSHIFT) 118021496Ssklower cb->s_rxtshift = 0; 118121496Ssklower } 118221496Ssklower /* 118321496Ssklower * Fast timeout routine for processing delayed acks 118421496Ssklower */ 118521496Ssklower int spp_ftcnt; 118621496Ssklower spp_fasttimo() 118721496Ssklower { 118821496Ssklower register struct nspcb *nsp; 118921496Ssklower register struct sppcb *cb; 119021496Ssklower int s = splnet(); 119121496Ssklower 119221496Ssklower nsp = nspcb.nsp_next; 119321496Ssklower spp_ftcnt++; 119421496Ssklower if (nsp) 119521496Ssklower for (; nsp != &nspcb; nsp = nsp->nsp_next) 119621496Ssklower if ((cb = (struct sppcb *)nsp->nsp_pcb) && 119721496Ssklower (cb->s_flags & SF_DELACK)) { 119821496Ssklower cb->s_flags &= ~SF_DELACK; 119921496Ssklower cb->s_flags |= SF_AK; 120021496Ssklower (void) spp_output(cb, (struct mbuf *) 0); 120121496Ssklower } 120221496Ssklower splx(s); 120321496Ssklower } 120421496Ssklower 120521496Ssklower /* 120621496Ssklower * spp protocol timeout routine called every 500 ms. 120721496Ssklower * Updates the timers in all active pcb's and 120821496Ssklower * causes finite state machine actions if timers expire. 120921496Ssklower */ 121021496Ssklower spp_slowtimo() 121121496Ssklower { 121221496Ssklower register struct nspcb *ip, *ipnxt; 121321496Ssklower register struct sppcb *cb; 121421496Ssklower int s = splnet(); 121521496Ssklower register int i; 121621496Ssklower 121721496Ssklower /* 121821496Ssklower * Search through tcb's and update active timers. 121921496Ssklower */ 122021496Ssklower ip = nspcb.nsp_next; 122121496Ssklower if (ip == 0) { 122221496Ssklower splx(s); 122321496Ssklower return; 122421496Ssklower } 122521496Ssklower while (ip != &nspcb) { 122621496Ssklower cb = nstosppcb(ip); 122721496Ssklower ipnxt = ip->nsp_next; 122821496Ssklower if (cb == 0) 122921496Ssklower goto tpgone; 123021496Ssklower for (i = 0; i < TCPT_NTIMERS; i++) { 123121496Ssklower if (cb->s_timer[i] && --cb->s_timer[i] == 0) { 123221496Ssklower (void) spp_usrreq(cb->s_nspcb->nsp_socket, 123321496Ssklower PRU_SLOWTIMO, (struct mbuf *)0, 123421496Ssklower (struct mbuf *)i, (struct mbuf *)0); 123521496Ssklower if (ipnxt->nsp_prev != ip) 123621496Ssklower goto tpgone; 123721496Ssklower } 123821496Ssklower } 123921496Ssklower cb->s_idle++; 124021496Ssklower if (cb->s_rtt) 124121496Ssklower cb->s_rtt++; 124221496Ssklower tpgone: 124321496Ssklower ip = ipnxt; 124421496Ssklower } 124521496Ssklower spp_iss += SPP_ISSINCR/PR_SLOWHZ; /* increment iss */ 124621496Ssklower splx(s); 124721496Ssklower } 124821496Ssklower 124921496Ssklower float spp_backoff[TCP_MAXRXTSHIFT] = 125021496Ssklower { 1.0, 1.2, 1.4, 1.7, 2.0, 3.0, 5.0, 8.0, 16.0, 32.0 }; 125121496Ssklower extern int tcpexprexmtbackoff; 125221496Ssklower /* 125321496Ssklower * TCP timer processing. 125421496Ssklower */ 125521496Ssklower struct sppcb * 125621496Ssklower spp_timers(cb, timer) 125721496Ssklower register struct sppcb *cb; 125821496Ssklower int timer; 125921496Ssklower { 126021496Ssklower 126121496Ssklower cb->s_force = 1 + timer; 126221496Ssklower switch (timer) { 126321496Ssklower 126421496Ssklower /* 126521496Ssklower * 2 MSL timeout in shutdown went off. Delete connection 126621496Ssklower * control block. 126721496Ssklower */ 126821496Ssklower case TCPT_2MSL: 126921496Ssklower cb = spp_close(cb); 127021496Ssklower break; 127121496Ssklower 127221496Ssklower /* 127321496Ssklower * Retransmission timer went off. Message has not 127421496Ssklower * been acked within retransmit interval. Back off 127521496Ssklower * to a longer retransmit interval and retransmit all 127621496Ssklower * unacknowledged messages in the window. 127721496Ssklower */ 127821496Ssklower case TCPT_REXMT: 127921496Ssklower cb->s_rxtshift++; 128021496Ssklower if (cb->s_rxtshift > TCP_MAXRXTSHIFT) { 128121496Ssklower cb = spp_drop(cb, ETIMEDOUT); 128221496Ssklower break; 128321496Ssklower } 128421496Ssklower (void) spp_output(cb, (struct mbuf *) 0); 128521496Ssklower TCPT_RANGESET(cb->s_timer[TCPT_REXMT], 128621496Ssklower (int)cb->s_srtt, TCPTV_MIN, TCPTV_MAX); 128721496Ssklower if (tcpexprexmtbackoff) { 128821496Ssklower TCPT_RANGESET(cb->s_timer[TCPT_REXMT], 128921496Ssklower cb->s_timer[TCPT_REXMT] << cb->s_rxtshift, 129021496Ssklower TCPTV_MIN, TCPTV_MAX); 129121496Ssklower } else { 129221496Ssklower TCPT_RANGESET(cb->s_timer[TCPT_REXMT], 129321496Ssklower cb->s_timer[TCPT_REXMT] * 129421496Ssklower spp_backoff[cb->s_rxtshift - 1], 129521496Ssklower TCPTV_MIN, TCPTV_MAX); 129621496Ssklower } 129721496Ssklower break; 129821496Ssklower 129921496Ssklower /* 130021496Ssklower * Persistance timer into zero window. 130121496Ssklower * Force a probe to be sent. 130221496Ssklower */ 130321496Ssklower case TCPT_PERSIST: 130421496Ssklower (void) spp_output(cb, (struct mbuf *) 0); 130521496Ssklower spp_setpersist(cb); 130621496Ssklower break; 130721496Ssklower 130821496Ssklower /* 130921496Ssklower * Keep-alive timer went off; send something 131021496Ssklower * or drop connection if idle for too long. 131121496Ssklower */ 131221496Ssklower case TCPT_KEEP: 131321496Ssklower if (cb->s_state < TCPS_ESTABLISHED) 131421496Ssklower goto dropit; 131521496Ssklower if (cb->s_nspcb->nsp_socket->so_options & SO_KEEPALIVE) { 131621496Ssklower if (cb->s_idle >= TCPTV_MAXIDLE) 131721496Ssklower goto dropit; 131821496Ssklower (void) spp_output(cb, (struct mbuf *) 0); 131921496Ssklower } else 132021496Ssklower cb->s_idle = 0; 132121496Ssklower cb->s_timer[TCPT_KEEP] = TCPTV_KEEP; 132221496Ssklower break; 132321496Ssklower dropit: 132421496Ssklower cb = spp_drop(cb, ETIMEDOUT); 132521496Ssklower break; 132621496Ssklower } 132721496Ssklower return (cb); 132821496Ssklower } 1329