📄 tp_subr.c
字号:
idleticks = tpcb->tp_inact_ticks - tpcb->tp_timer[TM_inact]; if (idleticks > tpcb->tp_dt_ticks) /* * We have been idle for "a while" and no acks are * expected to clock out any data we send -- * slow start to get ack "clock" running again. */ tpcb->tp_cong_win = tpcb->tp_l_tpdusize; } cong_win = tpcb->tp_cong_win; highseq = SEQ(tpcb, tpcb->tp_fcredit + tpcb->tp_snduna); if (tpcb->tp_Xsnd.sb_mb) highseq = SEQ_MIN(tpcb, highseq, tpcb->tp_sndnew); IFDEBUG(D_DATA) printf("tp_send enter tpcb 0x%x nxt 0x%x win %d high 0x%x\n", tpcb, tpcb->tp_sndnxt, cong_win, highseq); ENDDEBUG IFTRACE(D_DATA) tptraceTPCB( TPPTmisc, "tp_send sndnew snduna", tpcb->tp_sndnew, tpcb->tp_snduna, 0, 0); tptraceTPCB( TPPTmisc, "tp_send tpcb->tp_sndnxt win fcredit congwin", tpcb->tp_sndnxt, cong_win, tpcb->tp_fcredit, tpcb->tp_cong_win); ENDTRACE IFTRACE(D_DATA) tptraceTPCB( TPPTmisc, "tp_send 2 nxt high fcredit congwin", tpcb->tp_sndnxt, highseq, tpcb->tp_fcredit, cong_win); ENDTRACE if (tpcb->tp_sndnxt_m) m = tpcb->tp_sndnxt_m; else { off = SEQ_SUB(tpcb, tpcb->tp_sndnxt, tpcb->tp_snduna); for (m = sb->sb_mb; m && off > 0; m = m->m_next) off--; }send: /* * Avoid silly window syndrome here . . . figure out how! */ checkseq = tpcb->tp_sndnum; if (idle && SEQ_LT(tpcb, tpcb->tp_sndnum, highseq)) checkseq = highseq; /* i.e. DON'T retain highest assigned packet */ while ((SEQ_LT(tpcb, tpcb->tp_sndnxt, highseq)) && m && cong_win > 0) { eotsdu = (m->m_flags & M_EOR) != 0; len = m->m_pkthdr.len; if (tpcb->tp_sndnxt == checkseq && eotsdu == 0 && len < (tpcb->tp_l_tpdusize / 2)) break; /* Nagle . . . . . */ cong_win -= len; /* make a copy - mb goes into the retransmission list * while m gets emitted. m_copy won't copy a zero-length mbuf. */ mb = m; m = m_copy(mb, 0, M_COPYALL); if (m == MNULL) break; IFTRACE(D_STASH) tptraceTPCB( TPPTmisc, "tp_send mcopy nxt high eotsdu len", tpcb->tp_sndnxt, highseq, eotsdu, len); ENDTRACE IFDEBUG(D_DATA) printf("tp_sending tpcb 0x%x nxt 0x%x\n", tpcb, tpcb->tp_sndnxt); ENDDEBUG /* when headers are precomputed, may need to fill in checksum here */ if (tpcb->tp_sock->so_error = tp_emit(DT_TPDU_type, tpcb, tpcb->tp_sndnxt, eotsdu, m)) { /* error */ break; } m = mb->m_nextpkt; tpcb->tp_sndnxt_m = m; if (tpcb->tp_sndnxt == tpcb->tp_sndnew) { SEQ_INC(tpcb, tpcb->tp_sndnew); /* * Time this transmission if not a retransmission and * not currently timing anything. */ if (tpcb->tp_rttemit == 0) { tpcb->tp_rttemit = ticks; tpcb->tp_rttseq = tpcb->tp_sndnxt; } tpcb->tp_sndnxt = tpcb->tp_sndnew; } else SEQ_INC(tpcb, tpcb->tp_sndnxt); /* * Set retransmit timer if not currently set. * Initial value for retransmit timer is smoothed * round-trip time + 2 * round-trip time variance. * Initialize shift counter which is used for backoff * of retransmit time. */ if (tpcb->tp_timer[TM_data_retrans] == 0 && tpcb->tp_class != TP_CLASS_0) { tpcb->tp_timer[TM_data_retrans] = tpcb->tp_dt_ticks; tpcb->tp_timer[TM_sendack] = tpcb->tp_keepalive_ticks; tpcb->tp_rxtshift = 0; } } if (SEQ_GT(tpcb, tpcb->tp_sndnew, tpcb->tp_sndnum)) tpcb->tp_oktonagle = 0;#ifdef TP_PERF_MEAS IFPERF(tpcb) { register int npkts; int elapsed = ticks - send_start_time, *t; struct timeval now; npkts = SEQ_SUB(tpcb, tpcb->tp_sndnxt, oldnxt); if (npkts > 0) tpcb->tp_Nwindow++; if (npkts > TP_PM_MAX) npkts = TP_PM_MAX; t = &(tpcb->tp_p_meas->tps_sendtime[npkts]); *t += (t - elapsed) >> TP_RTT_ALPHA; if (mb == 0) { IncPStat(tpcb, tps_win_lim_by_data[npkts] ); } else { IncPStat(tpcb, tps_win_lim_by_cdt[npkts] ); /* not true with congestion-window being used */ } now.tv_sec = elapsed / hz; now.tv_usec = (elapsed - (hz * now.tv_sec)) * 1000000 / hz; tpmeas( tpcb->tp_lref, TPsbsend, &elapsed, newseq, tpcb->tp_Nwindow, npkts); } ENDPERF#endif /* TP_PERF_MEAS */ IFTRACE(D_DATA) tptraceTPCB( TPPTmisc, "tp_send at end: new nxt eotsdu error", tpcb->tp_sndnew, tpcb->tp_sndnxt, eotsdu, tpcb->tp_sock->so_error); ENDTRACE}int TPNagleok;int TPNagled;tp_packetize(tpcb, m, eotsdu)register struct tp_pcb *tpcb;register struct mbuf *m;int eotsdu;{ register struct mbuf *n; register struct sockbuf *sb = &tpcb->tp_sock->so_snd; int maxsize = tpcb->tp_l_tpdusize - tp_headersize(DT_TPDU_type, tpcb) - (tpcb->tp_use_checksum?4:0) ; int totlen = m->m_pkthdr.len; struct mbuf *m_split(); /* * Pre-packetize the data in the sockbuf * according to negotiated mtu. Do it here * where we can safely wait for mbufs. * * This presumes knowledge of sockbuf conventions. * TODO: allocate space for header and fill it in (once!). */ IFDEBUG(D_DATA) printf("SEND BF: maxsize %d totlen %d eotsdu %d sndnum 0x%x\n", maxsize, totlen, eotsdu, tpcb->tp_sndnum); ENDTRACE if (tpcb->tp_oktonagle) { if ((n = sb->sb_mb) == 0) panic("tp_packetize"); while (n->m_act) n = n->m_act; if (n->m_flags & M_EOR) panic("tp_packetize 2"); SEQ_INC(tpcb, tpcb->tp_sndnum); if (totlen + n->m_pkthdr.len < maxsize) { /* There is an unsent packet with space, combine data */ struct mbuf *old_n = n; tpsbcheck(tpcb,3); n->m_pkthdr.len += totlen; while (n->m_next) n = n->m_next; sbcompress(sb, m, n); tpsbcheck(tpcb,4); n = old_n; TPNagled++; goto out; } } while (m) { n = m; if (totlen > maxsize) { if ((m = m_split(n, maxsize, M_WAIT)) == 0) panic("tp_packetize"); } else m = 0; totlen -= maxsize; tpsbcheck(tpcb, 5); sbappendrecord(sb, n); tpsbcheck(tpcb, 6); SEQ_INC(tpcb, tpcb->tp_sndnum); }out: if (eotsdu) { n->m_flags |= M_EOR; /* XXX belongs at end */ tpcb->tp_oktonagle = 0; } else { SEQ_DEC(tpcb, tpcb->tp_sndnum); tpcb->tp_oktonagle = 1; TPNagleok++; } IFDEBUG(D_DATA) printf("SEND out: oktonagle %d sndnum 0x%x\n", tpcb->tp_oktonagle, tpcb->tp_sndnum); ENDTRACE return 0;}/* * NAME: tp_stash() * CALLED FROM: * tp.trans on arrival of a DT tpdu * FUNCTION, ARGUMENTS, and RETURN VALUE: * Returns 1 if * a) something new arrived and it's got eotsdu_reached bit on, * b) this arrival was caused other out-of-sequence things to be * accepted, or * c) this arrival is the highest seq # for which we last gave credit * (sender just sent a whole window) * In other words, returns 1 if tp should send an ack immediately, 0 if * the ack can wait a while. * * Note: this implementation no longer renegs on credit, (except * when debugging option D_RENEG is on, for the purpose of testing * ack subsequencing), so we don't need to check for incoming tpdus * being in a reneged portion of the window. */tp_stash(tpcb, e) register struct tp_pcb *tpcb; register struct tp_event *e;{ register int ack_reason= tpcb->tp_ack_strat & ACK_STRAT_EACH; /* 0--> delay acks until full window */ /* 1--> ack each tpdu */#ifndef lint#define E e->ATTR(DT_TPDU)#else /* lint */#define E e->ev_union.EV_DT_TPDU#endif /* lint */ if ( E.e_eot ) { register struct mbuf *n = E.e_data; n->m_flags |= M_EOR; n->m_act = 0; } IFDEBUG(D_STASH) dump_mbuf(tpcb->tp_sock->so_rcv.sb_mb, "stash: so_rcv before appending"); dump_mbuf(E.e_data, "stash: e_data before appending"); ENDDEBUG IFPERF(tpcb) PStat(tpcb, Nb_from_ll) += E.e_datalen; tpmeas(tpcb->tp_lref, TPtime_from_ll, &e->e_time, E.e_seq, (u_int)PStat(tpcb, Nb_from_ll), (u_int)E.e_datalen); ENDPERF if (E.e_seq == tpcb->tp_rcvnxt) { IFDEBUG(D_STASH) printf("stash EQ: seq 0x%x datalen 0x%x eot 0x%x\n", E.e_seq, E.e_datalen, E.e_eot); ENDDEBUG IFTRACE(D_STASH) tptraceTPCB(TPPTmisc, "stash EQ: seq len eot", E.e_seq, E.e_datalen, E.e_eot, 0); ENDTRACE SET_DELACK(tpcb); sbappend(&tpcb->tp_sock->so_rcv, E.e_data); SEQ_INC( tpcb, tpcb->tp_rcvnxt ); /* * move chains from the reassembly queue to the socket buffer */ if (tpcb->tp_rsycnt) { register struct mbuf **mp; struct mbuf **mplim; mp = tpcb->tp_rsyq + (tpcb->tp_rcvnxt % tpcb->tp_maxlcredit); mplim = tpcb->tp_rsyq + tpcb->tp_maxlcredit; while (tpcb->tp_rsycnt && *mp) { sbappend(&tpcb->tp_sock->so_rcv, *mp); tpcb->tp_rsycnt--; *mp = 0; SEQ_INC(tpcb, tpcb->tp_rcvnxt); ack_reason |= ACK_REORDER; if (++mp == mplim) mp = tpcb->tp_rsyq; } } IFDEBUG(D_STASH) dump_mbuf(tpcb->tp_sock->so_rcv.sb_mb, "stash: so_rcv after appending"); ENDDEBUG } else { register struct mbuf **mp; SeqNum uwe; IFTRACE(D_STASH) tptraceTPCB(TPPTmisc, "stash Reseq: seq rcvnxt lcdt", E.e_seq, tpcb->tp_rcvnxt, tpcb->tp_lcredit, 0); ENDTRACE if (tpcb->tp_rsyq == 0) tp_rsyset(tpcb); uwe = SEQ(tpcb, tpcb->tp_rcvnxt + tpcb->tp_maxlcredit); if (tpcb->tp_rsyq == 0 || !IN_RWINDOW(tpcb, E.e_seq, tpcb->tp_rcvnxt, uwe)) { ack_reason = ACK_DONT; m_freem(E.e_data); } else if (*(mp = tpcb->tp_rsyq + (E.e_seq % tpcb->tp_maxlcredit))) { IFDEBUG(D_STASH) printf("tp_stash - drop & ack\n"); ENDDEBUG /* retransmission - drop it and force an ack */ IncStat(ts_dt_dup); IFPERF(tpcb) IncPStat(tpcb, tps_n_ack_cuz_dup); ENDPERF m_freem(E.e_data); ack_reason |= ACK_DUP; } else { *mp = E.e_data; tpcb->tp_rsycnt++; ack_reason = ACK_DONT; } } /* there were some comments of historical interest here. */ { LOCAL_CREDIT(tpcb); if ( E.e_seq == tpcb->tp_sent_uwe ) ack_reason |= ACK_STRAT_FULLWIN; IFTRACE(D_STASH) tptraceTPCB(TPPTmisc, "end of stash, eot, ack_reason, sent_uwe ", E.e_eot, ack_reason, tpcb->tp_sent_uwe, 0); ENDTRACE if ( ack_reason == ACK_DONT ) { IncStat( ts_ackreason[ACK_DONT] ); return 0; } else { IFPERF(tpcb) if(ack_reason & ACK_STRAT_EACH) { IncPStat(tpcb, tps_n_ack_cuz_strat); } else if(ack_reason & ACK_STRAT_FULLWIN) { IncPStat(tpcb, tps_n_ack_cuz_fullwin); } else if(ack_reason & ACK_REORDER) { IncPStat(tpcb, tps_n_ack_cuz_reorder); } tpmeas(tpcb->tp_lref, TPtime_ack_sent, 0, SEQ_ADD(tpcb, E.e_seq, 1), 0, 0); ENDPERF { register int i; /* keep track of all reasons that apply */ for( i=1; i<_ACK_NUM_REASONS_ ;i++) { if( ack_reason & (1<<i) ) IncStat( ts_ackreason[i] ); } } return 1; } }}/* * tp_rsyflush - drop all the packets on the reassembly queue. * Do this when closing the socket, or when somebody has changed * the space avaible in the receive socket (XXX). */tp_rsyflush(tpcb)register struct tp_pcb *tpcb;{ register struct mbuf *m, **mp; if (tpcb->tp_rsycnt) { for (mp == tpcb->tp_rsyq + tpcb->tp_maxlcredit; --mp >= tpcb->tp_rsyq; ) if (*mp) { tpcb->tp_rsycnt--; m_freem(*mp); } if (tpcb->tp_rsycnt) { printf("tp_rsyflush %x\n", tpcb); tpcb->tp_rsycnt = 0; } } free((caddr_t)tpcb->tp_rsyq, M_PCB); tpcb->tp_rsyq = 0;}tp_rsyset(tpcb)register struct tp_pcb *tpcb;{ register struct socket *so = tpcb->tp_sock; int maxcredit = tpcb->tp_xtd_format ? 0xffff : 0xf; int old_credit = tpcb->tp_maxlcredit; caddr_t rsyq; tpcb->tp_maxlcredit = maxcredit = min(maxcredit, (so->so_rcv.sb_hiwat + tpcb->tp_l_tpdusize)/ tpcb->tp_l_tpdusize); if (old_credit == tpcb->tp_maxlcredit && tpcb->tp_rsyq != 0) return; maxcredit *= sizeof(struct mbuf *); if (tpcb->tp_rsyq) tp_rsyflush(tpcb); if (rsyq = (caddr_t)malloc(maxcredit, M_PCB, M_NOWAIT)) bzero(rsyq, maxcredit); tpcb->tp_rsyq = (struct mbuf **)rsyq;}tpsbcheck(tpcb, i)struct tp_pcb *tpcb;{ register struct mbuf *n, *m; register int len = 0, mbcnt = 0, pktlen; struct sockbuf *sb = &tpcb->tp_sock->so_snd; for (n = sb->sb_mb; n; n = n->m_nextpkt) { if ((n->m_flags & M_PKTHDR) == 0) panic("tpsbcheck nohdr"); pktlen = len + n->m_pkthdr.len; for (m = n; m; m = m->m_next) { len += m->m_len; mbcnt += MSIZE; if (m->m_flags & M_EXT) mbcnt += m->m_ext.ext_size; } if (len != pktlen) { printf("test %d; len %d != pktlen %d on mbuf 0x%x\n", i, len, pktlen, n); panic("tpsbcheck short"); } } if (len != sb->sb_cc || mbcnt != sb->sb_mbcnt) { printf("test %d: cc %d != %d || mbcnt %d != %d\n", i, len, sb->sb_cc, mbcnt, sb->sb_mbcnt); panic("tpsbcheck"); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -