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*24732Ssklower * @(#)spp_usrreq.c 6.12 (Berkeley) 09/13/85 723215Smckusick */ 821496Ssklower 921496Ssklower #include "param.h" 1021496Ssklower #include "dir.h" 1121496Ssklower #include "user.h" 1221496Ssklower #include "mbuf.h" 1321496Ssklower #include "protosw.h" 1421496Ssklower #include "socket.h" 1521496Ssklower #include "socketvar.h" 1621496Ssklower #include "errno.h" 1721496Ssklower 1821496Ssklower #include "../net/if.h" 1921496Ssklower #include "../net/route.h" 2021496Ssklower #include "../netinet/tcp_fsm.h" 2121496Ssklower #include "../netinet/tcp_timer.h" 2221496Ssklower 2321496Ssklower #include "ns.h" 2421496Ssklower #include "ns_pcb.h" 2521496Ssklower #include "idp.h" 2621496Ssklower #include "idp_var.h" 2721496Ssklower #include "ns_error.h" 2821496Ssklower #include "sp.h" 2921496Ssklower #include "spidp.h" 3021496Ssklower #include "spp_var.h" 3121496Ssklower #include "spp_debug.h" 3221496Ssklower 3321496Ssklower /* 3421496Ssklower * SP protocol implementation. 3521496Ssklower */ 3621496Ssklower spp_init() 3721496Ssklower { 3821496Ssklower 3921496Ssklower spp_iss = 1; /* WRONG !! should fish it out of TODR */ 4021496Ssklower } 4121496Ssklower struct spidp spp_savesi; 4221496Ssklower int traceallspps = 0; 4321496Ssklower extern int sppconsdebug; 4424615Ssklower int spp_hardnosed; 4521496Ssklower 4624615Ssklower /*ARGSUSED*/ 4724615Ssklower spp_input(m, nsp, ifp) 4821496Ssklower register struct mbuf *m; 4924047Ssklower register struct nspcb *nsp; 5024615Ssklower struct ifnet *ifp; 5121496Ssklower { 5221496Ssklower register struct sppcb *cb; 5321496Ssklower register struct spidp *si = mtod(m, struct spidp *); 5421496Ssklower register struct socket *so; 5524225Ssklower short ostate; 5621496Ssklower int dropsocket = 0; 5721496Ssklower 5821496Ssklower 5924330Ssklower if (nsp == 0) { 6024047Ssklower panic("No nspcb in spp_input\n"); 6123979Ssklower return; 6223979Ssklower } 6321496Ssklower 6421496Ssklower cb = nstosppcb(nsp); 6521496Ssklower if (cb == 0) goto bad; 6621496Ssklower 6724047Ssklower if (m->m_len < sizeof(*si)) { 6824330Ssklower if ((m = m_pullup(m, sizeof(*si))) == 0) { 6924047Ssklower spp_istat.hdrops++; 7024047Ssklower return; 7124047Ssklower } 7224047Ssklower si = mtod(m, struct spidp *); 7324047Ssklower } 7421496Ssklower si->si_seq = ntohs(si->si_seq); 7521496Ssklower si->si_ack = ntohs(si->si_ack); 7621496Ssklower si->si_alo = ntohs(si->si_alo); 7721496Ssklower 7821496Ssklower so = nsp->nsp_socket; 7921496Ssklower if (so->so_options & SO_DEBUG || traceallspps) { 8021496Ssklower ostate = cb->s_state; 8121496Ssklower spp_savesi = *si; 8221496Ssklower } 8321496Ssklower if (so->so_options & SO_ACCEPTCONN) { 8421496Ssklower so = sonewconn(so); 8521496Ssklower if (so == 0) { 8621496Ssklower spp_istat.nonucn++; 8721496Ssklower goto drop; 8821496Ssklower } 8921496Ssklower /* 9021496Ssklower * This is ugly, but .... 9121496Ssklower * 9221496Ssklower * Mark socket as temporary until we're 9321496Ssklower * committed to keeping it. The code at 9421496Ssklower * ``drop'' and ``dropwithreset'' check the 9521496Ssklower * flag dropsocket to see if the temporary 9621496Ssklower * socket created here should be discarded. 9721496Ssklower * We mark the socket as discardable until 9821496Ssklower * we're committed to it below in TCPS_LISTEN. 9921496Ssklower */ 10021496Ssklower dropsocket++; 10121496Ssklower nsp = (struct nspcb *)so->so_pcb; 10221496Ssklower nsp->nsp_laddr = si->si_dna; 10321496Ssklower cb = nstosppcb(nsp); 10421496Ssklower cb->s_state = TCPS_LISTEN; 10521496Ssklower } 10621496Ssklower 10721496Ssklower /* 10821496Ssklower * Packet received on connection. 10921496Ssklower * reset idle time and keep-alive timer; 11021496Ssklower */ 11121496Ssklower cb->s_idle = 0; 11221496Ssklower cb->s_timer[TCPT_KEEP] = TCPTV_KEEP; 11321496Ssklower 11421496Ssklower switch (cb->s_state) { 11523515Ssklower 11621496Ssklower case TCPS_LISTEN:{ 11721496Ssklower struct mbuf *am; 11821496Ssklower register struct sockaddr_ns *sns; 11921496Ssklower struct ns_addr laddr; 12021496Ssklower 12121496Ssklower /* 12221496Ssklower * If somebody here was carying on a conversation 12321496Ssklower * and went away, and his pen pal thinks he can 12421496Ssklower * still talk, we get the misdirected packet. 12521496Ssklower */ 12621496Ssklower if (spp_hardnosed && (si->si_did != 0 || si->si_seq != 0)) { 12721496Ssklower spp_istat.gonawy++; 12821496Ssklower goto dropwithreset; 12921496Ssklower } 13021496Ssklower am = m_get(M_DONTWAIT, MT_SONAME); 13121496Ssklower if (am == NULL) 13221496Ssklower goto drop; 13321496Ssklower am->m_len = sizeof (struct sockaddr_ns); 13421496Ssklower sns = mtod(am, struct sockaddr_ns *); 13521496Ssklower sns->sns_family = AF_NS; 13621496Ssklower sns->sns_addr = si->si_sna; 13721496Ssklower laddr = nsp->nsp_laddr; 13821496Ssklower if (ns_nullhost(laddr)) 13921496Ssklower nsp->nsp_laddr = si->si_dna; 14021496Ssklower if (ns_pcbconnect(nsp, am)) { 14121496Ssklower nsp->nsp_laddr = laddr; 14221496Ssklower (void) m_free(am); 14321496Ssklower spp_istat.noconn++; 14421496Ssklower goto drop; 14521496Ssklower } 14621496Ssklower (void) m_free(am); 14721496Ssklower spp_template(cb); 148*24732Ssklower dropsocket = 0; /* committed to socket */ 14921496Ssklower cb->s_did = si->si_sid; 15021496Ssklower cb->s_rack = si->si_ack; 15121496Ssklower cb->s_ralo = si->si_alo; 152*24732Ssklower #define THREEWAYSHAKE 153*24732Ssklower #ifdef THREEWAYSHAKE 154*24732Ssklower cb->s_state = TCPS_SYN_RECEIVED; 155*24732Ssklower cb->s_force = 1 + TCPT_REXMT; 156*24732Ssklower cb->s_timer[TCPT_REXMT] = 2 * TCPTV_MIN; 15721496Ssklower } 15821496Ssklower break; 159*24732Ssklower /* 160*24732Ssklower * This state means that we have heard a response 161*24732Ssklower * to our acceptance of their connection 162*24732Ssklower * It is probably logically unnecessary in this 163*24732Ssklower * implementation. 164*24732Ssklower */ 165*24732Ssklower case TCPS_SYN_RECEIVED: 166*24732Ssklower if (si->si_did!=cb->s_sid) { 167*24732Ssklower spp_istat.wrncon++; 168*24732Ssklower goto drop; 169*24732Ssklower } 170*24732Ssklower #endif 171*24732Ssklower nsp->nsp_fport = si->si_sport; 172*24732Ssklower cb->s_timer[TCPT_REXMT] = 0; 173*24732Ssklower cb->s_timer[TCPT_KEEP] = TCPTV_KEEP; 174*24732Ssklower soisconnected(so); 175*24732Ssklower cb->s_state = TCPS_ESTABLISHED; 176*24732Ssklower break; 17721496Ssklower 17821496Ssklower /* 17921496Ssklower * This state means that we have gotten a response 18021496Ssklower * to our attempt to establish a connection. 18123979Ssklower * We fill in the data from the other side, 18223979Ssklower * telling us which port to respond to, instead of the well- 18323979Ssklower * known one we might have sent to in the first place. 18421496Ssklower * We also require that this is a response to our 18523979Ssklower * connection id. 18621496Ssklower */ 18721496Ssklower case TCPS_SYN_SENT: 18821496Ssklower if (si->si_did!=cb->s_sid) { 18921496Ssklower spp_istat.notme++; 19021496Ssklower goto drop; 19121496Ssklower } 19221496Ssklower cb->s_did = si->si_sid; 19321496Ssklower cb->s_rack = si->si_ack; 19421496Ssklower cb->s_ralo = si->si_alo; 19521496Ssklower cb->s_dport = nsp->nsp_fport = si->si_sport; 19621496Ssklower cb->s_timer[TCPT_REXMT] = 0; 19721496Ssklower cb->s_flags |= SF_AK; 19821496Ssklower soisconnected(so); 19921496Ssklower cb->s_state = TCPS_ESTABLISHED; 20021496Ssklower } 20121496Ssklower if (so->so_options & SO_DEBUG || traceallspps) 20224225Ssklower spp_trace(SA_INPUT, (u_char)ostate, cb, &spp_savesi, 0); 20321496Ssklower 20421496Ssklower m->m_len -= sizeof (struct idp); 20521496Ssklower m->m_off += sizeof (struct idp); 20621496Ssklower 20721496Ssklower if (spp_reass(cb,si)) { 20821496Ssklower goto drop; 20921496Ssklower } 21024225Ssklower (void) spp_output(cb,(struct mbuf *)0); 21121496Ssklower return; 21221496Ssklower 21321496Ssklower dropwithreset: 21421496Ssklower if (dropsocket) 21521496Ssklower (void) soabort(so); 21621496Ssklower si->si_seq = ntohs(si->si_seq); 21721496Ssklower si->si_ack = ntohs(si->si_ack); 21821496Ssklower si->si_alo = ntohs(si->si_alo); 21921496Ssklower ns_error(dtom(si), NS_ERR_NOSOCK, 0); 22021496Ssklower if (cb->s_nspcb->nsp_socket->so_options & SO_DEBUG || traceallspps) 22124225Ssklower spp_trace(SA_DROP, (u_char)ostate, cb, &spp_savesi, 0); 22221496Ssklower return; 22321496Ssklower 22421496Ssklower drop: 22521496Ssklower bad: 22624330Ssklower if (cb == 0 || cb->s_nspcb->nsp_socket->so_options & SO_DEBUG || traceallspps) 22724225Ssklower spp_trace(SA_DROP, (u_char)ostate, cb, &spp_savesi, 0); 22821496Ssklower m_freem(m); 22921496Ssklower } 23021496Ssklower 23121496Ssklower /* 23221496Ssklower * This is structurally similar to the tcp reassembly routine 23321496Ssklower * but its function is somewhat different: It merely queues 23421496Ssklower * packets up, and suppresses duplicates. 23521496Ssklower */ 23621496Ssklower spp_reass(cb,si) 23721496Ssklower register struct sppcb *cb; 23821496Ssklower register struct spidp *si; 23921496Ssklower { 24021496Ssklower register struct spidp_q *q; 24121496Ssklower register struct mbuf *m; 24221496Ssklower struct socket *so = cb->s_nspcb->nsp_socket; 24321496Ssklower struct sockbuf *sb = & (so->so_rcv); 24421496Ssklower char packetp = cb->s_flags & SF_HI; 24521496Ssklower char wakeup = 0; 24621496Ssklower 24721496Ssklower 24824330Ssklower if (si == SI(0)) 24921496Ssklower goto present; 25021496Ssklower /* 25121496Ssklower * Update our news from them. 25221496Ssklower */ 25321496Ssklower if (si->si_cc & SP_SA) 25421496Ssklower cb->s_flags |= SF_DELACK; 25521496Ssklower if (SSEQ_GT(si->si_ack,cb->s_rack)) { 25621496Ssklower cb->s_rack = si->si_ack; 25721496Ssklower cb->s_timer[TCPT_REXMT] = 0; 25821496Ssklower 25921496Ssklower /* 26021496Ssklower * If transmit timer is running and timed sequence 26121496Ssklower * number was acked, update smoothed round trip time. 26221496Ssklower */ 26321496Ssklower if (cb->s_rtt && SSEQ_GT(si->si_ack, cb->s_rtseq)) { 26421496Ssklower if (cb->s_srtt == 0) 26521496Ssklower cb->s_srtt = cb->s_rtt; 26621496Ssklower else 26721496Ssklower cb->s_srtt = 26821496Ssklower tcp_alpha * cb->s_srtt + 26921496Ssklower (1 - tcp_alpha) * cb->s_rtt; 27021496Ssklower cb->s_rtt = 0; 27121496Ssklower } 27221496Ssklower } 27321496Ssklower if (SSEQ_GT(si->si_alo,cb->s_ralo)) { 27421496Ssklower cb->s_ralo = si->si_alo; 27521496Ssklower cb->s_timer[TCPT_PERSIST] = 0; 27621496Ssklower } 27721496Ssklower /* 27821496Ssklower * If this is a system packet, we don't need to 27921496Ssklower * queue it up, and won't update acknowledge # 28021496Ssklower */ 28123561Ssklower if (si->si_cc & SP_SP) { 28223561Ssklower m_freem(dtom(si)); 28323515Ssklower return (0); 28423561Ssklower } 28521496Ssklower 28621496Ssklower /* 28721496Ssklower * If this packet number has a sequence number less 28821496Ssklower * than that of the first packet not yet seen coming 28921496Ssklower * from them, this must be a duplicate, so drop. 29021496Ssklower */ 29123979Ssklower if (SSEQ_LT(si->si_seq,cb->s_ack)) { 29223979Ssklower spp_istat.bdreas++; 29324330Ssklower if (si->si_seq == cb->s_ack-1) 29423979Ssklower spp_istat.lstdup++; 29523515Ssklower return (1); 29623979Ssklower } 29721496Ssklower /* 29821496Ssklower * If this packet number is higher than that which 29921496Ssklower * we have allocated refuse it, unless urgent 30021496Ssklower */ 30121496Ssklower if (SSEQ_GT(si->si_seq,cb->s_alo) && (!(si->si_cc & SP_OB))) { 30223979Ssklower spp_istat.notyet++; 30323515Ssklower return (1); 30421496Ssklower } 30521496Ssklower /* 30621496Ssklower * If this packet is urgent, inform process 30721496Ssklower */ 30821496Ssklower if (si->si_cc & SP_OB) { 30921496Ssklower cb->s_iobc = ((char *)si)[1 + sizeof(*si)]; 31021496Ssklower sohasoutofband(so); 31121496Ssklower } 31221496Ssklower 31321496Ssklower /* 31421496Ssklower * Loop through all packets queued up to insert in 31521496Ssklower * appropriate sequence. 31621496Ssklower */ 31721496Ssklower 31821496Ssklower for (q = cb->s_q.si_next; q!=&cb->s_q; q = q->si_next) { 31924330Ssklower if (si->si_seq == SI(q)->si_seq) return (1); /*duplicate */ 32021496Ssklower if (SSEQ_LT(si->si_seq,SI(q)->si_seq)) break; 32121496Ssklower } 32221496Ssklower insque(si,q->si_prev); 32321496Ssklower 32421496Ssklower present: 32521496Ssklower #define SPINC sizeof(struct sphdr) 32621496Ssklower /* 32721496Ssklower * Loop through all packets queued up to update acknowledge 32821496Ssklower * number, and present all acknowledged data to user; 32921496Ssklower * If in packet interface mode, show packet headers. 33021496Ssklower */ 33121496Ssklower for (q = cb->s_q.si_next; q!=&cb->s_q; q = q->si_next) { 33224330Ssklower if (SI(q)->si_seq == cb->s_ack) { 33321496Ssklower cb->s_ack++; 33421496Ssklower m = dtom(q); 33521496Ssklower if (SI(q)->si_cc & SP_OB) { 33621496Ssklower if (sb->sb_cc) 33721496Ssklower so->so_oobmark = sb->sb_cc; 33821496Ssklower else 33921496Ssklower so->so_state |= SS_RCVATMARK; 34021496Ssklower } 34121496Ssklower q = q->si_prev; 34221496Ssklower remque(q->si_next); 34321496Ssklower wakeup = 1; 34421496Ssklower if (packetp) { 34521496Ssklower sbappendrecord(sb,m); 34621496Ssklower } else { 34721496Ssklower cb->s_rhdr = *mtod(m, struct sphdr *); 34821496Ssklower m->m_off += SPINC; 34921496Ssklower m->m_len -= SPINC; 35021496Ssklower sbappend(sb,m); 35121496Ssklower } 35221496Ssklower } else 35321496Ssklower break; 35421496Ssklower } 35521496Ssklower if (wakeup) sorwakeup(so); 35623515Ssklower return (0); 35721496Ssklower } 35821496Ssklower 35921496Ssklower spp_ctlinput(cmd, arg) 36021496Ssklower int cmd; 36121496Ssklower caddr_t arg; 36221496Ssklower { 36321496Ssklower struct ns_addr *na; 36421496Ssklower extern u_char nsctlerrmap[]; 36521496Ssklower extern spp_abort(); 36624225Ssklower extern struct nspcb *idp_drop(); 36723979Ssklower struct ns_errp *errp; 36823979Ssklower struct nspcb *nsp; 36924615Ssklower struct sockaddr_ns *sns; 37021496Ssklower int type; 37121496Ssklower 37221496Ssklower if (cmd < 0 || cmd > PRC_NCMDS) 37321496Ssklower return; 37421496Ssklower type = NS_ERR_UNREACH_HOST; 37521496Ssklower 37621496Ssklower switch (cmd) { 37723515Ssklower 37821496Ssklower case PRC_ROUTEDEAD: 37921496Ssklower case PRC_QUENCH: 38021496Ssklower break; 38121496Ssklower 38221496Ssklower case PRC_IFDOWN: 38321496Ssklower case PRC_HOSTDEAD: 38421496Ssklower case PRC_HOSTUNREACH: 38524615Ssklower sns = (struct sockaddr_ns *)arg; 38624615Ssklower if (sns->sns_family != AF_NS) 38724615Ssklower return; 38824615Ssklower na = &sns->sns_addr; 38921496Ssklower break; 39021496Ssklower 39121496Ssklower default: 39223979Ssklower errp = (struct ns_errp *)arg; 39323979Ssklower na = &errp->ns_err_idp.idp_dna; 39423979Ssklower type = errp->ns_err_num; 39524225Ssklower type = ntohs((u_short)type); 39621496Ssklower } 39721496Ssklower switch (type) { 39823515Ssklower 39921496Ssklower case NS_ERR_UNREACH_HOST: 40023979Ssklower ns_pcbnotify(na, (int)nsctlerrmap[cmd], spp_abort, (long) 0); 40121496Ssklower break; 40223515Ssklower 40321496Ssklower case NS_ERR_TOO_BIG: 40423979Ssklower case NS_ERR_NOSOCK: 40523979Ssklower nsp = ns_pcblookup(na, errp->ns_err_idp.idp_sna.x_port, 40623979Ssklower NS_WILDCARD); 40723979Ssklower if (nsp) { 40823979Ssklower if(nsp->nsp_pcb) 40924225Ssklower (void) spp_drop((struct sppcb *)nsp->nsp_pcb, 41024225Ssklower (int)nsctlerrmap[cmd]); 41123979Ssklower else 41224225Ssklower (void) idp_drop(nsp, (int)nsctlerrmap[cmd]); 41323979Ssklower } 41421496Ssklower } 41521496Ssklower } 41621496Ssklower 41724225Ssklower #ifdef notdef 41821496Ssklower int 41921496Ssklower spp_fixmtu(nsp) 42021496Ssklower register struct nspcb *nsp; 42121496Ssklower { 42221496Ssklower register struct sppcb *cb = (struct sppcb *)(nsp->nsp_pcb); 42321496Ssklower register struct mbuf *m; 42421496Ssklower register struct spidp *si; 42521496Ssklower struct ns_errp *ep; 42621496Ssklower struct sockbuf *sb; 42721496Ssklower int badseq, len; 42821496Ssklower struct mbuf *firstbad, *m0; 42921496Ssklower 43021496Ssklower if (cb) { 43121496Ssklower /* 43221496Ssklower * The notification that we have sent 43321496Ssklower * too much is bad news -- we will 43421496Ssklower * have to go through queued up so far 43521496Ssklower * splitting ones which are too big and 43621496Ssklower * reassigning sequence numbers and checksums. 43721496Ssklower * we should then retransmit all packets from 43821496Ssklower * one above the offending packet to the last one 43921496Ssklower * we had sent (or our allocation) 44021496Ssklower * then the offending one so that the any queued 44121496Ssklower * data at our destination will be discarded. 44221496Ssklower */ 44321496Ssklower ep = (struct ns_errp *)nsp->nsp_notify_param; 44421496Ssklower sb = &nsp->nsp_socket->so_snd; 44521496Ssklower cb->s_mtu = ep->ns_err_param; 44621496Ssklower badseq = SI(&ep->ns_err_idp)->si_seq; 44721496Ssklower for (m = sb->sb_mb; m; m = m->m_act) { 44821496Ssklower si = mtod(m, struct spidp *); 44921496Ssklower if (si->si_seq == badseq) 45021496Ssklower break; 45121496Ssklower } 45224330Ssklower if (m == 0) return; 45321496Ssklower firstbad = m; 45421496Ssklower /*for (;;) {*/ 45521496Ssklower /* calculate length */ 45621496Ssklower for (m0 = m, len = 0; m ; m = m->m_next) 45721496Ssklower len += m->m_len; 45821496Ssklower if (len > cb->s_mtu) { 45921496Ssklower } 46021496Ssklower /* FINISH THIS 46121496Ssklower } */ 46221496Ssklower } 46321496Ssklower } 46424225Ssklower #endif 46521496Ssklower 46621496Ssklower int spp_output_cnt = 0; 46723979Ssklower 46821496Ssklower spp_output(cb, m0) 46921496Ssklower register struct sppcb *cb; 47021496Ssklower struct mbuf *m0; 47121496Ssklower { 47221496Ssklower struct socket *so = cb->s_nspcb->nsp_socket; 47321496Ssklower register struct mbuf *m; 47421496Ssklower register struct spidp *si = (struct spidp *) 0; 47521496Ssklower register struct sockbuf *sb = &(so->so_snd); 47621496Ssklower register int len = 0; 47724330Ssklower int error = 0; 47824330Ssklower u_short lookfor = 0; 47921496Ssklower struct mbuf *mprev; 48021496Ssklower extern int idpcksum; 48121496Ssklower 48224330Ssklower if (m0) { 48324615Ssklower int mtu = cb->s_mtu; 48424615Ssklower int datalen; 48524615Ssklower /* 48624615Ssklower * Make sure that packet isn't too big. 48724615Ssklower */ 48821496Ssklower for (m = m0; m ; m = m->m_next) { 48921496Ssklower mprev = m; 49021496Ssklower len += m->m_len; 49121496Ssklower } 49224615Ssklower datalen = (cb->s_flags & SF_HO) ? 49324615Ssklower len - sizeof (struct sphdr) : len; 49424615Ssklower if (datalen > mtu) { 49521496Ssklower if (cb->s_flags & SF_PI) { 49621496Ssklower m_freem(m0); 49723515Ssklower return (EMSGSIZE); 49821496Ssklower } else { 49921496Ssklower int off = 0; 50024615Ssklower int oldEM = cb->s_cc & SP_EM; 50124615Ssklower 50224615Ssklower cb->s_cc &= ~SP_EM; 50321496Ssklower while (len > mtu) { 50421496Ssklower m = m_copy(m0, off, mtu); 50524330Ssklower if (m == NULL) { 50624615Ssklower error = ENOBUFS; 50724615Ssklower goto bad_copy; 50823515Ssklower } 50921496Ssklower error = spp_output(cb, m); 51021496Ssklower if (error) { 51124615Ssklower bad_copy: 51224615Ssklower cb->s_cc |= oldEM; 51321496Ssklower m_freem(m0); 51424615Ssklower return(error); 51521496Ssklower } 51621496Ssklower m_adj(m0, mtu); 51721496Ssklower len -= mtu; 51821496Ssklower } 51924615Ssklower cb->s_cc |= oldEM; 52021496Ssklower } 52121496Ssklower } 52224330Ssklower /* 52324330Ssklower * Force length even, by adding a "garbage byte" if 52424330Ssklower * necessary. 52524330Ssklower */ 52621496Ssklower if (len & 1) { 52723979Ssklower m = mprev; 52824330Ssklower if (m->m_len + m->m_off < MMAXOFF) 52921496Ssklower m->m_len++; 53024330Ssklower else { 53121496Ssklower struct mbuf *m1 = m_get(M_DONTWAIT, MT_DATA); 53221496Ssklower 53321496Ssklower if (m1 == 0) { 53421496Ssklower m_freem(m0); 53521496Ssklower return (ENOBUFS); 53621496Ssklower } 53721496Ssklower m1->m_len = 1; 53821496Ssklower m1->m_off = MMAXOFF - 1; 53924330Ssklower m->m_next = m1; 54021496Ssklower } 54121496Ssklower } 54221496Ssklower m = m_get(M_DONTWAIT, MT_HEADER); 54321496Ssklower if (m == 0) { 54421496Ssklower m_freem(m0); 54523515Ssklower return (ENOBUFS); 54621496Ssklower } 54721496Ssklower /* 54821496Ssklower * Fill in mbuf with extended SP header 54921496Ssklower * and addresses and length put into network format. 55021496Ssklower */ 55121496Ssklower m->m_off = MMAXOFF - sizeof (struct spidp); 55221496Ssklower m->m_len = sizeof (struct spidp); 55321496Ssklower m->m_next = m0; 55421496Ssklower si = mtod(m, struct spidp *); 55521496Ssklower *si = cb->s_shdr; 55621496Ssklower if ((cb->s_flags & SF_PI) && (cb->s_flags & SF_HO)) { 55724330Ssklower register struct sphdr *sh; 55824330Ssklower if (m0->m_len < sizeof (*sh)) { 55924330Ssklower if((m0 = m_pullup(m0, sizeof(*sh))) == NULL) { 56024330Ssklower (void) m_free(m); 56124330Ssklower m_freem(m0); 56224330Ssklower return (EINVAL); 56324330Ssklower } 56424330Ssklower m->m_next = m0; 56524330Ssklower } 56624330Ssklower sh = mtod(m0, struct sphdr *); 56721496Ssklower si->si_dt = sh->sp_dt; 56821496Ssklower si->si_cc |= sh->sp_cc & SP_EM; 56921496Ssklower m0->m_len -= sizeof (*sh); 57021496Ssklower m0->m_off += sizeof (*sh); 57121496Ssklower len -= sizeof (*sh); 57221496Ssklower } 57321496Ssklower len += sizeof(*si); 57423979Ssklower if (cb->s_oobflags & SF_SOOB) { 57523979Ssklower /* 57623979Ssklower * Per jqj@cornell: 57723979Ssklower * make sure OB packets convey exactly 1 byte. 57823979Ssklower * If the packet is 1 byte or larger, we 57923979Ssklower * have already guaranted there to be at least 58023979Ssklower * one garbage byte for the checksum, and 58123979Ssklower * extra bytes shouldn't hurt! 58223979Ssklower */ 58323979Ssklower if (len > sizeof(*si)) { 58423979Ssklower si->si_cc |= SP_OB; 58523979Ssklower len = (1 + sizeof(*si)); 58623979Ssklower } 58723979Ssklower } 58824225Ssklower si->si_len = htons((u_short)len); 58921496Ssklower /* 59021496Ssklower * queue stuff up for output 59121496Ssklower */ 59221496Ssklower sbappendrecord(sb,m); 59321496Ssklower cb->s_seq++; 59421496Ssklower } 59521496Ssklower /* 59621496Ssklower * update window 59721496Ssklower */ 59821496Ssklower { 59924225Ssklower register struct sockbuf *sb2 = &so->so_rcv; 600*24732Ssklower int credit = ((sb2->sb_mbmax - sb2->sb_mbcnt) / 601*24732Ssklower ((short)cb->s_mtu)); 602*24732Ssklower int alo = cb->s_ack + (credit > 0 ? credit : 0) - 1; 60321496Ssklower 604*24732Ssklower if (cb->s_alo < alo) { 605*24732Ssklower /* If the amount we are raising the window 606*24732Ssklower is more than his remaining headroom, tell 607*24732Ssklower him about it. In particular, if he is at 608*24732Ssklower his limit, any amount at all will do! */ 609*24732Ssklower u_short raise = alo - cb->s_alo; 610*24732Ssklower u_short headroom = 1 + cb->s_alo - cb->s_ack; 611*24732Ssklower 612*24732Ssklower if(SSEQ_LT(headroom, raise)) 613*24732Ssklower cb->s_flags |= SF_AK; 61424330Ssklower cb->s_alo = alo; 615*24732Ssklower } 61621496Ssklower } 61721496Ssklower 61821496Ssklower if (cb->s_oobflags & SF_SOOB) { 61921496Ssklower /* 62021496Ssklower * must transmit this out of band packet 62121496Ssklower */ 62221496Ssklower cb->s_oobflags &= ~ SF_SOOB; 62321496Ssklower } else { 62421496Ssklower /* 62521496Ssklower * Decide what to transmit: 62621496Ssklower * If we have a new packet, send that 62721496Ssklower * (So long as it is in our allocation) 62821496Ssklower * If it is time to retransmit a packet, 62921496Ssklower * send that. 63021496Ssklower * Otherwise, see if it time to bang on them 63121496Ssklower * to ask for our current allocation. 63221496Ssklower */ 63321496Ssklower if (SSEQ_LT(cb->s_snt, cb->s_ralo)) 63421496Ssklower lookfor = cb->s_snt + 1; 63524330Ssklower else if (cb->s_force == (1+TCPT_REXMT)) { 63621496Ssklower lookfor = cb->s_rack; 63721496Ssklower } else if (SSEQ_LT(cb->s_ralo, cb->s_seq)) { 63821496Ssklower lookfor = 0; 63924330Ssklower if (cb->s_timer[TCPT_PERSIST] == 0) { 64021496Ssklower spp_setpersist(cb); 64124330Ssklower /* tcp has cb->s_rxtshift = 0; here */ 64221496Ssklower } 64321496Ssklower } 64421496Ssklower m = sb->sb_mb; 64524330Ssklower while (m) { 64621496Ssklower si = mtod(m, struct spidp *); 64721496Ssklower m = m->m_act; 64821496Ssklower if (SSEQ_LT(si->si_seq, cb->s_rack)) { 64921496Ssklower if ((sb->sb_flags & SB_WAIT) 65021496Ssklower || so->so_snd.sb_sel) 65121496Ssklower sowwakeup(so); 65221496Ssklower sbdroprecord(sb); 65321496Ssklower si = 0; 65421496Ssklower continue; 65521496Ssklower } 65621496Ssklower if (SSEQ_LT(si->si_seq, lookfor)) 65721496Ssklower continue; 65821496Ssklower break; 65921496Ssklower } 66024330Ssklower if (si && (si->si_seq != lookfor)) 66124330Ssklower si = 0; 66221496Ssklower } 66321496Ssklower cb->s_want = lookfor; 66421496Ssklower 66521496Ssklower if (si) { 66621496Ssklower /* 66721496Ssklower * must make a copy of this packet for 66821496Ssklower * idp_output to monkey with 66921496Ssklower */ 67024330Ssklower m = m_copy(dtom(si), 0, (int)M_COPYALL); 67124330Ssklower if (m == NULL) 67223515Ssklower return (ENOBUFS); 67323515Ssklower m0 = m; 67421496Ssklower si = mtod(m, struct spidp *); 67521496Ssklower } else if (cb->s_force || cb->s_flags & SF_AK) { 67621496Ssklower /* 67721496Ssklower * Must send an acknowledgement or a probe 67821496Ssklower */ 67921496Ssklower m = m_get(M_DONTWAIT, MT_HEADER); 68021496Ssklower if (m == 0) 68123515Ssklower return (ENOBUFS); 68221496Ssklower /* 68321496Ssklower * Fill in mbuf with extended SP header 68421496Ssklower * and addresses and length put into network format. 68521496Ssklower */ 68621496Ssklower m->m_off = MMAXOFF - sizeof (struct spidp); 68721496Ssklower m->m_len = sizeof (*si); 68821496Ssklower m->m_next = 0; 68921496Ssklower si = mtod(m, struct spidp *); 69021496Ssklower *si = cb->s_shdr; 69121496Ssklower si->si_seq = cb->s_snt + 1; 69223979Ssklower si->si_len = htons(sizeof (*si)); 69321496Ssklower si->si_cc |= SP_SP; 69421496Ssklower cb->s_flags &= ~SF_AK; 69521496Ssklower } 69621496Ssklower /* 69721496Ssklower * Stuff checksum and output datagram. 69821496Ssklower */ 69921496Ssklower if (si) { 70021496Ssklower /* 70121496Ssklower * If we are almost out of allocation 70221496Ssklower * or one of the timers has gone off 70321496Ssklower * request an ack. 70421496Ssklower */ 70524330Ssklower if (SSEQ_GEQ(cb->s_seq, cb->s_ralo)) 70621496Ssklower si->si_cc |= SP_SA; 70721496Ssklower if (cb->s_force) { 70821496Ssklower si->si_cc |= SP_SA; 70921496Ssklower cb->s_force = 0; 71021496Ssklower } 71124330Ssklower /* 71224330Ssklower * If this is a new packet (and not a system packet), 71323979Ssklower * and we are not currently timing anything, 71423979Ssklower * time this one and ask for an ack. 71521496Ssklower */ 71624330Ssklower if (SSEQ_LT(cb->s_snt, si->si_seq) && (!(si->si_cc & SP_SP))) { 71721496Ssklower cb->s_snt = si->si_seq; 71824330Ssklower if (cb->s_rtt == 0) { 71921496Ssklower cb->s_rtseq = si->si_seq; 72021496Ssklower cb->s_rtt = 1; 72121496Ssklower si->si_cc |= SP_SA; 72221496Ssklower } 72321496Ssklower /* 72421496Ssklower * If the retransmit timer has not been set 72521496Ssklower * and this is a real packet 72621496Ssklower * then start the retransmit timer 72721496Ssklower */ 72824330Ssklower if (cb->s_timer[TCPT_REXMT] == 0) { 72921496Ssklower TCPT_RANGESET(cb->s_timer[TCPT_REXMT], 73021496Ssklower tcp_beta * cb->s_srtt, TCPTV_MIN, 73121496Ssklower TCPTV_MAX); 73221496Ssklower cb->s_rxtshift = 0; 73321496Ssklower } 73421496Ssklower } 73521496Ssklower si->si_seq = htons(si->si_seq); 73621496Ssklower si->si_alo = htons(cb->s_alo); 73721496Ssklower si->si_ack = htons(cb->s_ack); 73821496Ssklower 73921496Ssklower if (idpcksum) { 74021496Ssklower si->si_sum = 0; 74123979Ssklower len = ntohs(si->si_len); 74224330Ssklower if (len & 1) 74324330Ssklower len++; 74421496Ssklower si->si_sum = ns_cksum(dtom(si), len); 74521496Ssklower } else 74621496Ssklower si->si_sum = 0xffff; 74721496Ssklower 74821496Ssklower if (so->so_options & SO_DEBUG || traceallspps) 74921496Ssklower spp_trace(SA_OUTPUT, cb->s_state, cb, si, 0); 75021496Ssklower spp_output_cnt++; 75121496Ssklower if (so->so_options & SO_DONTROUTE) 75221496Ssklower error = ns_output(m, (struct route *)0, NS_ROUTETOIF); 75321496Ssklower else 75421496Ssklower error = ns_output(m, &cb->s_nspcb->nsp_route, 0); 75521496Ssklower if (traceallspps && sppconsdebug) { 75621496Ssklower printf("spp_out: %x\n", error); 75721496Ssklower } 75823515Ssklower return (error); 75921496Ssklower } 76021496Ssklower if (so->so_options & SO_DEBUG || traceallspps) 76121496Ssklower spp_trace(SA_OUTPUT, cb->s_state, cb, si, 0); 76223515Ssklower return (error); 76321496Ssklower } 76421496Ssklower 76521496Ssklower /*ARGSUSED*/ 76621496Ssklower spp_ctloutput(req, so, level, name, value) 76721496Ssklower int req; 76821496Ssklower struct socket *so; 76921496Ssklower int name; 77021496Ssklower struct mbuf **value; 77121496Ssklower { 77221496Ssklower register struct mbuf *m; 77321496Ssklower struct nspcb *nsp = sotonspcb(so); 77421496Ssklower register struct sppcb *cb; 77521496Ssklower int mask, error = 0; 77621496Ssklower 77721496Ssklower if (level != NSPROTO_SPP) { 77821496Ssklower /* This will have to be changed when we do more general 77921496Ssklower stacking of protocols */ 78023515Ssklower return (idp_ctloutput(req, so, level, name, value)); 78121496Ssklower } 78221496Ssklower if (nsp == NULL) { 78321496Ssklower error = EINVAL; 78421496Ssklower goto release; 78521496Ssklower } else 78621496Ssklower cb = nstosppcb(nsp); 78721496Ssklower 78821496Ssklower switch (req) { 78923515Ssklower 79021496Ssklower case PRCO_GETOPT: 79124330Ssklower if (value == NULL) 79223515Ssklower return (EINVAL); 79321496Ssklower m = m_get(M_DONTWAIT, MT_DATA); 79424330Ssklower if (m == NULL) 79523515Ssklower return (ENOBUFS); 79621496Ssklower switch (name) { 79723515Ssklower 79821496Ssklower case SO_HEADERS_ON_INPUT: 79921496Ssklower mask = SF_HI; 80021496Ssklower goto get_flags; 80123515Ssklower 80221496Ssklower case SO_HEADERS_ON_OUTPUT: 80321496Ssklower mask = SF_HO; 80421496Ssklower get_flags: 80521496Ssklower m->m_len = sizeof(short); 80621496Ssklower m->m_off = MMAXOFF - sizeof(short); 80721496Ssklower *mtod(m, short *) = cb->s_flags & mask; 80821496Ssklower break; 80923515Ssklower 81024615Ssklower case SO_MTU: 81124615Ssklower m->m_len = sizeof(u_short); 81224615Ssklower m->m_off = MMAXOFF - sizeof(short); 81324615Ssklower *mtod(m, short *) = cb->s_mtu; 81424615Ssklower break; 81524615Ssklower 81621496Ssklower case SO_LAST_HEADER: 81721496Ssklower m->m_len = sizeof(struct sphdr); 81821496Ssklower m->m_off = MMAXOFF - sizeof(struct sphdr); 81921496Ssklower *mtod(m, struct sphdr *) = cb->s_rhdr; 82021496Ssklower break; 82123515Ssklower 82221496Ssklower case SO_DEFAULT_HEADERS: 82321496Ssklower m->m_len = sizeof(struct spidp); 82421496Ssklower m->m_off = MMAXOFF - sizeof(struct sphdr); 82521496Ssklower *mtod(m, struct sphdr *) = cb->s_shdr.si_s; 82621496Ssklower } 82721496Ssklower *value = m; 82821496Ssklower break; 82923515Ssklower 83021496Ssklower case PRCO_SETOPT: 83124615Ssklower if (value == 0 || *value == 0) { 83224615Ssklower error = EINVAL; 83324615Ssklower break; 83424615Ssklower } 83521496Ssklower switch (name) { 83624225Ssklower int *ok; 83721496Ssklower 83821496Ssklower case SO_HEADERS_ON_INPUT: 83921496Ssklower mask = SF_HI; 84021496Ssklower goto set_head; 84123515Ssklower 84221496Ssklower case SO_HEADERS_ON_OUTPUT: 84321496Ssklower mask = SF_HO; 84421496Ssklower set_head: 84524615Ssklower if (cb->s_flags & SF_PI) { 84621496Ssklower ok = mtod(*value, int *); 84721496Ssklower if (*ok) 84821496Ssklower cb->s_flags |= mask; 84921496Ssklower else 85021496Ssklower cb->s_flags &= ~mask; 85121496Ssklower } else error = EINVAL; 85221496Ssklower break; 85323515Ssklower 85424615Ssklower case SO_MTU: 85524615Ssklower cb->s_mtu = *(mtod(*value, u_short *)); 85624615Ssklower break; 85724615Ssklower 85821496Ssklower case SO_DEFAULT_HEADERS: 85921496Ssklower { 86021496Ssklower register struct sphdr *sp 86121496Ssklower = mtod(*value, struct sphdr *); 86221496Ssklower cb->s_dt = sp->sp_dt; 86321496Ssklower cb->s_cc = sp->sp_cc & SP_EM; 86421496Ssklower } 86521496Ssklower } 86624615Ssklower m_freem(*value); 86721496Ssklower break; 86821496Ssklower } 86921496Ssklower release: 87023515Ssklower return (error); 87121496Ssklower } 87221496Ssklower 87321496Ssklower /*ARGSUSED*/ 87421496Ssklower spp_usrreq(so, req, m, nam, rights) 87521496Ssklower struct socket *so; 87621496Ssklower int req; 87721496Ssklower struct mbuf *m, *nam, *rights; 87821496Ssklower { 87921496Ssklower struct nspcb *nsp = sotonspcb(so); 88021496Ssklower register struct sppcb *cb; 88121496Ssklower int s = splnet(); 88221496Ssklower int error = 0, ostate; 88321496Ssklower 88421496Ssklower if (req == PRU_CONTROL) 88521496Ssklower return (ns_control(so, (int)m, (caddr_t)nam, 88621496Ssklower (struct ifnet *)rights)); 88721496Ssklower if (rights && rights->m_len) { 88821496Ssklower error = EINVAL; 88921496Ssklower goto release; 89021496Ssklower } 89121496Ssklower if (nsp == NULL) { 89221496Ssklower if (req != PRU_ATTACH) { 89321496Ssklower error = EINVAL; 89421496Ssklower goto release; 89521496Ssklower } 89621496Ssklower } else 89721496Ssklower cb = nstosppcb(nsp); 89821496Ssklower 89921496Ssklower ostate = cb ? cb->s_state : 0; 90021496Ssklower 90121496Ssklower switch (req) { 90223515Ssklower 90321496Ssklower case PRU_ATTACH: 90421496Ssklower if (nsp != NULL) { 90521496Ssklower error = EISCONN; 90621496Ssklower break; 90721496Ssklower } 90821496Ssklower error = ns_pcballoc(so, &nspcb); 90921496Ssklower if (error) 91021496Ssklower break; 91121496Ssklower error = soreserve(so, 2048, 2048); 91221496Ssklower if (error) 91321496Ssklower break; 91421496Ssklower nsp = sotonspcb(so); 91521496Ssklower { 91621496Ssklower struct mbuf *mm = m_getclr(M_DONTWAIT,MT_PCB); 91721496Ssklower 91824330Ssklower if (mm == NULL) { 91921496Ssklower error = ENOBUFS; 92021496Ssklower break; 92121496Ssklower } 92221496Ssklower cb = mtod(mm, struct sppcb *); 92321496Ssklower cb->s_state = TCPS_LISTEN; 92421496Ssklower cb->s_snt = -1; 92521496Ssklower cb->s_q.si_next = cb->s_q.si_prev = &cb->s_q; 92621496Ssklower cb->s_nspcb = nsp; 92721496Ssklower nsp->nsp_pcb = (caddr_t) cb; 92821496Ssklower } 92921496Ssklower break; 93021496Ssklower 93121496Ssklower case PRU_DETACH: 93221496Ssklower if (nsp == NULL) { 93321496Ssklower error = ENOTCONN; 93421496Ssklower break; 93521496Ssklower } 93621496Ssklower if (cb->s_state > TCPS_LISTEN) 93721496Ssklower cb = spp_disconnect(cb); 93821496Ssklower else 93921496Ssklower cb = spp_close(cb); 94021496Ssklower break; 94121496Ssklower 94221496Ssklower case PRU_BIND: 94321496Ssklower error = ns_pcbbind(nsp, nam); 94421496Ssklower break; 94521496Ssklower 94621496Ssklower case PRU_LISTEN: 94721496Ssklower if (nsp->nsp_lport == 0) 94821496Ssklower error = ns_pcbbind(nsp, (struct mbuf *)0); 94921496Ssklower if (error == 0) 95021496Ssklower cb->s_state = TCPS_LISTEN; 95121496Ssklower break; 95221496Ssklower 95321496Ssklower /* 95421496Ssklower * Initiate connection to peer. 95521496Ssklower * Enter SYN_SENT state, and mark socket as connecting. 95621496Ssklower * Start keep-alive timer, setup prototype header, 95721496Ssklower * Send initial system packet requesting connection. 95821496Ssklower */ 95921496Ssklower case PRU_CONNECT: 96021496Ssklower if (nsp->nsp_lport == 0) { 96121496Ssklower error = ns_pcbbind(nsp, (struct mbuf *)0); 96221496Ssklower if (error) 96321496Ssklower break; 96421496Ssklower } 96521496Ssklower error = ns_pcbconnect(nsp, nam); 96621496Ssklower if (error) 96721496Ssklower break; 96821496Ssklower soisconnecting(so); 96921496Ssklower cb->s_state = TCPS_SYN_SENT; 97021496Ssklower cb->s_did = 0; 97121496Ssklower spp_template(cb); 97221496Ssklower cb->s_timer[TCPT_KEEP] = TCPTV_KEEP; 97321496Ssklower cb->s_force = 1 + TCPTV_KEEP; 97421496Ssklower /* 97521496Ssklower * Other party is required to respond to 97621496Ssklower * the port I send from, but he is not 97721496Ssklower * required to answer from where I am sending to, 97821496Ssklower * so allow wildcarding. 97921496Ssklower * original port I am sending to is still saved in 98021496Ssklower * cb->s_dport. 98121496Ssklower */ 98221496Ssklower nsp->nsp_fport = 0; 98321496Ssklower error = spp_output(cb, (struct mbuf *) 0); 98421496Ssklower break; 98521496Ssklower 98621496Ssklower case PRU_CONNECT2: 98721496Ssklower error = EOPNOTSUPP; 98821496Ssklower break; 98921496Ssklower 99021496Ssklower /* 99121496Ssklower * We may decide later to implement connection closing 99221496Ssklower * handshaking at the spp level optionally. 99321496Ssklower * here is the hook to do it: 99421496Ssklower */ 99521496Ssklower case PRU_DISCONNECT: 99621496Ssklower cb = spp_disconnect(cb); 99721496Ssklower break; 99821496Ssklower 99921496Ssklower /* 100021496Ssklower * Accept a connection. Essentially all the work is 100121496Ssklower * done at higher levels; just return the address 100221496Ssklower * of the peer, storing through addr. 100321496Ssklower */ 100421496Ssklower case PRU_ACCEPT: { 100521496Ssklower struct sockaddr_ns *sns = mtod(nam, struct sockaddr_ns *); 100621496Ssklower 100721496Ssklower nam->m_len = sizeof (struct sockaddr_ns); 100821496Ssklower sns->sns_family = AF_NS; 100921496Ssklower sns->sns_addr = nsp->nsp_faddr; 101021496Ssklower break; 101121496Ssklower } 101221496Ssklower 101321496Ssklower case PRU_SHUTDOWN: 101421496Ssklower socantsendmore(so); 101521496Ssklower cb = spp_usrclosed(cb); 101621496Ssklower if (cb) 101721496Ssklower error = spp_output(cb, (struct mbuf *) 0); 101821496Ssklower break; 101921496Ssklower 102021496Ssklower /* 102121496Ssklower * After a receive, possibly send acknowledgment 102221496Ssklower * updating allocation. 102321496Ssklower */ 102421496Ssklower case PRU_RCVD: 102521496Ssklower (void) spp_output(cb, (struct mbuf *) 0); 102621496Ssklower break; 102721496Ssklower 102821496Ssklower case PRU_SEND: 102921496Ssklower error = spp_output(cb, m); 103021496Ssklower m = NULL; 103121496Ssklower break; 103221496Ssklower 103321496Ssklower case PRU_ABORT: 103424225Ssklower (void) spp_drop(cb, ECONNABORTED); 103521496Ssklower break; 103621496Ssklower 103721496Ssklower case PRU_SENSE: 103821496Ssklower case PRU_CONTROL: 103921496Ssklower m = NULL; 104021496Ssklower error = EOPNOTSUPP; 104121496Ssklower break; 104221496Ssklower 104321496Ssklower case PRU_RCVOOB: 1044*24732Ssklower if (so->so_oobmark == 0 && 1045*24732Ssklower (so->so_state & SS_RCVATMARK) == 0) { 1046*24732Ssklower error = EINVAL; 1047*24732Ssklower break; 1048*24732Ssklower } 104921496Ssklower if ( ! (cb->s_oobflags & SF_IOOB) ) { 105021496Ssklower error = EWOULDBLOCK; 105121496Ssklower break; 105221496Ssklower } 105321496Ssklower m->m_len = 1; 105421496Ssklower *mtod(m, caddr_t) = cb->s_iobc; 1055*24732Ssklower if (((int)nam & MSG_PEEK) == 0) 1056*24732Ssklower cb->s_oobflags &= ~ SF_IOOB; 105721496Ssklower break; 105821496Ssklower 105921496Ssklower case PRU_SENDOOB: 106021496Ssklower if (sbspace(&so->so_snd) < -512) { 106121496Ssklower m_freem(m); 106221496Ssklower error = ENOBUFS; 106321496Ssklower break; 106421496Ssklower } 106521496Ssklower cb->s_oobflags |= SF_SOOB; 106621496Ssklower error = spp_output(cb, m); 106721496Ssklower m = NULL; 106821496Ssklower cb->s_oobflags &= ~SF_SOOB; 106921496Ssklower break; 107021496Ssklower 107121496Ssklower case PRU_SOCKADDR: 107221496Ssklower ns_setsockaddr(nsp, nam); 107321496Ssklower break; 107421496Ssklower 107521496Ssklower case PRU_PEERADDR: 107621496Ssklower ns_setpeeraddr(nsp, nam); 107721496Ssklower break; 107821496Ssklower 107921496Ssklower case PRU_SLOWTIMO: 108021496Ssklower cb = spp_timers(cb, (int)nam); 108121496Ssklower break; 108221496Ssklower 108321496Ssklower case PRU_FASTTIMO: 108421496Ssklower case PRU_PROTORCV: 108521496Ssklower case PRU_PROTOSEND: 108621496Ssklower error = EOPNOTSUPP; 108721496Ssklower break; 108821496Ssklower 108921496Ssklower default: 109021496Ssklower panic("sp_usrreq"); 109121496Ssklower } 109221496Ssklower if (cb && (so->so_options & SO_DEBUG || traceallspps)) 109324225Ssklower spp_trace(SA_USER, (u_char)ostate, cb, (struct spidp *)0, req); 109421496Ssklower release: 109521496Ssklower if (m != NULL) 109621496Ssklower m_freem(m); 109721496Ssklower splx(s); 109821496Ssklower return (error); 109921496Ssklower } 110021496Ssklower 110121496Ssklower spp_usrreq_sp(so, req, m, nam, rights) 110221496Ssklower struct socket *so; 110321496Ssklower int req; 110421496Ssklower struct mbuf *m, *nam, *rights; 110521496Ssklower { 110621496Ssklower int error = spp_usrreq(so, req, m, nam, rights); 110721496Ssklower 110824330Ssklower if (req == PRU_ATTACH && error == 0) { 110921496Ssklower struct nspcb *nsp = sotonspcb(so); 111021496Ssklower ((struct sppcb *)nsp->nsp_pcb)->s_flags |= 111121496Ssklower (SF_HI | SF_HO | SF_PI); 111221496Ssklower } 111323515Ssklower return (error); 111421496Ssklower } 111521496Ssklower 111621496Ssklower /* 111721496Ssklower * Create template to be used to send spp packets on a connection. 111821496Ssklower * Called after host entry created, fills 111921496Ssklower * in a skeletal spp header (choosing connection id), 112021496Ssklower * minimizing the amount of work necessary when the connection is used. 112121496Ssklower */ 112221496Ssklower spp_template(cb) 112321496Ssklower struct sppcb *cb; 112421496Ssklower { 112521496Ssklower register struct nspcb *nsp = cb->s_nspcb; 112621496Ssklower register struct spidp *n = &(cb->s_shdr); 112721496Ssklower 112824615Ssklower cb->s_mtu = 576 - sizeof (struct spidp); 112921496Ssklower n->si_pt = NSPROTO_SPP; 113021496Ssklower n->si_sna = nsp->nsp_laddr; 113121496Ssklower n->si_dna = nsp->nsp_faddr; 113221496Ssklower n->si_sid = htons(spp_iss); 113321496Ssklower spp_iss += SPP_ISSINCR/2; 113421496Ssklower n->si_alo = 1; 113521496Ssklower } 113621496Ssklower 113721496Ssklower /* 113821496Ssklower * Close a SPIP control block: 113921496Ssklower * discard spp control block itself 114021496Ssklower * discard ns protocol control block 114121496Ssklower * wake up any sleepers 114221496Ssklower */ 114321496Ssklower struct sppcb * 114421496Ssklower spp_close(cb) 114521496Ssklower register struct sppcb *cb; 114621496Ssklower { 114721496Ssklower register struct spidp_q *s; 114821496Ssklower struct nspcb *nsp = cb->s_nspcb; 114921496Ssklower struct socket *so = nsp->nsp_socket; 115021496Ssklower register struct mbuf *m; 115121496Ssklower 115221496Ssklower s = cb->s_q.si_next; 115321496Ssklower while (s != &(cb->s_q)) { 115421496Ssklower s = s->si_next; 115521496Ssklower m = dtom(s->si_prev); 115621496Ssklower remque(s->si_prev); 115721496Ssklower m_freem(m); 115821496Ssklower } 115921496Ssklower (void) m_free(dtom(cb)); 116021496Ssklower nsp->nsp_pcb = 0; 116121496Ssklower soisdisconnected(so); 116221496Ssklower ns_pcbdetach(nsp); 116323515Ssklower return ((struct sppcb *)0); 116421496Ssklower } 116521496Ssklower /* 116621496Ssklower * Someday we may do level 3 handshaking 116721496Ssklower * to close a connection or send a xerox style error. 116821496Ssklower * For now, just close. 116921496Ssklower */ 117021496Ssklower struct sppcb * 117121496Ssklower spp_usrclosed(cb) 117221496Ssklower register struct sppcb *cb; 117321496Ssklower { 117423515Ssklower return (spp_close(cb)); 117521496Ssklower } 117621496Ssklower struct sppcb * 117721496Ssklower spp_disconnect(cb) 117821496Ssklower register struct sppcb *cb; 117921496Ssklower { 118023515Ssklower return (spp_close(cb)); 118121496Ssklower } 118221496Ssklower /* 118321496Ssklower * Drop connection, reporting 118421496Ssklower * the specified error. 118521496Ssklower */ 118621496Ssklower struct sppcb * 118721496Ssklower spp_drop(cb, errno) 118821496Ssklower register struct sppcb *cb; 118921496Ssklower int errno; 119021496Ssklower { 119121496Ssklower struct socket *so = cb->s_nspcb->nsp_socket; 119221496Ssklower 119321496Ssklower /* 119421496Ssklower * someday, in the xerox world 119521496Ssklower * we will generate error protocol packets 119621496Ssklower * announcing that the socket has gone away. 119721496Ssklower */ 119821496Ssklower /*if (TCPS_HAVERCVDSYN(tp->t_state)) { 119921496Ssklower tp->t_state = TCPS_CLOSED; 120021496Ssklower (void) tcp_output(tp); 120121496Ssklower }*/ 120221496Ssklower so->so_error = errno; 120321496Ssklower return (spp_close(cb)); 120421496Ssklower } 120521496Ssklower 120621496Ssklower spp_abort(nsp) 120721496Ssklower struct nspcb *nsp; 120821496Ssklower { 120921496Ssklower 121024225Ssklower (void) spp_close((struct sppcb *)nsp->nsp_pcb); 121121496Ssklower } 121221496Ssklower 121321496Ssklower spp_setpersist(cb) 121421496Ssklower register struct sppcb *cb; 121521496Ssklower { 121621496Ssklower 121721496Ssklower /*if (cb->s_timer[TCPT_REXMT]) 121821496Ssklower panic("spp_output REXMT");*/ 121921496Ssklower /* 122021496Ssklower * Start/restart persistance timer. 122121496Ssklower */ 122221496Ssklower TCPT_RANGESET(cb->s_timer[TCPT_PERSIST], 122321496Ssklower ((int)(tcp_beta * cb->s_srtt)) << cb->s_rxtshift, 122421496Ssklower TCPTV_PERSMIN, TCPTV_MAX); 122521496Ssklower cb->s_rxtshift++; 122621496Ssklower if (cb->s_rxtshift >= TCP_MAXRXTSHIFT) 122721496Ssklower cb->s_rxtshift = 0; 122821496Ssklower } 122921496Ssklower /* 123021496Ssklower * Fast timeout routine for processing delayed acks 123121496Ssklower */ 123221496Ssklower int spp_ftcnt; 123321496Ssklower spp_fasttimo() 123421496Ssklower { 123521496Ssklower register struct nspcb *nsp; 123621496Ssklower register struct sppcb *cb; 123721496Ssklower int s = splnet(); 123821496Ssklower 123921496Ssklower nsp = nspcb.nsp_next; 124021496Ssklower spp_ftcnt++; 124121496Ssklower if (nsp) 124221496Ssklower for (; nsp != &nspcb; nsp = nsp->nsp_next) 124321496Ssklower if ((cb = (struct sppcb *)nsp->nsp_pcb) && 124421496Ssklower (cb->s_flags & SF_DELACK)) { 124521496Ssklower cb->s_flags &= ~SF_DELACK; 124621496Ssklower cb->s_flags |= SF_AK; 124721496Ssklower (void) spp_output(cb, (struct mbuf *) 0); 124821496Ssklower } 124921496Ssklower splx(s); 125021496Ssklower } 125121496Ssklower 125221496Ssklower /* 125321496Ssklower * spp protocol timeout routine called every 500 ms. 125421496Ssklower * Updates the timers in all active pcb's and 125521496Ssklower * causes finite state machine actions if timers expire. 125621496Ssklower */ 125721496Ssklower spp_slowtimo() 125821496Ssklower { 125921496Ssklower register struct nspcb *ip, *ipnxt; 126021496Ssklower register struct sppcb *cb; 126121496Ssklower int s = splnet(); 126221496Ssklower register int i; 126321496Ssklower 126421496Ssklower /* 126521496Ssklower * Search through tcb's and update active timers. 126621496Ssklower */ 126721496Ssklower ip = nspcb.nsp_next; 126821496Ssklower if (ip == 0) { 126921496Ssklower splx(s); 127021496Ssklower return; 127121496Ssklower } 127221496Ssklower while (ip != &nspcb) { 127321496Ssklower cb = nstosppcb(ip); 127421496Ssklower ipnxt = ip->nsp_next; 127521496Ssklower if (cb == 0) 127621496Ssklower goto tpgone; 127721496Ssklower for (i = 0; i < TCPT_NTIMERS; i++) { 127821496Ssklower if (cb->s_timer[i] && --cb->s_timer[i] == 0) { 127921496Ssklower (void) spp_usrreq(cb->s_nspcb->nsp_socket, 128021496Ssklower PRU_SLOWTIMO, (struct mbuf *)0, 128121496Ssklower (struct mbuf *)i, (struct mbuf *)0); 128221496Ssklower if (ipnxt->nsp_prev != ip) 128321496Ssklower goto tpgone; 128421496Ssklower } 128521496Ssklower } 128621496Ssklower cb->s_idle++; 128721496Ssklower if (cb->s_rtt) 128821496Ssklower cb->s_rtt++; 128921496Ssklower tpgone: 129021496Ssklower ip = ipnxt; 129121496Ssklower } 129221496Ssklower spp_iss += SPP_ISSINCR/PR_SLOWHZ; /* increment iss */ 129321496Ssklower splx(s); 129421496Ssklower } 129521496Ssklower 129621496Ssklower float spp_backoff[TCP_MAXRXTSHIFT] = 129721496Ssklower { 1.0, 1.2, 1.4, 1.7, 2.0, 3.0, 5.0, 8.0, 16.0, 32.0 }; 129824412Swalsh int sppexprexmtbackoff = 0; 129921496Ssklower /* 130024615Ssklower * SPP timer processing. 130121496Ssklower */ 130221496Ssklower struct sppcb * 130321496Ssklower spp_timers(cb, timer) 130421496Ssklower register struct sppcb *cb; 130521496Ssklower int timer; 130621496Ssklower { 130721496Ssklower 130821496Ssklower cb->s_force = 1 + timer; 130921496Ssklower switch (timer) { 131021496Ssklower 131121496Ssklower /* 131221496Ssklower * 2 MSL timeout in shutdown went off. Delete connection 131321496Ssklower * control block. 131421496Ssklower */ 131521496Ssklower case TCPT_2MSL: 131621496Ssklower cb = spp_close(cb); 131721496Ssklower break; 131821496Ssklower 131921496Ssklower /* 132021496Ssklower * Retransmission timer went off. Message has not 132121496Ssklower * been acked within retransmit interval. Back off 132221496Ssklower * to a longer retransmit interval and retransmit all 132321496Ssklower * unacknowledged messages in the window. 132421496Ssklower */ 132521496Ssklower case TCPT_REXMT: 132621496Ssklower cb->s_rxtshift++; 132721496Ssklower if (cb->s_rxtshift > TCP_MAXRXTSHIFT) { 132821496Ssklower cb = spp_drop(cb, ETIMEDOUT); 132921496Ssklower break; 133021496Ssklower } 133121496Ssklower (void) spp_output(cb, (struct mbuf *) 0); 133221496Ssklower TCPT_RANGESET(cb->s_timer[TCPT_REXMT], 133321496Ssklower (int)cb->s_srtt, TCPTV_MIN, TCPTV_MAX); 133424412Swalsh if (sppexprexmtbackoff) { 133521496Ssklower TCPT_RANGESET(cb->s_timer[TCPT_REXMT], 133621496Ssklower cb->s_timer[TCPT_REXMT] << cb->s_rxtshift, 133721496Ssklower TCPTV_MIN, TCPTV_MAX); 133821496Ssklower } else { 133921496Ssklower TCPT_RANGESET(cb->s_timer[TCPT_REXMT], 134021496Ssklower cb->s_timer[TCPT_REXMT] * 134121496Ssklower spp_backoff[cb->s_rxtshift - 1], 134221496Ssklower TCPTV_MIN, TCPTV_MAX); 134321496Ssklower } 134421496Ssklower break; 134521496Ssklower 134621496Ssklower /* 134721496Ssklower * Persistance timer into zero window. 134821496Ssklower * Force a probe to be sent. 134921496Ssklower */ 135021496Ssklower case TCPT_PERSIST: 135121496Ssklower (void) spp_output(cb, (struct mbuf *) 0); 135221496Ssklower spp_setpersist(cb); 135321496Ssklower break; 135421496Ssklower 135521496Ssklower /* 135621496Ssklower * Keep-alive timer went off; send something 135721496Ssklower * or drop connection if idle for too long. 135821496Ssklower */ 135921496Ssklower case TCPT_KEEP: 136021496Ssklower if (cb->s_state < TCPS_ESTABLISHED) 136121496Ssklower goto dropit; 136221496Ssklower if (cb->s_nspcb->nsp_socket->so_options & SO_KEEPALIVE) { 136321496Ssklower if (cb->s_idle >= TCPTV_MAXIDLE) 136421496Ssklower goto dropit; 136521496Ssklower (void) spp_output(cb, (struct mbuf *) 0); 136621496Ssklower } else 136721496Ssklower cb->s_idle = 0; 136821496Ssklower cb->s_timer[TCPT_KEEP] = TCPTV_KEEP; 136921496Ssklower break; 137021496Ssklower dropit: 137121496Ssklower cb = spp_drop(cb, ETIMEDOUT); 137221496Ssklower break; 137321496Ssklower } 137421496Ssklower return (cb); 137521496Ssklower } 1376