📄 tcpmisc.c
字号:
} /* tcp_adjust_out_sack_blocks_for_rnxt *//*************************************************************************/static void tcp_remove_in_sack_block(fast tcpsv_t *svp, int wbi){ int sbi; for (sbi = (wbi + 1); sbi < svp->sv_num_in_sack_blocks; sbi++) { OS_MOVE_N( &(svp->sv_in_sack_blocks[sbi - 1]), &(svp->sv_in_sack_blocks[sbi]), sizeof(tcp_sack_block_) ); } /* for */ (svp->sv_num_in_sack_blocks)--;} /* tcp_remove_in_sack_block *//*****************************************************************************/#ifdef TCP_SELACK_ENHANCEMENTS /* DEBUG_IN_SACKS */void print_insack_table(tcpsv_t *svp){ int iter;/* os_printf("\n insack table: "); */ os_printf(" "); for (iter = 0; iter < svp->sv_num_in_sack_blocks; iter++) { tcp_sack_block_ *sbp = &(svp->sv_in_sack_blocks[iter]); u32 sb_begin_seqno = NetToHost32(&(sbp->begin_seqno)); u32 sb_end_seqno = NetToHost32(&(sbp->end_seqno)); os_printf(" %d-(%u,%u) ",(iter + 1),sb_begin_seqno, sb_end_seqno); } /* for *//* os_printf("\n"); */}#endif/*****************************************************************************//* Function to adjust the TCP incoming SACK block list according to the *//* the sequence numbers of a SACK block received in the options field of an *//* incoming segment. *//* NOTE: the incoming parameters are received in netowrk order. *//*****************************************************************************/static void tcp_process_in_sack_block(fast tcpsv_t *svp, u32 *bseqno,u32 *eseqno) { int sbi; u32 begin_seqno = NetToHost32(bseqno); u32 end_seqno = NetToHost32(eseqno);#ifdef DEBUG_IN_SACKS os_printf("\n tcp_process_in_sack_block: beg=%u, end=%u:",begin_seqno,end_seqno);#endif /* Sanity test: ignore SACK blocks that contain beginning sequences larger (mod32) than end sequence. (Ought we to send a "reset" here?) */ if ( MODULO32(begin_seqno, >, end_seqno) ) {#ifdef DEBUG_IN_SACKS os_printf("...rejected, invalid SACK\n");#endif return; } /* if */ /* Sanity test: ignore SACK blocks referring to data that has already been cumulatively ACKED by the peer, or contiguous with data that has been been ACKED (if it were contiguous, it should have been ACKED now). (Ought we to send a "reset" here?) */ if ( UC32M(begin_seqno, <= , svp->sv_suna) ) {#ifdef DEBUG_IN_SACKS os_printf("...rejected, some or all data already ACKED\n");#endif return; } /* if */ /* Loop thru our existing list of received SACK blocks to find where this one fits. */ sbi = 0; while (sbi < svp->sv_num_in_sack_blocks) { tcp_sack_block_ *sbp = &(svp->sv_in_sack_blocks[sbi]); u32 sb_begin_seqno; u32 sb_end_seqno; /* Need to convert to host order for comparisions */ sb_begin_seqno = NetToHost32(&(sbp->begin_seqno)); sb_end_seqno = NetToHost32(&(sbp->end_seqno)); /* Is the new SACK block completely for lower sequence numbers than the one we are looking at? */ if (end_seqno < sb_begin_seqno) { int sbii; /* This is where it fits. Move all the current and all subsequent entries up one notch and insert the new block. If the list is currently full, we may lose the item with the highest sequence numbers -- so be it */ for (sbii = (svp->sv_num_in_sack_blocks - 1); sbii > sbi; sbii--) { OS_MOVE_N(&(svp->sv_in_sack_blocks[sbii]), &(svp->sv_in_sack_blocks[(sbii - 1)]), sizeof(tcp_sack_block_) ); } /* for */ sbp->begin_seqno = *bseqno; sbp->end_seqno = *eseqno;#ifdef DEBUG_IN_SACKS print_insack_table(svp);#endif return; } /* if */ /* Is the new SACK block an exact overlay, or contained entirely within, this list item? */ if ( (begin_seqno >= sb_begin_seqno) && (end_seqno <= sb_end_seqno) ) { /* no new information, ignore */#ifdef DEBUG_IN_SACKS print_insack_table(svp);#endif return; } /* end */ /* Is the new SACK block completely for higher sequence numbers than the list item we are currently looking at? */ if (begin_seqno > sb_end_seqno) { /* Yes -- keep looking for where it fits. */ sbi++; continue; } /* if */ /* The new SACK block overlaps or is a superset of this list item. Expand the span of the new SACK to include all the data in the current list item, then delete the list item and recycle, taking care to adjust our loop index so that the new (adjusted) SACK block will be compared to the list item that has just been moved down into the spot we were looking at. */ /* NOTE: For the overlap case, in a strict sense that implies that the peer has reneged on part of the data it previously SACKED, but we won't worry about that here, we deal with reneging when and if we get a retransmission time out. */ if (begin_seqno > sb_begin_seqno) { begin_seqno = sb_begin_seqno; } /* if */ if (end_seqno < sb_end_seqno) { end_seqno = sb_end_seqno; } /* if */ tcp_remove_in_sack_block(svp, sbi); /* leave the list index unchanged, because the items above this spot have been moved down and we want to catch all of them */ } /* while */ /* If we fall down to here, then it means that the new SACK block is for higher sequence numbers than all the blocks in our list. So, provided there is room, put this item into the list (our index, sbi. will be equal here to the number of blocks currently in the list, and sbp will be poi) */ if (sbi < MAX_NUM_IN_SACK_BLOCKS) { svp->sv_in_sack_blocks[sbi].begin_seqno = *bseqno; svp->sv_in_sack_blocks[sbi].end_seqno = *eseqno; (svp->sv_num_in_sack_blocks)++; } /* if */#ifdef DEBUG_IN_SACKS print_insack_table(svp);#endif} /* tcp_process_in_sack_block *//*****************************************************************************//* This function is called to update the in sack table in view of a new *//* cumulative ACK which may have advanced past one or more of the previously *//* received selective ACKS. It is assumed that this function is called during*//* the processing of an ACK, after the svp->sv_suna field has been updated. *//*****************************************************************************/export void tcp_in_sack_proc_suna(fast tcpsv_t *svp){ u32 suna = MU32(svp->sv_suna); /* Purge any SACKS from our list that are obsolete given the current value of sv_suna. Since the in SACK BLOCK list is sorted in order of increasing sequence numbers, loop thru the list until we hit either the end of the list or an item whose beginning sequence number is larger (mod32) than SUNA. Delete all items until we get to that item. */ /* Question: what should we do if we find an item SUNA falls in the middle of? If that happens, it would seem to imply that the peer has reneged on the SACK of the portion of that block that lies beyond SUNA. So, in that unlikely case, we will eliminate that block. The worst that will happen is we end up unecessarily retransmitting that data. */ /* NOTE: No need for a loop index, as we will be removing blocks at index zero until either the list is empty or that item is not subject to removal. */ while (svp->sv_num_in_sack_blocks > 0) { u32 sb_seqno = NetToHost32(&(svp->sv_in_sack_blocks[0].begin_seqno)); /* Have we reached an item which is beyond SUNA ?*/ if ( MODULO32(sb_seqno, > , suna) ) { /* Yes, we're done */ break; } /* if */ #ifdef DEBUG_IN_SACKS os_printf("\ntcp_in_sack_proc_suna: removing sack due to suna=%u\n",suna);#endif /* Either this block has been ACKED or the SACK has been reneged. In either case, remove it from our list. */ tcp_remove_in_sack_block(svp, 0);#ifdef DEBUG_IN_SACKS print_insack_table(svp);#endif } /* while */ } /* tcp_in_sack_proc_suna *//*****************************************************************************//* Note: It is assumed in the following function that the sv_suna field *//* has been updated according the the cumulative ACK field in the segment *//* whose SACK options we are processing, prior to calling this function. *//*****************************************************************************/export void tcp_in_sack_processing(fast tcpsv_t *svp, TCPO_T *tcphp){ u32 suna = MU32(svp->sv_suna); TCPH_T *sack; int sack_length; /* Find the SACK option in the current segment, if any */ sack = tcp_find_option(tcphp,TCPO_SACK_KIND); if (sack == (TCPO_T) 0) return; /* no sacks in this header */ /* Need some logic here to make sure the length field of the SACK option doesn't overflow the length of the options field as implied by the data offset field of the header. */ sack_length = (sack[TCPO_SIZE] - TCPO_VAL); sack += TCPO_VAL; /* Compute the number of SACK BLOCKS contained here. Ignore if we smell anything funny, like the length not being consistent with an integral number of SACK blocks */ if ( (sack_length % TCPO_SACK_BLOCK_SIZE) != 0) return; /* smells funny */#ifdef DEBUG_IN_SACKS os_printf("\ntcp_in_sack_processing:");#endif /* Loop thru the SACK blocks, process them one at a time */ while (sack_length > 0) { tcp_process_in_sack_block(svp, (u32 *) sack, (u32 *) (sack + sizeof(u32))); sack_length -= TCPO_SACK_BLOCK_SIZE; sack += TCPO_SACK_BLOCK_SIZE; } /* while */} /* tcp_in_sack_processing */#endif /* TCP_SELACK_ENHANCEMENTS *//************************************************************************* ** Function : ** ** Description : ** ** ** Parameters : None. ** ** Return : None. ** *************************************************************************/export st tcp_up (fast m * mp){ fast TCPH_T * tcphp; /* TCP header pointer */ fast int length; u16 checksum; trace0(tcp_trace, "tcp_up:\n"); INC_MIB_CNTR_TCP_IN_SEGS /* discard packets with insufficient TCP header information */ if ((length = mp->m_tp - mp->m_cp) < SIZEOF_TCPH_T) { debug0(tcp_debug, "tcp_up: packet too small\n"); return (st)mp->m_dispfn; } tcphp = (TCPH_T *)mp->m_cp; /* MBM -- we probably need to put some validity checking here for the options part of the header, e.g., make sure some option doesn't have a length field that overflows the data offset. When I mistakenly sent a SACK to Linux that was invalid that way, Linux sent back a reset. */ mp->m_pflags = 0; if (is_remote(mp)) { /* checksum not generated on this machine */ fast IPH_T * iphp; /* IP header pointer */ fast PIPH_T * piphp; /* Pseudo IP header pointer */ /* validate the checksum */ iphp = (IPH_T *)mp->m_hp; piphp = (PIPH_T *)(&iphp[IPH_PIPH]); checksum = (~NetToHost16(&tcphp[TCPH_CHECKSUM])) & 0xFFFF; /*RLS 12/96 rev. 3.7*/ if (checksum == (u16)0xFFFF) checksum = 0; HostToNet16(&piphp[PIPH_LENGTH], (u16)length); piphp[PIPH_ZERO] = 0; HostToNet16(&tcphp[TCPH_CHECKSUM], oc_sum((a16 *)piphp, SIZEOF_PIPH_T)); if (checksum != oc_sum((a16 *)tcphp, length)) { debug0(tcp_debug, "tcp_up: checksum error\n"); return (st)mp->m_dispfn; } } mp->m_src.a_ipa.ip_port = MemToHost16(&tcphp[TCPH_SPORT]); mp->m_dest.a_ipa.ip_port = MemToHost16(&tcphp[TCPH_DPORT]);#ifndef AVOID_MSM return (st)tcp_target;#else return (tcp_target(mp));#endif}#ifdef TCP_KEEP_ALIVEimport u32 tcp_try_max;import u32 tcp_idle_interval;import boolean tcp_keep_alive;export int tcp_init_ka (fast tcpsv_t * svp){ so_t * sop; trace0(tcp_trace, "tcp_init_ka:\n"); svp->sv_ka_retrycnt = (u16)tcp_try_max; sop = svp->sv_sop; if (sop) svp->sv_ka_tcb = t_new((tcb *)0, tcp_ka_timer, (void *)svp, tcp_idle_interval, (u16)give_bs(sop->so_flags)); else return FNS_EINVAL; if (svp->sv_ka_tcb) return(0); else return(FNS_EWOULDBLOCK);}export void tcp_end_ka (fast tcpsv_t * svp){ trace0(tcp_trace, "tcp_end_ka:\n"); if (GET_SVSOCKET_OPTION_STATUS(svp,SO_KEEPALIVE)) { if (svp->sv_ka_tcb != (tcb *)0) { t_delete((tcb *)svp->sv_ka_tcb); svp->sv_ka_tcb = (tcb *)0; } SET_SVSOCKET_OPTION_OFF(svp,SO_KEEPALIVE); } }export int tcp_ka_timer (void * uarg){#define lsvp ((tcpsv_t *) uarg) so_t * sop; trace0(tcp_trace, "tcp_ka_timer:\n"); if (lsvp->sv_ka_retrycnt-- > 0) { if (tcp_keep_alive && (lsvp->sv_ka_tcb != (tcb *)0)) { if (lsvp->sv_ka_type == NO_GARBAGE_DATA) { tcp_ska((m *)0, lsvp, false); t_start(lsvp->sv_ka_tcb, lsvp->sv_srtt << 1); } else if (lsvp->sv_ka_type == GARBAGE_DATA) { tcp_ska((m *)0, lsvp, true); t_start(lsvp->sv_ka_tcb, lsvp->sv_srtt << 1); } els
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -