📄 spp_usrreq.c
字号:
mask = SF_HI; goto set_head; case SO_HEADERS_ON_OUTPUT: mask = SF_HO; set_head: if (cb->s_flags & SF_PI) { ok = mtod(*value, int *); if (*ok) cb->s_flags |= mask; else cb->s_flags &= ~mask; } else error = EINVAL; break; case SO_MTU: cb->s_mtu = *(mtod(*value, u_short *)); break;#ifdef SF_NEWCALL case SO_NEWCALL: ok = mtod(*value, int *); if (*ok) { cb->s_flags2 |= SF_NEWCALL; spp_newchecks[5]++; } else { cb->s_flags2 &= ~SF_NEWCALL; spp_newchecks[6]++; } break;#endif case SO_DEFAULT_HEADERS: { register struct sphdr *sp = mtod(*value, struct sphdr *); cb->s_dt = sp->sp_dt; cb->s_cc = sp->sp_cc & SP_EM; } break; default: error = EINVAL; } m_freem(*value); break; } release: return (error);}/*ARGSUSED*/spp_usrreq(so, req, m, nam, controlp) struct socket *so; int req; struct mbuf *m, *nam, *controlp;{ struct nspcb *nsp = sotonspcb(so); register struct sppcb *cb; int s = splnet(); int error = 0, ostate; struct mbuf *mm; register struct sockbuf *sb; if (req == PRU_CONTROL) return (ns_control(so, (int)m, (caddr_t)nam, (struct ifnet *)controlp)); if (nsp == NULL) { if (req != PRU_ATTACH) { error = EINVAL; goto release; } } else cb = nstosppcb(nsp); ostate = cb ? cb->s_state : 0; switch (req) { case PRU_ATTACH: if (nsp != NULL) { error = EISCONN; break; } error = ns_pcballoc(so, &nspcb); if (error) break; if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { error = soreserve(so, (u_long) 3072, (u_long) 3072); if (error) break; } nsp = sotonspcb(so); mm = m_getclr(M_DONTWAIT, MT_PCB); sb = &so->so_snd; if (mm == NULL) { error = ENOBUFS; break; } cb = mtod(mm, struct sppcb *); mm = m_getclr(M_DONTWAIT, MT_HEADER); if (mm == NULL) { (void) m_free(dtom(m)); error = ENOBUFS; break; } cb->s_idp = mtod(mm, struct idp *); cb->s_state = TCPS_LISTEN; cb->s_smax = -1; cb->s_swl1 = -1; cb->s_q.si_next = cb->s_q.si_prev = &cb->s_q; cb->s_nspcb = nsp; cb->s_mtu = 576 - sizeof (struct spidp); cb->s_cwnd = sbspace(sb) * CUNIT / cb->s_mtu; cb->s_ssthresh = cb->s_cwnd; cb->s_cwmx = sbspace(sb) * CUNIT / (2 * sizeof (struct spidp)); /* Above is recomputed when connecting to account for changed buffering or mtu's */ cb->s_rtt = SPPTV_SRTTBASE; cb->s_rttvar = SPPTV_SRTTDFLT << 2; SPPT_RANGESET(cb->s_rxtcur, ((SPPTV_SRTTBASE >> 2) + (SPPTV_SRTTDFLT << 2)) >> 1, SPPTV_MIN, SPPTV_REXMTMAX); nsp->nsp_pcb = (caddr_t) cb; break; case PRU_DETACH: if (nsp == NULL) { error = ENOTCONN; break; } if (cb->s_state > TCPS_LISTEN) cb = spp_disconnect(cb); else cb = spp_close(cb); break; case PRU_BIND: error = ns_pcbbind(nsp, nam); break; case PRU_LISTEN: if (nsp->nsp_lport == 0) error = ns_pcbbind(nsp, (struct mbuf *)0); if (error == 0) cb->s_state = TCPS_LISTEN; break; /* * Initiate connection to peer. * Enter SYN_SENT state, and mark socket as connecting. * Start keep-alive timer, setup prototype header, * Send initial system packet requesting connection. */ case PRU_CONNECT: if (nsp->nsp_lport == 0) { error = ns_pcbbind(nsp, (struct mbuf *)0); if (error) break; } error = ns_pcbconnect(nsp, nam); if (error) break; soisconnecting(so); sppstat.spps_connattempt++; cb->s_state = TCPS_SYN_SENT; cb->s_did = 0; spp_template(cb); cb->s_timer[SPPT_KEEP] = SPPTV_KEEP; cb->s_force = 1 + SPPTV_KEEP; /* * Other party is required to respond to * the port I send from, but he is not * required to answer from where I am sending to, * so allow wildcarding. * original port I am sending to is still saved in * cb->s_dport. */ nsp->nsp_fport = 0; error = spp_output(cb, (struct mbuf *) 0); break; case PRU_CONNECT2: error = EOPNOTSUPP; break; /* * We may decide later to implement connection closing * handshaking at the spp level optionally. * here is the hook to do it: */ case PRU_DISCONNECT: cb = spp_disconnect(cb); break; /* * Accept a connection. Essentially all the work is * done at higher levels; just return the address * of the peer, storing through addr. */ case PRU_ACCEPT: { struct sockaddr_ns *sns = mtod(nam, struct sockaddr_ns *); nam->m_len = sizeof (struct sockaddr_ns); sns->sns_family = AF_NS; sns->sns_addr = nsp->nsp_faddr; break; } case PRU_SHUTDOWN: socantsendmore(so); cb = spp_usrclosed(cb); if (cb) error = spp_output(cb, (struct mbuf *) 0); break; /* * After a receive, possibly send acknowledgment * updating allocation. */ case PRU_RCVD: cb->s_flags |= SF_RVD; (void) spp_output(cb, (struct mbuf *) 0); cb->s_flags &= ~SF_RVD; break; case PRU_ABORT: (void) spp_drop(cb, ECONNABORTED); break; case PRU_SENSE: case PRU_CONTROL: m = NULL; error = EOPNOTSUPP; break; case PRU_RCVOOB: if ((cb->s_oobflags & SF_IOOB) || so->so_oobmark || (so->so_state & SS_RCVATMARK)) { m->m_len = 1; *mtod(m, caddr_t) = cb->s_iobc; break; } error = EINVAL; break; case PRU_SENDOOB: if (sbspace(&so->so_snd) < -512) { error = ENOBUFS; break; } cb->s_oobflags |= SF_SOOB; /* fall into */ case PRU_SEND: if (controlp) { u_short *p = mtod(controlp, u_short *); spp_newchecks[2]++; if ((p[0] == 5) && p[1] == 1) { /* XXXX, for testing */ cb->s_shdr.sp_dt = *(u_char *)(&p[2]); spp_newchecks[3]++; } m_freem(controlp); } controlp = NULL; error = spp_output(cb, m); m = NULL; break; case PRU_SOCKADDR: ns_setsockaddr(nsp, nam); break; case PRU_PEERADDR: ns_setpeeraddr(nsp, nam); break; case PRU_SLOWTIMO: cb = spp_timers(cb, (int)nam); req |= ((int)nam) << 8; break; case PRU_FASTTIMO: case PRU_PROTORCV: case PRU_PROTOSEND: error = EOPNOTSUPP; break; default: panic("sp_usrreq"); } if (cb && (so->so_options & SO_DEBUG || traceallspps)) spp_trace(SA_USER, (u_char)ostate, cb, (struct spidp *)0, req);release: if (controlp != NULL) m_freem(controlp); if (m != NULL) m_freem(m); splx(s); return (error);}spp_usrreq_sp(so, req, m, nam, controlp) struct socket *so; int req; struct mbuf *m, *nam, *controlp;{ int error = spp_usrreq(so, req, m, nam, controlp); if (req == PRU_ATTACH && error == 0) { struct nspcb *nsp = sotonspcb(so); ((struct sppcb *)nsp->nsp_pcb)->s_flags |= (SF_HI | SF_HO | SF_PI); } return (error);}/* * Create template to be used to send spp packets on a connection. * Called after host entry created, fills * in a skeletal spp header (choosing connection id), * minimizing the amount of work necessary when the connection is used. */spp_template(cb) register struct sppcb *cb;{ register struct nspcb *nsp = cb->s_nspcb; register struct idp *idp = cb->s_idp; register struct sockbuf *sb = &(nsp->nsp_socket->so_snd); idp->idp_pt = NSPROTO_SPP; idp->idp_sna = nsp->nsp_laddr; idp->idp_dna = nsp->nsp_faddr; cb->s_sid = htons(spp_iss); spp_iss += SPP_ISSINCR/2; cb->s_alo = 1; cb->s_cwnd = (sbspace(sb) * CUNIT) / cb->s_mtu; cb->s_ssthresh = cb->s_cwnd; /* Try to expand fast to full complement of large packets */ cb->s_cwmx = (sbspace(sb) * CUNIT) / (2 * sizeof(struct spidp)); cb->s_cwmx = max(cb->s_cwmx, cb->s_cwnd); /* But allow for lots of little packets as well */}/* * Close a SPIP control block: * discard spp control block itself * discard ns protocol control block * wake up any sleepers */struct sppcb *spp_close(cb) register struct sppcb *cb;{ register struct spidp_q *s; struct nspcb *nsp = cb->s_nspcb; struct socket *so = nsp->nsp_socket; register struct mbuf *m; s = cb->s_q.si_next; while (s != &(cb->s_q)) { s = s->si_next; m = dtom(s->si_prev); remque(s->si_prev); m_freem(m); } (void) m_free(dtom(cb->s_idp)); (void) m_free(dtom(cb)); nsp->nsp_pcb = 0; soisdisconnected(so); ns_pcbdetach(nsp); sppstat.spps_closed++; return ((struct sppcb *)0);}/* * Someday we may do level 3 handshaking * to close a connection or send a xerox style error. * For now, just close. */struct sppcb *spp_usrclosed(cb) register struct sppcb *cb;{ return (spp_close(cb));}struct sppcb *spp_disconnect(cb) register struct sppcb *cb;{ return (spp_close(cb));}/* * Drop connection, reporting * the specified error. */struct sppcb *spp_drop(cb, errno) register struct sppcb *cb; int errno;{ struct socket *so = cb->s_nspcb->nsp_socket; /* * someday, in the xerox world * we will generate error protocol packets * announcing that the socket has gone away. */ if (TCPS_HAVERCVDSYN(cb->s_state)) { sppstat.spps_drops++; cb->s_state = TCPS_CLOSED; /*(void) tcp_output(cb);*/ } else sppstat.spps_conndrops++; so->so_error = errno; return (spp_close(cb));}spp_abort(nsp) struct nspcb *nsp;{ (void) spp_close((struct sppcb *)nsp->nsp_pcb);}int spp_backoff[SPP_MAXRXTSHIFT+1] = { 1, 2, 4, 8, 16, 32, 64, 64, 64, 64, 64, 64, 64 };/* * Fast timeout routine for processing delayed acks */spp_fasttimo(){ register struct nspcb *nsp; register struct sppcb *cb; int s = splnet(); nsp = nspcb.nsp_next; if (nsp) for (; nsp != &nspcb; nsp = nsp->nsp_next) if ((cb = (struct sppcb *)nsp->nsp_pcb) && (cb->s_flags & SF_DELACK)) { cb->s_flags &= ~SF_DELACK; cb->s_flags |= SF_ACKNOW; sppstat.spps_delack++; (void) spp_output(cb, (struct mbuf *) 0); } splx(s);}/* * spp protocol timeout routine called every 500 ms. * Updates the timers in all active pcb's and * causes finite state machine actions if timers expire. */spp_slowtimo(){ register struct nspcb *ip, *ipnxt; register struct sppcb *cb; int s = splnet(); register int i; /* * Search through tcb's and update active timers. */ ip = nspcb.nsp_next; if (ip == 0) { splx(s); return; } while (ip != &nspcb) { cb = nstosppcb(ip); ipnxt = ip->nsp_next; if (cb == 0) goto tpgone; for (i = 0; i < SPPT_NTIMERS; i++) { if (cb->s_timer[i] && --cb->s_timer[i] == 0) { (void) spp_usrreq(cb->s_nspcb->nsp_socket, PRU_SLOWTIMO, (struct mbuf *)0, (struct mbuf *)i, (struct mbuf *)0, (struct mbuf *)0); if (ipnxt->nsp_prev != ip) goto tpgone; } } cb->s_idle++; if (cb->s_rtt) cb->s_rtt++;tpgone: ip = ipnxt; } spp_iss += SPP_ISSINCR/PR_SLOWHZ; /* increment iss */ splx(s);}/* * SPP timer processing. */struct sppcb *spp_timers(cb, timer) register struct sppcb *cb; int timer;{ long rexmt; int win; cb->s_force = 1 + timer; switch (timer) { /* * 2 MSL timeout in shutdown went off. TCP deletes connection * control block. */ case SPPT_2MSL: printf("spp: SPPT_2MSL went off for no reason\n"); cb->s_timer[timer] = 0; break; /* * Retransmission timer went off. Message has not * been acked within retransmit interval. Back off * to a longer retransmit interval and retransmit one packet. */ case SPPT_REXMT: if (++cb->s_rxtshift > SPP_MAXRXTSHIFT) { cb->s_rxtshift = SPP_MAXRXTSHIFT; sppstat.spps_timeoutdrop++; cb = spp_drop(cb, ETIMEDOUT); break; } sppstat.spps_rexmttimeo++; rexmt = ((cb->s_srtt >> 2) + cb->s_rttvar) >> 1; rexmt *= spp_backoff[cb->s_rxtshift]; SPPT_RANGESET(cb->s_rxtcur, rexmt, SPPTV_MIN, SPPTV_REXMTMAX); cb->s_timer[SPPT_REXMT] = cb->s_rxtcur; /* * If we have backed off fairly far, our srtt * estimate is probably bogus. Clobber it * so we'll take the next rtt measurement as our srtt; * move the current srtt into rttvar to keep the current * retransmit times until then. */ if (cb->s_rxtshift > SPP_MAXRXTSHIFT / 4 ) { cb->s_rttvar += (cb->s_srtt >> 2); cb->s_srtt = 0; } cb->s_snxt = cb->s_rack; /* * If timing a packet, stop the timer. */ cb->s_rtt = 0; /* * See very long discussion in tcp_timer.c about congestion * window and sstrhesh */ win = min(cb->s_swnd, (cb->s_cwnd/CUNIT)) / 2; if (win < 2) win = 2; cb->s_cwnd = CUNIT; cb->s_ssthresh = win * CUNIT; (void) spp_output(cb, (struct mbuf *) 0); break; /* * Persistance timer into zero window. * Force a probe to be sent. */ case SPPT_PERSIST: sppstat.spps_persisttimeo++; spp_setpersist(cb); (void) spp_output(cb, (struct mbuf *) 0); break; /* * Keep-alive timer went off; send something * or drop connection if idle for too long. */ case SPPT_KEEP: sppstat.spps_keeptimeo++; if (cb->s_state < TCPS_ESTABLISHED) goto dropit; if (cb->s_nspcb->nsp_socket->so_options & SO_KEEPALIVE) { if (cb->s_idle >= SPPTV_MAXIDLE) goto dropit; sppstat.spps_keepprobe++; (void) spp_output(cb, (struct mbuf *) 0); } else cb->s_idle = 0; cb->s_timer[SPPT_KEEP] = SPPTV_KEEP; break; dropit: sppstat.spps_keepdrops++; cb = spp_drop(cb, ETIMEDOUT); break; } return (cb);}#ifndef lintint SppcbSize = sizeof (struct sppcb);int NspcbSize = sizeof (struct nspcb);#endif /* lint */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -