1*21496Ssklower /* spp_usrreq.c 6.1 85/05/30 */ 2*21496Ssklower 3*21496Ssklower #include "param.h" 4*21496Ssklower #include "dir.h" 5*21496Ssklower #include "user.h" 6*21496Ssklower #include "mbuf.h" 7*21496Ssklower #include "protosw.h" 8*21496Ssklower #include "socket.h" 9*21496Ssklower #include "socketvar.h" 10*21496Ssklower #include "errno.h" 11*21496Ssklower 12*21496Ssklower #include "../net/if.h" 13*21496Ssklower #include "../net/route.h" 14*21496Ssklower #include "../netinet/tcp_fsm.h" 15*21496Ssklower #include "../netinet/tcp_timer.h" 16*21496Ssklower 17*21496Ssklower #include "ns.h" 18*21496Ssklower #include "ns_pcb.h" 19*21496Ssklower #include "idp.h" 20*21496Ssklower #include "idp_var.h" 21*21496Ssklower #include "ns_error.h" 22*21496Ssklower #include "sp.h" 23*21496Ssklower #include "spidp.h" 24*21496Ssklower #include "spp_var.h" 25*21496Ssklower #include "spp_debug.h" 26*21496Ssklower 27*21496Ssklower /* 28*21496Ssklower * SP protocol implementation. 29*21496Ssklower */ 30*21496Ssklower spp_init() 31*21496Ssklower { 32*21496Ssklower 33*21496Ssklower spp_iss = 1; /* WRONG !! should fish it out of TODR */ 34*21496Ssklower } 35*21496Ssklower struct spidp spp_savesi; 36*21496Ssklower int traceallspps = 0; 37*21496Ssklower extern int sppconsdebug; 38*21496Ssklower 39*21496Ssklower int spp_hardnosed; 40*21496Ssklower spp_input(m, nsp) 41*21496Ssklower register struct nspcb *nsp; 42*21496Ssklower register struct mbuf *m; 43*21496Ssklower { 44*21496Ssklower register struct sppcb *cb; 45*21496Ssklower register struct spidp *si = mtod(m, struct spidp *); 46*21496Ssklower register struct socket *so; 47*21496Ssklower int len; short ostate; 48*21496Ssklower int dropsocket = 0; 49*21496Ssklower 50*21496Ssklower 51*21496Ssklower 52*21496Ssklower cb = nstosppcb(nsp); 53*21496Ssklower if (cb == 0) goto bad; 54*21496Ssklower 55*21496Ssklower si->si_seq = ntohs(si->si_seq); 56*21496Ssklower si->si_ack = ntohs(si->si_ack); 57*21496Ssklower si->si_alo = ntohs(si->si_alo); 58*21496Ssklower 59*21496Ssklower so = nsp->nsp_socket; 60*21496Ssklower if (so->so_options & SO_DEBUG || traceallspps) { 61*21496Ssklower ostate = cb->s_state; 62*21496Ssklower spp_savesi = *si; 63*21496Ssklower } 64*21496Ssklower if (so->so_options & SO_ACCEPTCONN) { 65*21496Ssklower so = sonewconn(so); 66*21496Ssklower if (so == 0) { 67*21496Ssklower spp_istat.nonucn++; 68*21496Ssklower goto drop; 69*21496Ssklower } 70*21496Ssklower /* 71*21496Ssklower * This is ugly, but .... 72*21496Ssklower * 73*21496Ssklower * Mark socket as temporary until we're 74*21496Ssklower * committed to keeping it. The code at 75*21496Ssklower * ``drop'' and ``dropwithreset'' check the 76*21496Ssklower * flag dropsocket to see if the temporary 77*21496Ssklower * socket created here should be discarded. 78*21496Ssklower * We mark the socket as discardable until 79*21496Ssklower * we're committed to it below in TCPS_LISTEN. 80*21496Ssklower */ 81*21496Ssklower dropsocket++; 82*21496Ssklower nsp = (struct nspcb *)so->so_pcb; 83*21496Ssklower nsp->nsp_laddr = si->si_dna; 84*21496Ssklower cb = nstosppcb(nsp); 85*21496Ssklower cb->s_state = TCPS_LISTEN; 86*21496Ssklower } 87*21496Ssklower 88*21496Ssklower /* 89*21496Ssklower * Packet received on connection. 90*21496Ssklower * reset idle time and keep-alive timer; 91*21496Ssklower */ 92*21496Ssklower cb->s_idle = 0; 93*21496Ssklower cb->s_timer[TCPT_KEEP] = TCPTV_KEEP; 94*21496Ssklower 95*21496Ssklower switch (cb->s_state) { 96*21496Ssklower case TCPS_LISTEN:{ 97*21496Ssklower struct mbuf *am; 98*21496Ssklower register struct sockaddr_ns *sns; 99*21496Ssklower struct ns_addr laddr; 100*21496Ssklower 101*21496Ssklower /* 102*21496Ssklower * If somebody here was carying on a conversation 103*21496Ssklower * and went away, and his pen pal thinks he can 104*21496Ssklower * still talk, we get the misdirected packet. 105*21496Ssklower */ 106*21496Ssklower if (spp_hardnosed && (si->si_did != 0 || si->si_seq != 0)) { 107*21496Ssklower spp_istat.gonawy++; 108*21496Ssklower goto dropwithreset; 109*21496Ssklower } 110*21496Ssklower am = m_get(M_DONTWAIT, MT_SONAME); 111*21496Ssklower if (am == NULL) 112*21496Ssklower goto drop; 113*21496Ssklower am->m_len = sizeof (struct sockaddr_ns); 114*21496Ssklower sns = mtod(am, struct sockaddr_ns *); 115*21496Ssklower sns->sns_family = AF_NS; 116*21496Ssklower sns->sns_addr = si->si_sna; 117*21496Ssklower laddr = nsp->nsp_laddr; 118*21496Ssklower if (ns_nullhost(laddr)) 119*21496Ssklower nsp->nsp_laddr = si->si_dna; 120*21496Ssklower if (ns_pcbconnect(nsp, am)) { 121*21496Ssklower nsp->nsp_laddr = laddr; 122*21496Ssklower (void) m_free(am); 123*21496Ssklower spp_istat.noconn++; 124*21496Ssklower goto drop; 125*21496Ssklower } 126*21496Ssklower (void) m_free(am); 127*21496Ssklower cb->s_state = TCPS_SYN_RECEIVED; 128*21496Ssklower spp_template(cb); 129*21496Ssklower cb->s_did = si->si_sid; 130*21496Ssklower cb->s_rack = si->si_ack; 131*21496Ssklower cb->s_ralo = si->si_alo; 132*21496Ssklower cb->s_flags |= SF_AK; 133*21496Ssklower cb->s_timer[TCPT_KEEP] = TCPTV_KEEP; 134*21496Ssklower dropsocket = 0; /* committed to socket */ 135*21496Ssklower } 136*21496Ssklower break; 137*21496Ssklower 138*21496Ssklower /* 139*21496Ssklower * This state means that we have gotten a response 140*21496Ssklower * to our attempt to establish a connection. 141*21496Ssklower * We fill in the data from the other side 142*21496Ssklower * (Telling which port to send to instead of the well- 143*21496Ssklower * known one we might have to in the first place ) 144*21496Ssklower * We also require that this is a response to our 145*21496Ssklower * connection id, and that it should be a system packet, 146*21496Ssklower * containing no data. 147*21496Ssklower */ 148*21496Ssklower case TCPS_SYN_SENT: 149*21496Ssklower if (si->si_did!=cb->s_sid) { 150*21496Ssklower spp_istat.notme++; 151*21496Ssklower goto drop; 152*21496Ssklower } 153*21496Ssklower cb->s_did = si->si_sid; 154*21496Ssklower cb->s_rack = si->si_ack; 155*21496Ssklower cb->s_ralo = si->si_alo; 156*21496Ssklower cb->s_dport = nsp->nsp_fport = si->si_sport; 157*21496Ssklower cb->s_timer[TCPT_REXMT] = 0; 158*21496Ssklower cb->s_flags |= SF_AK; 159*21496Ssklower soisconnected(so); 160*21496Ssklower cb->s_state = TCPS_ESTABLISHED; 161*21496Ssklower break; 162*21496Ssklower /* 163*21496Ssklower * This state means that we have heard a response 164*21496Ssklower * to our acceptance of their connection 165*21496Ssklower * It is probably logically unnecessary in this 166*21496Ssklower * implementation. 167*21496Ssklower */ 168*21496Ssklower case TCPS_SYN_RECEIVED: 169*21496Ssklower if (si->si_did!=cb->s_sid) { 170*21496Ssklower spp_istat.wrncon++; 171*21496Ssklower goto drop; 172*21496Ssklower } 173*21496Ssklower nsp->nsp_fport = si->si_sport; 174*21496Ssklower cb->s_timer[TCPT_REXMT] = 0; 175*21496Ssklower cb->s_timer[TCPT_KEEP] = TCPTV_KEEP; 176*21496Ssklower soisconnected(so); 177*21496Ssklower cb->s_state = TCPS_ESTABLISHED; 178*21496Ssklower } 179*21496Ssklower if (so->so_options & SO_DEBUG || traceallspps) 180*21496Ssklower spp_trace(SA_INPUT, ostate, cb, &spp_savesi, 0); 181*21496Ssklower 182*21496Ssklower m->m_len -= sizeof (struct idp); 183*21496Ssklower m->m_off += sizeof (struct idp); 184*21496Ssklower 185*21496Ssklower if (spp_reass(cb,si)) { 186*21496Ssklower spp_istat.bdreas++; 187*21496Ssklower goto drop; 188*21496Ssklower } 189*21496Ssklower spp_output(cb,(struct mbuf *)0); 190*21496Ssklower return; 191*21496Ssklower 192*21496Ssklower dropwithreset: 193*21496Ssklower if (dropsocket) 194*21496Ssklower (void) soabort(so); 195*21496Ssklower si->si_seq = ntohs(si->si_seq); 196*21496Ssklower si->si_ack = ntohs(si->si_ack); 197*21496Ssklower si->si_alo = ntohs(si->si_alo); 198*21496Ssklower ns_error(dtom(si), NS_ERR_NOSOCK, 0); 199*21496Ssklower if (cb->s_nspcb->nsp_socket->so_options & SO_DEBUG || traceallspps) 200*21496Ssklower spp_trace(SA_DROP, ostate, cb, &spp_savesi, 0); 201*21496Ssklower return; 202*21496Ssklower 203*21496Ssklower drop: 204*21496Ssklower bad: 205*21496Ssklower if (cb->s_nspcb->nsp_socket->so_options & SO_DEBUG || traceallspps) 206*21496Ssklower spp_trace(SA_DROP, ostate, cb, &spp_savesi, 0); 207*21496Ssklower m_freem(m); 208*21496Ssklower } 209*21496Ssklower 210*21496Ssklower /* 211*21496Ssklower * This is structurally similar to the tcp reassembly routine 212*21496Ssklower * but its function is somewhat different: It merely queues 213*21496Ssklower * packets up, and suppresses duplicates. 214*21496Ssklower */ 215*21496Ssklower spp_reass(cb,si) 216*21496Ssklower register struct sppcb *cb; 217*21496Ssklower register struct spidp *si; 218*21496Ssklower { 219*21496Ssklower register struct spidp_q *q; 220*21496Ssklower register struct mbuf *m; 221*21496Ssklower struct socket *so = cb->s_nspcb->nsp_socket; 222*21496Ssklower struct sockbuf *sb = & (so->so_rcv); 223*21496Ssklower char packetp = cb->s_flags & SF_HI; 224*21496Ssklower char wakeup = 0; 225*21496Ssklower 226*21496Ssklower 227*21496Ssklower if (si==SI(0)) 228*21496Ssklower goto present; 229*21496Ssklower /* 230*21496Ssklower * Update our news from them. 231*21496Ssklower */ 232*21496Ssklower if (si->si_cc & SP_SA) 233*21496Ssklower cb->s_flags |= SF_DELACK; 234*21496Ssklower if (SSEQ_GT(si->si_ack,cb->s_rack)) { 235*21496Ssklower cb->s_rack = si->si_ack; 236*21496Ssklower cb->s_timer[TCPT_REXMT] = 0; 237*21496Ssklower 238*21496Ssklower /* 239*21496Ssklower * If transmit timer is running and timed sequence 240*21496Ssklower * number was acked, update smoothed round trip time. 241*21496Ssklower */ 242*21496Ssklower if (cb->s_rtt && SSEQ_GT(si->si_ack, cb->s_rtseq)) { 243*21496Ssklower if (cb->s_srtt == 0) 244*21496Ssklower cb->s_srtt = cb->s_rtt; 245*21496Ssklower else 246*21496Ssklower cb->s_srtt = 247*21496Ssklower tcp_alpha * cb->s_srtt + 248*21496Ssklower (1 - tcp_alpha) * cb->s_rtt; 249*21496Ssklower cb->s_rtt = 0; 250*21496Ssklower } 251*21496Ssklower } 252*21496Ssklower if (SSEQ_GT(si->si_alo,cb->s_ralo)) { 253*21496Ssklower cb->s_ralo = si->si_alo; 254*21496Ssklower cb->s_timer[TCPT_PERSIST] = 0; 255*21496Ssklower } 256*21496Ssklower /* 257*21496Ssklower * If this is a system packet, we don't need to 258*21496Ssklower * queue it up, and won't update acknowledge # 259*21496Ssklower */ 260*21496Ssklower if (si->si_cc & SP_SP) 261*21496Ssklower return(0); 262*21496Ssklower 263*21496Ssklower /* 264*21496Ssklower * If this packet number has a sequence number less 265*21496Ssklower * than that of the first packet not yet seen coming 266*21496Ssklower * from them, this must be a duplicate, so drop. 267*21496Ssklower */ 268*21496Ssklower if (SSEQ_LT(si->si_seq,cb->s_ack)) 269*21496Ssklower return(1); 270*21496Ssklower /* 271*21496Ssklower * If this packet number is higher than that which 272*21496Ssklower * we have allocated refuse it, unless urgent 273*21496Ssklower */ 274*21496Ssklower if (SSEQ_GT(si->si_seq,cb->s_alo) && (!(si->si_cc & SP_OB))) { 275*21496Ssklower return(1); 276*21496Ssklower } 277*21496Ssklower /* 278*21496Ssklower * If this packet is urgent, inform process 279*21496Ssklower */ 280*21496Ssklower if (si->si_cc & SP_OB) { 281*21496Ssklower cb->s_iobc = ((char *)si)[1 + sizeof(*si)]; 282*21496Ssklower sohasoutofband(so); 283*21496Ssklower } 284*21496Ssklower 285*21496Ssklower /* 286*21496Ssklower * Loop through all packets queued up to insert in 287*21496Ssklower * appropriate sequence. 288*21496Ssklower */ 289*21496Ssklower 290*21496Ssklower for (q = cb->s_q.si_next; q!=&cb->s_q; q = q->si_next) { 291*21496Ssklower if (si->si_seq==SI(q)->si_seq) return(1); /*duplicate */ 292*21496Ssklower if (SSEQ_LT(si->si_seq,SI(q)->si_seq)) break; 293*21496Ssklower } 294*21496Ssklower insque(si,q->si_prev); 295*21496Ssklower 296*21496Ssklower present: 297*21496Ssklower #define SPINC sizeof(struct sphdr) 298*21496Ssklower /* 299*21496Ssklower * Loop through all packets queued up to update acknowledge 300*21496Ssklower * number, and present all acknowledged data to user; 301*21496Ssklower * If in packet interface mode, show packet headers. 302*21496Ssklower */ 303*21496Ssklower for (q = cb->s_q.si_next; q!=&cb->s_q; q = q->si_next) { 304*21496Ssklower if (SI(q)->si_seq==cb->s_ack) { 305*21496Ssklower cb->s_ack++; 306*21496Ssklower m = dtom(q); 307*21496Ssklower if (SI(q)->si_cc & SP_OB) { 308*21496Ssklower if (sb->sb_cc) 309*21496Ssklower so->so_oobmark = sb->sb_cc; 310*21496Ssklower else 311*21496Ssklower so->so_state |= SS_RCVATMARK; 312*21496Ssklower } 313*21496Ssklower q = q->si_prev; 314*21496Ssklower remque(q->si_next); 315*21496Ssklower wakeup = 1; 316*21496Ssklower if (packetp) { 317*21496Ssklower sbappendrecord(sb,m); 318*21496Ssklower } else { 319*21496Ssklower cb->s_rhdr = *mtod(m, struct sphdr *); 320*21496Ssklower m->m_off += SPINC; 321*21496Ssklower m->m_len -= SPINC; 322*21496Ssklower sbappend(sb,m); 323*21496Ssklower } 324*21496Ssklower } else 325*21496Ssklower break; 326*21496Ssklower } 327*21496Ssklower if (wakeup) sorwakeup(so); 328*21496Ssklower return(0); 329*21496Ssklower } 330*21496Ssklower 331*21496Ssklower spp_ctlinput(cmd, arg) 332*21496Ssklower int cmd; 333*21496Ssklower caddr_t arg; 334*21496Ssklower { 335*21496Ssklower struct ns_addr *na; 336*21496Ssklower extern u_char nsctlerrmap[]; 337*21496Ssklower extern spp_abort(); 338*21496Ssklower int type; 339*21496Ssklower 340*21496Ssklower if (cmd < 0 || cmd > PRC_NCMDS) 341*21496Ssklower return; 342*21496Ssklower type = NS_ERR_UNREACH_HOST; 343*21496Ssklower 344*21496Ssklower switch (cmd) { 345*21496Ssklower case PRC_ROUTEDEAD: 346*21496Ssklower case PRC_QUENCH: 347*21496Ssklower break; 348*21496Ssklower 349*21496Ssklower case PRC_IFDOWN: 350*21496Ssklower na = &((struct sockaddr_ns *)arg)->sns_addr; 351*21496Ssklower break; 352*21496Ssklower 353*21496Ssklower case PRC_HOSTDEAD: 354*21496Ssklower case PRC_HOSTUNREACH: 355*21496Ssklower na = (struct ns_addr *)arg; 356*21496Ssklower break; 357*21496Ssklower 358*21496Ssklower default: 359*21496Ssklower na = &((struct ns_errp *)arg)->ns_err_idp.idp_dna; 360*21496Ssklower type = ((struct ns_errp *)arg)->ns_err_num; 361*21496Ssklower type = ntohs(type); 362*21496Ssklower } 363*21496Ssklower switch (type) { 364*21496Ssklower case NS_ERR_UNREACH_HOST: 365*21496Ssklower case NS_ERR_NOSOCK: 366*21496Ssklower ns_pcbnotify(na, (int)nsctlerrmap[cmd], 367*21496Ssklower spp_abort, (long) 0); 368*21496Ssklower break; 369*21496Ssklower case NS_ERR_TOO_BIG: 370*21496Ssklower ns_pcbnotify(na, 0, spp_abort, (long)arg); 371*21496Ssklower } 372*21496Ssklower } 373*21496Ssklower 374*21496Ssklower int 375*21496Ssklower spp_fixmtu(nsp) 376*21496Ssklower register struct nspcb *nsp; 377*21496Ssklower { 378*21496Ssklower register struct sppcb *cb = (struct sppcb *)(nsp->nsp_pcb); 379*21496Ssklower register struct mbuf *m; 380*21496Ssklower register struct spidp *si; 381*21496Ssklower struct ns_errp *ep; 382*21496Ssklower struct sockbuf *sb; 383*21496Ssklower int badseq, len; 384*21496Ssklower struct mbuf *firstbad, *m0; 385*21496Ssklower 386*21496Ssklower if (cb) { 387*21496Ssklower /* 388*21496Ssklower * The notification that we have sent 389*21496Ssklower * too much is bad news -- we will 390*21496Ssklower * have to go through queued up so far 391*21496Ssklower * splitting ones which are too big and 392*21496Ssklower * reassigning sequence numbers and checksums. 393*21496Ssklower * we should then retransmit all packets from 394*21496Ssklower * one above the offending packet to the last one 395*21496Ssklower * we had sent (or our allocation) 396*21496Ssklower * then the offending one so that the any queued 397*21496Ssklower * data at our destination will be discarded. 398*21496Ssklower */ 399*21496Ssklower ep = (struct ns_errp *)nsp->nsp_notify_param; 400*21496Ssklower sb = &nsp->nsp_socket->so_snd; 401*21496Ssklower cb->s_mtu = ep->ns_err_param; 402*21496Ssklower badseq = SI(&ep->ns_err_idp)->si_seq; 403*21496Ssklower for (m = sb->sb_mb; m; m = m->m_act) { 404*21496Ssklower si = mtod(m, struct spidp *); 405*21496Ssklower if (si->si_seq == badseq) 406*21496Ssklower break; 407*21496Ssklower } 408*21496Ssklower if (m==0) return; 409*21496Ssklower firstbad = m; 410*21496Ssklower /*for (;;) {*/ 411*21496Ssklower /* calculate length */ 412*21496Ssklower for (m0 = m, len = 0; m ; m = m->m_next) 413*21496Ssklower len += m->m_len; 414*21496Ssklower if (len > cb->s_mtu) { 415*21496Ssklower } 416*21496Ssklower /* FINISH THIS 417*21496Ssklower } */ 418*21496Ssklower } 419*21496Ssklower } 420*21496Ssklower 421*21496Ssklower int spp_output_cnt = 0; 422*21496Ssklower spp_output(cb, m0) 423*21496Ssklower register struct sppcb *cb; 424*21496Ssklower struct mbuf *m0; 425*21496Ssklower { 426*21496Ssklower struct socket *so = cb->s_nspcb->nsp_socket; 427*21496Ssklower register struct mbuf *m; 428*21496Ssklower register struct spidp *si = (struct spidp *) 0; 429*21496Ssklower register struct sockbuf *sb = &(so->so_snd); 430*21496Ssklower register int len = 0; 431*21496Ssklower int flags, debit, mtu = cb->s_mtu; 432*21496Ssklower int error = 0; u_short lookfor = 0; 433*21496Ssklower struct mbuf *mprev; 434*21496Ssklower extern int idpcksum; 435*21496Ssklower 436*21496Ssklower if (m0) 437*21496Ssklower { 438*21496Ssklower for (m = m0; m ; m = m->m_next) { 439*21496Ssklower mprev = m; 440*21496Ssklower len += m->m_len; 441*21496Ssklower } 442*21496Ssklower if (len > mtu) { 443*21496Ssklower if (cb->s_flags & SF_PI) { 444*21496Ssklower m_freem(m0); 445*21496Ssklower return(EMSGSIZE); 446*21496Ssklower } else { 447*21496Ssklower int off = 0; 448*21496Ssklower while (len > mtu) { 449*21496Ssklower m = m_copy(m0, off, mtu); 450*21496Ssklower error = spp_output(cb, m); 451*21496Ssklower if (error) { 452*21496Ssklower m_freem(m0); 453*21496Ssklower return(error); 454*21496Ssklower } 455*21496Ssklower m_adj(m0, mtu); 456*21496Ssklower len -= mtu; 457*21496Ssklower } 458*21496Ssklower } 459*21496Ssklower } 460*21496Ssklower if (len & 1) { 461*21496Ssklower if (m->m_len + m->m_off < MMAXOFF) { 462*21496Ssklower m->m_len++; 463*21496Ssklower } else { 464*21496Ssklower struct mbuf *m1 = m_get(M_DONTWAIT, MT_DATA); 465*21496Ssklower 466*21496Ssklower if (m1 == 0) { 467*21496Ssklower m_freem(m0); 468*21496Ssklower return (ENOBUFS); 469*21496Ssklower } 470*21496Ssklower m1->m_len = 1; 471*21496Ssklower m1->m_off = MMAXOFF - 1; 472*21496Ssklower mprev->m_next = m1; 473*21496Ssklower } 474*21496Ssklower } 475*21496Ssklower m = m_get(M_DONTWAIT, MT_HEADER); 476*21496Ssklower if (m == 0) { 477*21496Ssklower m_freem(m0); 478*21496Ssklower return(ENOBUFS); 479*21496Ssklower } 480*21496Ssklower 481*21496Ssklower /* 482*21496Ssklower * Fill in mbuf with extended SP header 483*21496Ssklower * and addresses and length put into network format. 484*21496Ssklower */ 485*21496Ssklower m->m_off = MMAXOFF - sizeof (struct spidp); 486*21496Ssklower m->m_len = sizeof (struct spidp); 487*21496Ssklower m->m_next = m0; 488*21496Ssklower si = mtod(m, struct spidp *); 489*21496Ssklower *si = cb->s_shdr; 490*21496Ssklower if ((cb->s_flags & SF_PI) && (cb->s_flags & SF_HO)) { 491*21496Ssklower register struct sphdr *sh = mtod(m0, struct sphdr *); 492*21496Ssklower si->si_dt = sh->sp_dt; 493*21496Ssklower si->si_cc |= sh->sp_cc & SP_EM; 494*21496Ssklower m0->m_len -= sizeof (*sh); 495*21496Ssklower m0->m_off += sizeof (*sh); 496*21496Ssklower len -= sizeof (*sh); 497*21496Ssklower } 498*21496Ssklower len += sizeof(*si); 499*21496Ssklower si->si_len = htons(len); 500*21496Ssklower /* 501*21496Ssklower * queue stuff up for output 502*21496Ssklower */ 503*21496Ssklower sbappendrecord(sb,m); 504*21496Ssklower cb->s_seq++; 505*21496Ssklower } 506*21496Ssklower output: 507*21496Ssklower /* 508*21496Ssklower * update window 509*21496Ssklower */ 510*21496Ssklower { 511*21496Ssklower register struct sockbuf *sb = &so->so_rcv; 512*21496Ssklower int credit = ((sb->sb_mbmax - sb->sb_mbcnt) / cb->s_mtu); 513*21496Ssklower int alo = cb->s_ack + credit; 514*21496Ssklower 515*21496Ssklower if (cb->s_alo < alo) cb->s_alo = alo; 516*21496Ssklower } 517*21496Ssklower 518*21496Ssklower if (cb->s_oobflags & SF_SOOB) { 519*21496Ssklower /* 520*21496Ssklower * must transmit this out of band packet 521*21496Ssklower */ 522*21496Ssklower cb->s_oobflags &= ~ SF_SOOB; 523*21496Ssklower } else { 524*21496Ssklower /* 525*21496Ssklower * Decide what to transmit: 526*21496Ssklower * If we have a new packet, send that 527*21496Ssklower * (So long as it is in our allocation) 528*21496Ssklower * If it is time to retransmit a packet, 529*21496Ssklower * send that. 530*21496Ssklower * Otherwise, see if it time to bang on them 531*21496Ssklower * to ask for our current allocation. 532*21496Ssklower */ 533*21496Ssklower if (SSEQ_LT(cb->s_snt, cb->s_ralo)) 534*21496Ssklower lookfor = cb->s_snt + 1; 535*21496Ssklower else if (cb->s_force==(1+TCPT_REXMT)) { 536*21496Ssklower lookfor = cb->s_rack; 537*21496Ssklower } else if (SSEQ_LT(cb->s_ralo, cb->s_seq)) { 538*21496Ssklower lookfor = 0; 539*21496Ssklower if (cb->s_timer[TCPT_PERSIST]==0) { 540*21496Ssklower spp_setpersist(cb); 541*21496Ssklower } 542*21496Ssklower } 543*21496Ssklower m = sb->sb_mb; 544*21496Ssklower while( m ) { 545*21496Ssklower si = mtod(m, struct spidp *); 546*21496Ssklower m = m->m_act; 547*21496Ssklower if (SSEQ_LT(si->si_seq, cb->s_rack)) { 548*21496Ssklower if ((sb->sb_flags & SB_WAIT) 549*21496Ssklower || so->so_snd.sb_sel) 550*21496Ssklower sowwakeup(so); 551*21496Ssklower sbdroprecord(sb); 552*21496Ssklower si = 0; 553*21496Ssklower continue; 554*21496Ssklower } 555*21496Ssklower if (SSEQ_LT(si->si_seq, lookfor)) 556*21496Ssklower continue; 557*21496Ssklower break; 558*21496Ssklower } 559*21496Ssklower if (si && (si->si_seq != lookfor)) si = 0; 560*21496Ssklower } 561*21496Ssklower cb->s_want = lookfor; 562*21496Ssklower 563*21496Ssklower if (si) { 564*21496Ssklower /* 565*21496Ssklower * must make a copy of this packet for 566*21496Ssklower * idp_output to monkey with 567*21496Ssklower */ 568*21496Ssklower m = dtom(si); 569*21496Ssklower m0 = m_copy(m, 0, M_COPYALL); 570*21496Ssklower m = m0; 571*21496Ssklower si = mtod(m, struct spidp *); 572*21496Ssklower } else if (cb->s_force || cb->s_flags & SF_AK) { 573*21496Ssklower /* 574*21496Ssklower * Must send an acknowledgement or a probe 575*21496Ssklower */ 576*21496Ssklower m = m_get(M_DONTWAIT, MT_HEADER); 577*21496Ssklower if (m == 0) 578*21496Ssklower return(ENOBUFS); 579*21496Ssklower /* 580*21496Ssklower * Fill in mbuf with extended SP header 581*21496Ssklower * and addresses and length put into network format. 582*21496Ssklower */ 583*21496Ssklower m->m_off = MMAXOFF - sizeof (struct spidp); 584*21496Ssklower m->m_len = sizeof (*si); 585*21496Ssklower m->m_next = 0; 586*21496Ssklower si = mtod(m, struct spidp *); 587*21496Ssklower *si = cb->s_shdr; 588*21496Ssklower si->si_seq = cb->s_snt + 1; 589*21496Ssklower len = sizeof (*si); 590*21496Ssklower si->si_len = htons((u_short)len); 591*21496Ssklower si->si_cc |= SP_SP; 592*21496Ssklower cb->s_flags &= ~SF_AK; 593*21496Ssklower } 594*21496Ssklower /* 595*21496Ssklower * Stuff checksum and output datagram. 596*21496Ssklower */ 597*21496Ssklower if (si) { 598*21496Ssklower /* 599*21496Ssklower * If we are almost out of allocation 600*21496Ssklower * or one of the timers has gone off 601*21496Ssklower * request an ack. 602*21496Ssklower */ 603*21496Ssklower if (SSEQ_GEQ(cb->s_seq,cb->s_ralo)) 604*21496Ssklower si->si_cc |= SP_SA; 605*21496Ssklower if (cb->s_force) { 606*21496Ssklower si->si_cc |= SP_SA; 607*21496Ssklower cb->s_force = 0; 608*21496Ssklower } 609*21496Ssklower /* if this is a new packet (and not a system packet) 610*21496Ssklower * and we are not currently timing anything 611*21496Ssklower * time this one and ask for an ack 612*21496Ssklower */ 613*21496Ssklower if (SSEQ_LT(cb->s_snt,si->si_seq) && 614*21496Ssklower (!(si->si_cc & SP_SP))) { 615*21496Ssklower cb->s_snt = si->si_seq; 616*21496Ssklower if (cb->s_rtt==0) { 617*21496Ssklower cb->s_rtseq = si->si_seq; 618*21496Ssklower cb->s_rtt = 1; 619*21496Ssklower si->si_cc |= SP_SA; 620*21496Ssklower } 621*21496Ssklower /* 622*21496Ssklower * If the retransmit timer has not been set 623*21496Ssklower * and this is a real packet 624*21496Ssklower * then start the retransmit timer 625*21496Ssklower */ 626*21496Ssklower if (cb->s_timer[TCPT_REXMT]==0) { 627*21496Ssklower TCPT_RANGESET(cb->s_timer[TCPT_REXMT], 628*21496Ssklower tcp_beta * cb->s_srtt, TCPTV_MIN, 629*21496Ssklower TCPTV_MAX); 630*21496Ssklower cb->s_rxtshift = 0; 631*21496Ssklower } 632*21496Ssklower } 633*21496Ssklower si->si_seq = htons(si->si_seq); 634*21496Ssklower si->si_alo = htons(cb->s_alo); 635*21496Ssklower si->si_ack = htons(cb->s_ack); 636*21496Ssklower 637*21496Ssklower if (idpcksum) { 638*21496Ssklower si->si_sum = 0; 639*21496Ssklower len = ((len - 1) | 1) + 1; 640*21496Ssklower si->si_sum = ns_cksum(dtom(si), len); 641*21496Ssklower } else 642*21496Ssklower si->si_sum = 0xffff; 643*21496Ssklower 644*21496Ssklower if (so->so_options & SO_DEBUG || traceallspps) 645*21496Ssklower spp_trace(SA_OUTPUT, cb->s_state, cb, si, 0); 646*21496Ssklower spp_output_cnt++; 647*21496Ssklower if (so->so_options & SO_DONTROUTE) 648*21496Ssklower error = ns_output(m, (struct route *)0, NS_ROUTETOIF); 649*21496Ssklower else 650*21496Ssklower error = ns_output(m, &cb->s_nspcb->nsp_route, 0); 651*21496Ssklower if (traceallspps && sppconsdebug) { 652*21496Ssklower printf("spp_out: %x\n", error); 653*21496Ssklower } 654*21496Ssklower return(error); 655*21496Ssklower } 656*21496Ssklower if (so->so_options & SO_DEBUG || traceallspps) 657*21496Ssklower spp_trace(SA_OUTPUT, cb->s_state, cb, si, 0); 658*21496Ssklower return(error); 659*21496Ssklower } 660*21496Ssklower 661*21496Ssklower /*ARGSUSED*/ 662*21496Ssklower spp_ctloutput(req, so, level, name, value) 663*21496Ssklower int req; 664*21496Ssklower struct socket *so; 665*21496Ssklower int name; 666*21496Ssklower struct mbuf **value; 667*21496Ssklower { 668*21496Ssklower register struct mbuf *m; 669*21496Ssklower struct nspcb *nsp = sotonspcb(so); 670*21496Ssklower register struct sppcb *cb; 671*21496Ssklower int mask, error = 0; 672*21496Ssklower 673*21496Ssklower if (level != NSPROTO_SPP) { 674*21496Ssklower /* This will have to be changed when we do more general 675*21496Ssklower stacking of protocols */ 676*21496Ssklower return(idp_ctloutput(req, so, level, name, value)); 677*21496Ssklower } 678*21496Ssklower if (nsp == NULL) { 679*21496Ssklower error = EINVAL; 680*21496Ssklower goto release; 681*21496Ssklower } else 682*21496Ssklower cb = nstosppcb(nsp); 683*21496Ssklower 684*21496Ssklower switch (req) { 685*21496Ssklower case PRCO_GETOPT: 686*21496Ssklower if (value==NULL) { 687*21496Ssklower error = EINVAL; 688*21496Ssklower goto release; 689*21496Ssklower } 690*21496Ssklower m = m_get(M_DONTWAIT, MT_DATA); 691*21496Ssklower switch (name) { 692*21496Ssklower case SO_HEADERS_ON_INPUT: 693*21496Ssklower mask = SF_HI; 694*21496Ssklower goto get_flags; 695*21496Ssklower case SO_HEADERS_ON_OUTPUT: 696*21496Ssklower mask = SF_HO; 697*21496Ssklower get_flags: 698*21496Ssklower m->m_len = sizeof(short); 699*21496Ssklower m->m_off = MMAXOFF - sizeof(short); 700*21496Ssklower *mtod(m, short *) = cb->s_flags & mask; 701*21496Ssklower break; 702*21496Ssklower case SO_LAST_HEADER: 703*21496Ssklower m->m_len = sizeof(struct sphdr); 704*21496Ssklower m->m_off = MMAXOFF - sizeof(struct sphdr); 705*21496Ssklower *mtod(m, struct sphdr *) = cb->s_rhdr; 706*21496Ssklower break; 707*21496Ssklower case SO_DEFAULT_HEADERS: 708*21496Ssklower m->m_len = sizeof(struct spidp); 709*21496Ssklower m->m_off = MMAXOFF - sizeof(struct sphdr); 710*21496Ssklower *mtod(m, struct sphdr *) = cb->s_shdr.si_s; 711*21496Ssklower } 712*21496Ssklower *value = m; 713*21496Ssklower break; 714*21496Ssklower case PRCO_SETOPT: 715*21496Ssklower switch (name) { 716*21496Ssklower int mask, *ok; 717*21496Ssklower 718*21496Ssklower case SO_HEADERS_ON_INPUT: 719*21496Ssklower mask = SF_HI; 720*21496Ssklower goto set_head; 721*21496Ssklower case SO_HEADERS_ON_OUTPUT: 722*21496Ssklower mask = SF_HO; 723*21496Ssklower set_head: 724*21496Ssklower if (value && *value) { 725*21496Ssklower ok = mtod(*value, int *); 726*21496Ssklower if (*ok) 727*21496Ssklower cb->s_flags |= mask; 728*21496Ssklower else 729*21496Ssklower cb->s_flags &= ~mask; 730*21496Ssklower } else error = EINVAL; 731*21496Ssklower break; 732*21496Ssklower case SO_DEFAULT_HEADERS: 733*21496Ssklower { 734*21496Ssklower register struct sphdr *sp 735*21496Ssklower = mtod(*value, struct sphdr *); 736*21496Ssklower cb->s_dt = sp->sp_dt; 737*21496Ssklower cb->s_cc = sp->sp_cc & SP_EM; 738*21496Ssklower } 739*21496Ssklower } 740*21496Ssklower if (value && *value) 741*21496Ssklower m_freem(*value); 742*21496Ssklower break; 743*21496Ssklower } 744*21496Ssklower release: 745*21496Ssklower return(error); 746*21496Ssklower } 747*21496Ssklower 748*21496Ssklower /*ARGSUSED*/ 749*21496Ssklower spp_usrreq(so, req, m, nam, rights) 750*21496Ssklower struct socket *so; 751*21496Ssklower int req; 752*21496Ssklower struct mbuf *m, *nam, *rights; 753*21496Ssklower { 754*21496Ssklower struct nspcb *nsp = sotonspcb(so); 755*21496Ssklower register struct sppcb *cb; 756*21496Ssklower int s = splnet(); 757*21496Ssklower int error = 0, ostate; 758*21496Ssklower 759*21496Ssklower if (req == PRU_CONTROL) 760*21496Ssklower return (ns_control(so, (int)m, (caddr_t)nam, 761*21496Ssklower (struct ifnet *)rights)); 762*21496Ssklower if (rights && rights->m_len) { 763*21496Ssklower error = EINVAL; 764*21496Ssklower goto release; 765*21496Ssklower } 766*21496Ssklower if (nsp == NULL) { 767*21496Ssklower if (req != PRU_ATTACH) { 768*21496Ssklower error = EINVAL; 769*21496Ssklower goto release; 770*21496Ssklower } 771*21496Ssklower } else 772*21496Ssklower cb = nstosppcb(nsp); 773*21496Ssklower 774*21496Ssklower ostate = cb ? cb->s_state : 0; 775*21496Ssklower 776*21496Ssklower switch (req) { 777*21496Ssklower case PRU_ATTACH: 778*21496Ssklower if (nsp != NULL) { 779*21496Ssklower error = EISCONN; 780*21496Ssklower break; 781*21496Ssklower } 782*21496Ssklower error = ns_pcballoc(so, &nspcb); 783*21496Ssklower if (error) 784*21496Ssklower break; 785*21496Ssklower error = soreserve(so, 2048, 2048); 786*21496Ssklower if (error) 787*21496Ssklower break; 788*21496Ssklower nsp = sotonspcb(so); 789*21496Ssklower { 790*21496Ssklower struct mbuf *mm = m_getclr(M_DONTWAIT,MT_PCB); 791*21496Ssklower 792*21496Ssklower if (mm==NULL) { 793*21496Ssklower error = ENOBUFS; 794*21496Ssklower break; 795*21496Ssklower } 796*21496Ssklower cb = mtod(mm, struct sppcb *); 797*21496Ssklower cb->s_state = TCPS_LISTEN; 798*21496Ssklower cb->s_flags = SF_HI | SF_HO; 799*21496Ssklower cb->s_snt = -1; 800*21496Ssklower cb->s_q.si_next = cb->s_q.si_prev = &cb->s_q; 801*21496Ssklower cb->s_nspcb = nsp; 802*21496Ssklower nsp->nsp_pcb = (caddr_t) cb; 803*21496Ssklower } 804*21496Ssklower break; 805*21496Ssklower 806*21496Ssklower case PRU_DETACH: 807*21496Ssklower if (nsp == NULL) { 808*21496Ssklower error = ENOTCONN; 809*21496Ssklower break; 810*21496Ssklower } 811*21496Ssklower if (cb->s_state > TCPS_LISTEN) 812*21496Ssklower cb = spp_disconnect(cb); 813*21496Ssklower else 814*21496Ssklower cb = spp_close(cb); 815*21496Ssklower break; 816*21496Ssklower 817*21496Ssklower case PRU_BIND: 818*21496Ssklower error = ns_pcbbind(nsp, nam); 819*21496Ssklower break; 820*21496Ssklower 821*21496Ssklower case PRU_LISTEN: 822*21496Ssklower if (nsp->nsp_lport == 0) 823*21496Ssklower error = ns_pcbbind(nsp, (struct mbuf *)0); 824*21496Ssklower if (error == 0) 825*21496Ssklower cb->s_state = TCPS_LISTEN; 826*21496Ssklower break; 827*21496Ssklower 828*21496Ssklower /* 829*21496Ssklower * Initiate connection to peer. 830*21496Ssklower * Enter SYN_SENT state, and mark socket as connecting. 831*21496Ssklower * Start keep-alive timer, setup prototype header, 832*21496Ssklower * Send initial system packet requesting connection. 833*21496Ssklower */ 834*21496Ssklower case PRU_CONNECT: 835*21496Ssklower if (nsp->nsp_lport == 0) { 836*21496Ssklower error = ns_pcbbind(nsp, (struct mbuf *)0); 837*21496Ssklower if (error) 838*21496Ssklower break; 839*21496Ssklower } 840*21496Ssklower error = ns_pcbconnect(nsp, nam); 841*21496Ssklower if (error) 842*21496Ssklower break; 843*21496Ssklower soisconnecting(so); 844*21496Ssklower cb->s_state = TCPS_SYN_SENT; 845*21496Ssklower cb->s_did = 0; 846*21496Ssklower spp_template(cb); 847*21496Ssklower cb->s_timer[TCPT_KEEP] = TCPTV_KEEP; 848*21496Ssklower cb->s_force = 1 + TCPTV_KEEP; 849*21496Ssklower /* 850*21496Ssklower * Other party is required to respond to 851*21496Ssklower * the port I send from, but he is not 852*21496Ssklower * required to answer from where I am sending to, 853*21496Ssklower * so allow wildcarding. 854*21496Ssklower * original port I am sending to is still saved in 855*21496Ssklower * cb->s_dport. 856*21496Ssklower */ 857*21496Ssklower nsp->nsp_fport = 0; 858*21496Ssklower error = spp_output(cb, (struct mbuf *) 0); 859*21496Ssklower break; 860*21496Ssklower 861*21496Ssklower case PRU_CONNECT2: 862*21496Ssklower error = EOPNOTSUPP; 863*21496Ssklower break; 864*21496Ssklower 865*21496Ssklower /* 866*21496Ssklower * We may decide later to implement connection closing 867*21496Ssklower * handshaking at the spp level optionally. 868*21496Ssklower * here is the hook to do it: 869*21496Ssklower */ 870*21496Ssklower case PRU_DISCONNECT: 871*21496Ssklower cb = spp_disconnect(cb); 872*21496Ssklower break; 873*21496Ssklower 874*21496Ssklower /* 875*21496Ssklower * Accept a connection. Essentially all the work is 876*21496Ssklower * done at higher levels; just return the address 877*21496Ssklower * of the peer, storing through addr. 878*21496Ssklower */ 879*21496Ssklower case PRU_ACCEPT: { 880*21496Ssklower struct sockaddr_ns *sns = mtod(nam, struct sockaddr_ns *); 881*21496Ssklower 882*21496Ssklower nam->m_len = sizeof (struct sockaddr_ns); 883*21496Ssklower sns->sns_family = AF_NS; 884*21496Ssklower sns->sns_addr = nsp->nsp_faddr; 885*21496Ssklower break; 886*21496Ssklower } 887*21496Ssklower 888*21496Ssklower case PRU_SHUTDOWN: 889*21496Ssklower socantsendmore(so); 890*21496Ssklower cb = spp_usrclosed(cb); 891*21496Ssklower if (cb) 892*21496Ssklower error = spp_output(cb, (struct mbuf *) 0); 893*21496Ssklower break; 894*21496Ssklower 895*21496Ssklower /* 896*21496Ssklower * After a receive, possibly send acknowledgment 897*21496Ssklower * updating allocation. 898*21496Ssklower */ 899*21496Ssklower case PRU_RCVD: 900*21496Ssklower (void) spp_output(cb, (struct mbuf *) 0); 901*21496Ssklower break; 902*21496Ssklower 903*21496Ssklower case PRU_SEND: 904*21496Ssklower error = spp_output(cb, m); 905*21496Ssklower m = NULL; 906*21496Ssklower break; 907*21496Ssklower 908*21496Ssklower case PRU_ABORT: 909*21496Ssklower spp_drop(cb, ECONNABORTED); 910*21496Ssklower break; 911*21496Ssklower 912*21496Ssklower case PRU_SENSE: 913*21496Ssklower case PRU_CONTROL: 914*21496Ssklower m = NULL; 915*21496Ssklower error = EOPNOTSUPP; 916*21496Ssklower break; 917*21496Ssklower 918*21496Ssklower case PRU_RCVOOB: 919*21496Ssklower if ( ! (cb->s_oobflags & SF_IOOB) ) { 920*21496Ssklower error = EWOULDBLOCK; 921*21496Ssklower break; 922*21496Ssklower } 923*21496Ssklower m->m_len = 1; 924*21496Ssklower *mtod(m, caddr_t) = cb->s_iobc; 925*21496Ssklower cb->s_oobflags &= ~ SF_IOOB; 926*21496Ssklower break; 927*21496Ssklower 928*21496Ssklower case PRU_SENDOOB: 929*21496Ssklower if (sbspace(&so->so_snd) < -512) { 930*21496Ssklower m_freem(m); 931*21496Ssklower error = ENOBUFS; 932*21496Ssklower break; 933*21496Ssklower } 934*21496Ssklower cb->s_oobflags |= SF_SOOB; 935*21496Ssklower error = spp_output(cb, m); 936*21496Ssklower m = NULL; 937*21496Ssklower cb->s_oobflags &= ~SF_SOOB; 938*21496Ssklower break; 939*21496Ssklower 940*21496Ssklower case PRU_SOCKADDR: 941*21496Ssklower ns_setsockaddr(nsp, nam); 942*21496Ssklower break; 943*21496Ssklower 944*21496Ssklower case PRU_PEERADDR: 945*21496Ssklower ns_setpeeraddr(nsp, nam); 946*21496Ssklower break; 947*21496Ssklower 948*21496Ssklower case PRU_SLOWTIMO: 949*21496Ssklower cb = spp_timers(cb, (int)nam); 950*21496Ssklower break; 951*21496Ssklower 952*21496Ssklower case PRU_FASTTIMO: 953*21496Ssklower case PRU_PROTORCV: 954*21496Ssklower case PRU_PROTOSEND: 955*21496Ssklower error = EOPNOTSUPP; 956*21496Ssklower break; 957*21496Ssklower 958*21496Ssklower default: 959*21496Ssklower panic("sp_usrreq"); 960*21496Ssklower } 961*21496Ssklower if (cb && (so->so_options & SO_DEBUG || traceallspps)) 962*21496Ssklower spp_trace(SA_USER, ostate, cb, (struct sphdr *)0, req); 963*21496Ssklower release: 964*21496Ssklower if (m != NULL) 965*21496Ssklower m_freem(m); 966*21496Ssklower splx(s); 967*21496Ssklower return (error); 968*21496Ssklower } 969*21496Ssklower 970*21496Ssklower spp_usrreq_sp(so, req, m, nam, rights) 971*21496Ssklower struct socket *so; 972*21496Ssklower int req; 973*21496Ssklower struct mbuf *m, *nam, *rights; 974*21496Ssklower { 975*21496Ssklower int error = spp_usrreq(so, req, m, nam, rights); 976*21496Ssklower 977*21496Ssklower if (req==PRU_ATTACH && error==0) { 978*21496Ssklower struct nspcb *nsp = sotonspcb(so); 979*21496Ssklower ((struct sppcb *)nsp->nsp_pcb)->s_flags |= 980*21496Ssklower (SF_HI | SF_HO | SF_PI); 981*21496Ssklower } 982*21496Ssklower return(error); 983*21496Ssklower } 984*21496Ssklower 985*21496Ssklower /* 986*21496Ssklower * Create template to be used to send spp packets on a connection. 987*21496Ssklower * Called after host entry created, fills 988*21496Ssklower * in a skeletal spp header (choosing connection id), 989*21496Ssklower * minimizing the amount of work necessary when the connection is used. 990*21496Ssklower */ 991*21496Ssklower spp_template(cb) 992*21496Ssklower struct sppcb *cb; 993*21496Ssklower { 994*21496Ssklower register struct nspcb *nsp = cb->s_nspcb; 995*21496Ssklower register struct spidp *n = &(cb->s_shdr); 996*21496Ssklower 997*21496Ssklower cb->s_mtu = 1024; 998*21496Ssklower n->si_pt = NSPROTO_SPP; 999*21496Ssklower n->si_sna = nsp->nsp_laddr; 1000*21496Ssklower n->si_dna = nsp->nsp_faddr; 1001*21496Ssklower n->si_sid = htons(spp_iss); 1002*21496Ssklower spp_iss += SPP_ISSINCR/2; 1003*21496Ssklower n->si_alo = 1; 1004*21496Ssklower } 1005*21496Ssklower 1006*21496Ssklower /* 1007*21496Ssklower * Close a SPIP control block: 1008*21496Ssklower * discard spp control block itself 1009*21496Ssklower * discard ns protocol control block 1010*21496Ssklower * wake up any sleepers 1011*21496Ssklower */ 1012*21496Ssklower struct sppcb * 1013*21496Ssklower spp_close(cb) 1014*21496Ssklower register struct sppcb *cb; 1015*21496Ssklower { 1016*21496Ssklower register struct spidp_q *s; 1017*21496Ssklower struct nspcb *nsp = cb->s_nspcb; 1018*21496Ssklower struct socket *so = nsp->nsp_socket; 1019*21496Ssklower register struct mbuf *m; 1020*21496Ssklower 1021*21496Ssklower s = cb->s_q.si_next; 1022*21496Ssklower while (s != &(cb->s_q)) { 1023*21496Ssklower s = s->si_next; 1024*21496Ssklower m = dtom(s->si_prev); 1025*21496Ssklower remque(s->si_prev); 1026*21496Ssklower m_freem(m); 1027*21496Ssklower } 1028*21496Ssklower (void) m_free(dtom(cb)); 1029*21496Ssklower nsp->nsp_pcb = 0; 1030*21496Ssklower soisdisconnected(so); 1031*21496Ssklower ns_pcbdetach(nsp); 1032*21496Ssklower return((struct sppcb *)0); 1033*21496Ssklower } 1034*21496Ssklower /* 1035*21496Ssklower * Someday we may do level 3 handshaking 1036*21496Ssklower * to close a connection or send a xerox style error. 1037*21496Ssklower * For now, just close. 1038*21496Ssklower */ 1039*21496Ssklower struct sppcb * 1040*21496Ssklower spp_usrclosed(cb) 1041*21496Ssklower register struct sppcb *cb; 1042*21496Ssklower { 1043*21496Ssklower return(spp_close(cb)); 1044*21496Ssklower } 1045*21496Ssklower struct sppcb * 1046*21496Ssklower spp_disconnect(cb) 1047*21496Ssklower register struct sppcb *cb; 1048*21496Ssklower { 1049*21496Ssklower return(spp_close(cb)); 1050*21496Ssklower } 1051*21496Ssklower /* 1052*21496Ssklower * Drop connection, reporting 1053*21496Ssklower * the specified error. 1054*21496Ssklower */ 1055*21496Ssklower struct sppcb * 1056*21496Ssklower spp_drop(cb, errno) 1057*21496Ssklower register struct sppcb *cb; 1058*21496Ssklower int errno; 1059*21496Ssklower { 1060*21496Ssklower struct socket *so = cb->s_nspcb->nsp_socket; 1061*21496Ssklower 1062*21496Ssklower /* 1063*21496Ssklower * someday, in the xerox world 1064*21496Ssklower * we will generate error protocol packets 1065*21496Ssklower * announcing that the socket has gone away. 1066*21496Ssklower */ 1067*21496Ssklower /*if (TCPS_HAVERCVDSYN(tp->t_state)) { 1068*21496Ssklower tp->t_state = TCPS_CLOSED; 1069*21496Ssklower (void) tcp_output(tp); 1070*21496Ssklower }*/ 1071*21496Ssklower so->so_error = errno; 1072*21496Ssklower return (spp_close(cb)); 1073*21496Ssklower } 1074*21496Ssklower 1075*21496Ssklower spp_abort(nsp) 1076*21496Ssklower struct nspcb *nsp; 1077*21496Ssklower { 1078*21496Ssklower 1079*21496Ssklower spp_close((struct sppcb *)nsp->nsp_pcb); 1080*21496Ssklower } 1081*21496Ssklower 1082*21496Ssklower spp_setpersist(cb) 1083*21496Ssklower register struct sppcb *cb; 1084*21496Ssklower { 1085*21496Ssklower 1086*21496Ssklower /*if (cb->s_timer[TCPT_REXMT]) 1087*21496Ssklower panic("spp_output REXMT");*/ 1088*21496Ssklower /* 1089*21496Ssklower * Start/restart persistance timer. 1090*21496Ssklower */ 1091*21496Ssklower TCPT_RANGESET(cb->s_timer[TCPT_PERSIST], 1092*21496Ssklower ((int)(tcp_beta * cb->s_srtt)) << cb->s_rxtshift, 1093*21496Ssklower TCPTV_PERSMIN, TCPTV_MAX); 1094*21496Ssklower cb->s_rxtshift++; 1095*21496Ssklower if (cb->s_rxtshift >= TCP_MAXRXTSHIFT) 1096*21496Ssklower cb->s_rxtshift = 0; 1097*21496Ssklower } 1098*21496Ssklower /* 1099*21496Ssklower * Fast timeout routine for processing delayed acks 1100*21496Ssklower */ 1101*21496Ssklower int spp_ftcnt; 1102*21496Ssklower spp_fasttimo() 1103*21496Ssklower { 1104*21496Ssklower register struct nspcb *nsp; 1105*21496Ssklower register struct sppcb *cb; 1106*21496Ssklower int s = splnet(); 1107*21496Ssklower 1108*21496Ssklower nsp = nspcb.nsp_next; 1109*21496Ssklower spp_ftcnt++; 1110*21496Ssklower if (nsp) 1111*21496Ssklower for (; nsp != &nspcb; nsp = nsp->nsp_next) 1112*21496Ssklower if ((cb = (struct sppcb *)nsp->nsp_pcb) && 1113*21496Ssklower (cb->s_flags & SF_DELACK)) { 1114*21496Ssklower cb->s_flags &= ~SF_DELACK; 1115*21496Ssklower cb->s_flags |= SF_AK; 1116*21496Ssklower (void) spp_output(cb, (struct mbuf *) 0); 1117*21496Ssklower } 1118*21496Ssklower splx(s); 1119*21496Ssklower } 1120*21496Ssklower 1121*21496Ssklower /* 1122*21496Ssklower * spp protocol timeout routine called every 500 ms. 1123*21496Ssklower * Updates the timers in all active pcb's and 1124*21496Ssklower * causes finite state machine actions if timers expire. 1125*21496Ssklower */ 1126*21496Ssklower spp_slowtimo() 1127*21496Ssklower { 1128*21496Ssklower register struct nspcb *ip, *ipnxt; 1129*21496Ssklower register struct sppcb *cb; 1130*21496Ssklower int s = splnet(); 1131*21496Ssklower register int i; 1132*21496Ssklower 1133*21496Ssklower /* 1134*21496Ssklower * Search through tcb's and update active timers. 1135*21496Ssklower */ 1136*21496Ssklower ip = nspcb.nsp_next; 1137*21496Ssklower if (ip == 0) { 1138*21496Ssklower splx(s); 1139*21496Ssklower return; 1140*21496Ssklower } 1141*21496Ssklower while (ip != &nspcb) { 1142*21496Ssklower cb = nstosppcb(ip); 1143*21496Ssklower ipnxt = ip->nsp_next; 1144*21496Ssklower if (cb == 0) 1145*21496Ssklower goto tpgone; 1146*21496Ssklower for (i = 0; i < TCPT_NTIMERS; i++) { 1147*21496Ssklower if (cb->s_timer[i] && --cb->s_timer[i] == 0) { 1148*21496Ssklower (void) spp_usrreq(cb->s_nspcb->nsp_socket, 1149*21496Ssklower PRU_SLOWTIMO, (struct mbuf *)0, 1150*21496Ssklower (struct mbuf *)i, (struct mbuf *)0); 1151*21496Ssklower if (ipnxt->nsp_prev != ip) 1152*21496Ssklower goto tpgone; 1153*21496Ssklower } 1154*21496Ssklower } 1155*21496Ssklower cb->s_idle++; 1156*21496Ssklower if (cb->s_rtt) 1157*21496Ssklower cb->s_rtt++; 1158*21496Ssklower tpgone: 1159*21496Ssklower ip = ipnxt; 1160*21496Ssklower } 1161*21496Ssklower spp_iss += SPP_ISSINCR/PR_SLOWHZ; /* increment iss */ 1162*21496Ssklower splx(s); 1163*21496Ssklower } 1164*21496Ssklower 1165*21496Ssklower float spp_backoff[TCP_MAXRXTSHIFT] = 1166*21496Ssklower { 1.0, 1.2, 1.4, 1.7, 2.0, 3.0, 5.0, 8.0, 16.0, 32.0 }; 1167*21496Ssklower extern int tcpexprexmtbackoff; 1168*21496Ssklower /* 1169*21496Ssklower * TCP timer processing. 1170*21496Ssklower */ 1171*21496Ssklower struct sppcb * 1172*21496Ssklower spp_timers(cb, timer) 1173*21496Ssklower register struct sppcb *cb; 1174*21496Ssklower int timer; 1175*21496Ssklower { 1176*21496Ssklower 1177*21496Ssklower cb->s_force = 1 + timer; 1178*21496Ssklower switch (timer) { 1179*21496Ssklower 1180*21496Ssklower /* 1181*21496Ssklower * 2 MSL timeout in shutdown went off. Delete connection 1182*21496Ssklower * control block. 1183*21496Ssklower */ 1184*21496Ssklower case TCPT_2MSL: 1185*21496Ssklower cb = spp_close(cb); 1186*21496Ssklower break; 1187*21496Ssklower 1188*21496Ssklower /* 1189*21496Ssklower * Retransmission timer went off. Message has not 1190*21496Ssklower * been acked within retransmit interval. Back off 1191*21496Ssklower * to a longer retransmit interval and retransmit all 1192*21496Ssklower * unacknowledged messages in the window. 1193*21496Ssklower */ 1194*21496Ssklower case TCPT_REXMT: 1195*21496Ssklower cb->s_rxtshift++; 1196*21496Ssklower if (cb->s_rxtshift > TCP_MAXRXTSHIFT) { 1197*21496Ssklower cb = spp_drop(cb, ETIMEDOUT); 1198*21496Ssklower break; 1199*21496Ssklower } 1200*21496Ssklower (void) spp_output(cb, (struct mbuf *) 0); 1201*21496Ssklower TCPT_RANGESET(cb->s_timer[TCPT_REXMT], 1202*21496Ssklower (int)cb->s_srtt, TCPTV_MIN, TCPTV_MAX); 1203*21496Ssklower if (tcpexprexmtbackoff) { 1204*21496Ssklower TCPT_RANGESET(cb->s_timer[TCPT_REXMT], 1205*21496Ssklower cb->s_timer[TCPT_REXMT] << cb->s_rxtshift, 1206*21496Ssklower TCPTV_MIN, TCPTV_MAX); 1207*21496Ssklower } else { 1208*21496Ssklower TCPT_RANGESET(cb->s_timer[TCPT_REXMT], 1209*21496Ssklower cb->s_timer[TCPT_REXMT] * 1210*21496Ssklower spp_backoff[cb->s_rxtshift - 1], 1211*21496Ssklower TCPTV_MIN, TCPTV_MAX); 1212*21496Ssklower } 1213*21496Ssklower break; 1214*21496Ssklower 1215*21496Ssklower /* 1216*21496Ssklower * Persistance timer into zero window. 1217*21496Ssklower * Force a probe to be sent. 1218*21496Ssklower */ 1219*21496Ssklower case TCPT_PERSIST: 1220*21496Ssklower (void) spp_output(cb, (struct mbuf *) 0); 1221*21496Ssklower spp_setpersist(cb); 1222*21496Ssklower break; 1223*21496Ssklower 1224*21496Ssklower /* 1225*21496Ssklower * Keep-alive timer went off; send something 1226*21496Ssklower * or drop connection if idle for too long. 1227*21496Ssklower */ 1228*21496Ssklower case TCPT_KEEP: 1229*21496Ssklower if (cb->s_state < TCPS_ESTABLISHED) 1230*21496Ssklower goto dropit; 1231*21496Ssklower if (cb->s_nspcb->nsp_socket->so_options & SO_KEEPALIVE) { 1232*21496Ssklower if (cb->s_idle >= TCPTV_MAXIDLE) 1233*21496Ssklower goto dropit; 1234*21496Ssklower (void) spp_output(cb, (struct mbuf *) 0); 1235*21496Ssklower } else 1236*21496Ssklower cb->s_idle = 0; 1237*21496Ssklower cb->s_timer[TCPT_KEEP] = TCPTV_KEEP; 1238*21496Ssklower break; 1239*21496Ssklower dropit: 1240*21496Ssklower cb = spp_drop(cb, ETIMEDOUT); 1241*21496Ssklower break; 1242*21496Ssklower } 1243*21496Ssklower return (cb); 1244*21496Ssklower } 1245