📄 tcpmisc.c
字号:
for (svp = (tcpsv_t *)tcp_q.q_next; svp != (tcpsv_t *)&tcp_q; svp = (tcpsv_t *)svp->sv_q.q_next) { if ( (svp->sv_state == CLOSED) || (svp->sv_state == LISTEN) ) continue; /* Note: tcp_set_send_mss will make sure that if the path MTU is larger than the MSS the peer sent us in a SYN MSS option, that we don't set the MSS larger than that option. */ if (svp->sv_dest.ip_nethost == hostaddr) { tcp_set_send_mss (svp, (u16) new_mss, TCP_MSS_SOURCE_PATH_MTU ); } } /* for */ return(0);} /* tcp_pmtu_change_notif */#endif /* IP_RFC_1191 *//************************************************************************* ** Function : ** ** Description : ** ** ** Parameters : None. ** ** Return : None. ** *************************************************************************//* 'ip_icmp' calls on us here. Two types of ICMP messages arrive here; * Destination unreachable and Source Quench. */export st tcp_icmp (fast m * mp){ fast u8 type; fast u8 code; fast TCPH_T * tcphp; fast tcpsv_t * svp; int err; use_critical; trace0(tcp_trace, "tcp_icmp:\n"); type = (u8)mp->m_p0; /* ICMP type */ code = (u8)mp->m_p1; /* ICMP code */ /* The tcp header in this context only contains port numbers and * a sequence number */ debug2(tcp_debug, "tcp_icmp: received icmp packet, type %d, code, %d\n", type, code); /* pointer to bogus TCP packet (8 bytes worth) */ tcphp = (TCPH_T *)mp->m_cp; err = FNS_ENOERR; /* scan the tcp_q for state vectors to harass */ critical; svp = (tcpsv_t *)tcp_q.q_next; while (svp != (tcpsv_t *)&tcp_q) { sv_bind(svp, tcp_icmp, true); normal; if (svp->sv_q.q_flags & F_Q_ZAPPED) /* it's a zombie! */ goto nextone; if (svp->sv_state == CLOSED) /* don't target closed state vectors */ goto nextone; /* source, destination ports and destination host must * match EXACTLY */ if ( (ntohs(svp->sv_src.ip_port) == NetToHost16(&tcphp[TCPH_SPORT]) ) && (ntohs(svp->sv_dest.ip_port) == NetToHost16(&tcphp[TCPH_DPORT]) ) && (svp->sv_dest.ip_nethost == mp->m_dest.a_ipa.ip_nethost) ) { /* match */ fast so_t * sop; switch (type) { case ICMP_DUR: /* destination unreachable message */#if 0 /* removed by MBM when implementing path MTU discovery */ if (svp->sv_state != SYN_SENT) /* only affect connections */ break;#endif /* Set the error code according to the condtion being reported */ switch (code) { case DUR_FRAG: /* frag. needed & DF set */ /* By the time this notification gets delivered to us, we will already have adjusted our MSS due to the broadcast PMTU change notification we received (done from ip_icmp before sending this message up to us). The only thing to do here is initiate retransmission because we are being informed that a segment was discarded on this connection. That retransmission will use the new, smaller MSS */ (void) t_start(svp->sv_rextcb, 1); break; case DUR_HOST: /* host unreachable */ err = FNS_EHOSTUNREACH; break; case DUR_PROTO: /* protocol unreachable */ err = FNS_ENOPROTOOPT; break; case DUR_PORT: /* port unreachable */ err = FNS_ECONNREFUSED; break; err = FNS_EMSGSIZE; break; case DUR_NET: /* network unreachable */ svp->sv_err = FNS_ENETUNREACH; break; case DUR_ROUTE: /* source route failed */ default: /* some bogus code */ err = FNS_ENETUNREACH; break; } /* switch */ /* If its a fatal error for the connection, reset ourselves. Otherwise, we've already done the processing we need to do for this message */ if (err != FNS_ENOERR) { tcp_rslf(svp, err); } break; case ICMP_SQ : /* source quench message */ /* Here we immediately drop the send queue * size to one, and set (or increase) the * amount of time we will leave it at one * before starting to increase it. The * countdown is decremented in tcp_perftimer, * and there the send queue size is gradually * increased back to the maximum, if no * further SQ requests come in. */ sop = sv_valid_sop(svp, sop); if (sop != (so_t *)0) { gq_max_set(&sop->so_sq, (int)svp->sv_mss); /* Set (or increase) slowdown period */ svp->sv_sqcntdwn += 60000 / MS_PER_TICK; /* Go into re-xmit mode */ svp->sv_flags |= SV_RIP;#ifdef TCP_SS_CA_FRETR_FREC M32M(svp->sv_rexmt_seqno, =, svp->sv_suna);#endif } break; } }nextone: /* detach the state vector, and pick up the next one */ critical; svp = sv_detach(svp, tcp_icmp, true); } /* switch */ normal; return (st)mp->m_dispfn;}#ifdef TCP_QUIET/* turn off tcp_quiet time and wakeup any process that is napping on * this event *//*ARGSUSED; this routine is called from a table, so * uarg is declared but not used*/pflocal int tcp_noisy (void * uarg){ tcp_quiet = (tcb *)0; os_wakeup((char *)&tcp_quiet); return 0;}#endif/* TCP initialization */export int tcpinit (pr_t * prp){ trace0(tcp_trace, "tcpinit:\n"); if (!tcp_initialized) {#ifdef TCP_QUIET i32 residual;#endif tcp_initialized = true; tcp_port = ((int) OS_RAND) & 0xFF; q_init(&tcp_q, F_Q_HEADER); tcp_prp = prp;#ifdef TCP_QUIET /* TCP quiet time [9.2.14.3.1, pg. 88] */ /* BOOT_TIME is the minimum amount of time (in seconds) * that it takes for the system to boot-up (cold boot) UNTIL * FUSION first initializes (gets to this routine). Since * TCP cannot know what previously used sequence numbers * have been used in earlier lifes, it must wait for one * maximum segment lifetime (4:15 minutes) UNTIL it generates * any TCP segment. Since there is no way for TCP to be * generating segments during reboot, the amount of time * it takes to reboot can be subtracted out, thus allowing * the use of TCP somewhat sooner. * * BOOT_TIME is a configuration dependant constant, and * should be defined in <config.h> */ /* Fudge BOOT_TIME by 5 seconds */ residual = ONEMSL - (max((u32)BOOT_TIME - 5, 0)*1000L); residual = max(1, residual); /* start the timer for tcp_quiet */ tcp_quiet = t_new((tcb *)0, tcp_noisy, (void *)0, (u32)residual, F_T_ONESHOT);#endif#ifdef TCP_TRANSACTION_TCP t_tcp_initialize();#endif /* TCP_TRANSACTION_TCP */ } return 0; /* indicate that TCP is now up */}/******************************************************************************//* * Used by getpeername and getsockname, Getpeername * is type 1, getsockname is type 2. Note that * getpeername is only valid if we're connected. */export inttcp_outaddr (so_t * sop, saddr * name, int * namelen, int type){ fast tcpsv_t * svp; struct in_sockaddr * is_addrp; use_critical; if ((name == (saddr *)0) || (namelen == (int *)0) || (*namelen < sizeof(struct in_sockaddr))) return FNS_EFAULT; *namelen = min(sizeof(struct in_sockaddr), *namelen); is_addrp = (struct in_sockaddr *)name; critical; if ((svp = sop->so_svp) == (tcpsv_t *)0) { normal; debug0(tcp_debug, "tcp_outaddr: no state vector\n"); return FNS_ENOTCONN; } if( type ) { /* Not connected */ switch (svp->sv_state) { case SYN_RECVD: case ESTAB: case FIN1_WAIT: case FIN2_WAIT: case LAST_ACK: break; default: normal; return FNS_ENOTCONN; } } sv_bind(svp, tcp_outaddr, true); normal; is_addrp->sin_family = AF_INET; if (type == 0) /* source address */ { is_addrp->sin_addr.s_addr = svp->sv_src.ip_nethost; is_addrp->sin_port = ntohs(svp->sv_src.ip_port); } else /* destination address */ { is_addrp->sin_addr.s_addr = svp->sv_dest.ip_nethost; is_addrp->sin_port = ntohs(svp->sv_dest.ip_port); } sv_detach(svp, tcp_outaddr, true); return 0;}/******************************************************************************/export void sv_nstate (fast char * msg, fast tcpsv_t * svp, fast u16 new_state){#ifdef DEBUG so_t * sop;#endif use_critical; critical; assert(svp->sv_refcnt != 0, "sv_nstate: state vector not bound\n"); assert(new_state <= TIME_WAIT, "sv_nstate: bogus new state\n");#ifdef DEBUG if (msg == (char *)0) msg = "<dunno>"; if (svp->sv_state != new_state) { /* state change */ /* compute sop once */ sop = svp->sv_sop; if (sop == (so_t *)0) trace3(tcp_tstate, "%s: [*] %s => %s\n", msg, tcp_st(svp->sv_state), tcp_st(new_state)); else trace4(tcp_tstate, "%s: [%d] %s => %s\n", msg, sop->so_index, tcp_st(svp->sv_state), tcp_st(new_state)); }#endif#if 0 /* debugging stuff put in by MBM */ {static int ctr = 0; os_printf("\n(%u) sv_nstate -- (svp=%p) (%d): transitioning from %d to %d\n", t_time,svp,++ctr,svp->sv_state,new_state); }#endif svp->sv_state = new_state; if (svp->sv_refcnt > 1) os_wakeup((char *)&svp->sv_state); normal;}/* bind a state vector and a socket together */export void sv_so_bind (fast tcpsv_t * svp, fast so_t * sop){ use_critical; /* the state vector must be given to us bound */ assert(svp->sv_refcnt != 0, "sv_so_bind: svp not bound\n"); critical; assert(sop->so_svp == (tcpsv_t *)0, "sv_so_bind: socket already bound\n"); assert(svp->sv_sop == (so_t *)0, "sv_so_bind: state vector already bound (incorrectly too...)\n"); sv_bind(sop->so_svp = svp, sop, false); /* bind here because socket references it */ svp->sv_sop = sop; svp->sv_soindx = sop->so_index; /* for validation use later */ normal;}/* remove the socket binding from a state vector */export void sv_so_detach (fast tcpsv_t * svp){ fast so_t * sop; use_critical; critical; sop = svp->sv_sop; if (sop == (so_t *)0) { normal; debug0(tcp_debug, "sv_so_detach: no sop\n"); return; } sop->so_svp = (tcpsv_t *)0; svp->sv_sop = (so_t *)0; svp->sv_soindx = 0; sv_detach(svp, sop, false);}#if defined(SNMP) || defined(WANT_NETWORK_STATISTICS) export u32 countTcpCurrEstab (void){ fast tcpsv_t * svp; u32 count; use_critical; count = 0; if (tcp_prp == (pr_t *)0) return count; /* allow time to initialize */ critical; for (svp = (tcpsv_t *)tcp_q.q_next; svp != (tcpsv_t *)&tcp_q; svp = (tcpsv_t *)svp->sv_q.q_next)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -