tcp_subr.c
来自「eCos操作系统源码」· C语言 代码 · 共 1,397 行 · 第 1/3 页
C
1,397 行
if (cmd == PRC_QUENCH) notify = tcp_quench; else if (icmp_may_rst && (cmd == PRC_UNREACH_ADMIN_PROHIB || cmd == PRC_UNREACH_PORT) && ip) notify = tcp_drop_syn_sent; else if (cmd == PRC_MSGSIZE) notify = tcp_mtudisc; else if (PRC_IS_REDIRECT(cmd)) { ip = 0; notify = in_rtchange; } else if (cmd == PRC_HOSTDEAD) ip = 0; else if ((unsigned)cmd > PRC_NCMDS || inetctlerrmap[cmd] == 0) return; if (ip) { s = splnet(); th = (struct tcphdr *)((caddr_t)ip + (IP_VHL_HL(ip->ip_vhl) << 2)); inp = in_pcblookup_hash(&tcbinfo, faddr, th->th_dport, ip->ip_src, th->th_sport, 0, NULL); if (inp != NULL && inp->inp_socket != NULL) { icmp_seq = htonl(th->th_seq); tp = intotcpcb(inp); if (SEQ_GEQ(icmp_seq, tp->snd_una) && SEQ_LT(icmp_seq, tp->snd_max)) (*notify)(inp, inetctlerrmap[cmd]); } splx(s); } else in_pcbnotifyall(&tcb, faddr, inetctlerrmap[cmd], notify);}#ifdef INET6voidtcp6_ctlinput(cmd, sa, d) int cmd; struct sockaddr *sa; void *d;{ struct tcphdr th; void (*notify) __P((struct inpcb *, int)) = tcp_notify; struct ip6_hdr *ip6; struct mbuf *m; struct ip6ctlparam *ip6cp = NULL; const struct sockaddr_in6 *sa6_src = NULL; int off; struct tcp_portonly { u_int16_t th_sport; u_int16_t th_dport; } *thp; if (sa->sa_family != AF_INET6 || sa->sa_len != sizeof(struct sockaddr_in6)) return; if (cmd == PRC_QUENCH) notify = tcp_quench; else if (cmd == PRC_MSGSIZE) notify = tcp_mtudisc; else if (!PRC_IS_REDIRECT(cmd) && ((unsigned)cmd > PRC_NCMDS || inet6ctlerrmap[cmd] == 0)) return; /* if the parameter is from icmp6, decode it. */ if (d != NULL) { ip6cp = (struct ip6ctlparam *)d; m = ip6cp->ip6c_m; ip6 = ip6cp->ip6c_ip6; off = ip6cp->ip6c_off; sa6_src = ip6cp->ip6c_src; } else { m = NULL; ip6 = NULL; off = 0; /* fool gcc */ sa6_src = &sa6_any; } if (ip6) { /* * XXX: We assume that when IPV6 is non NULL, * M and OFF are valid. */ /* check if we can safely examine src and dst ports */ if (m->m_pkthdr.len < off + sizeof(*thp)) return; bzero(&th, sizeof(th)); m_copydata(m, off, sizeof(*thp), (caddr_t)&th); in6_pcbnotify(&tcb, sa, th.th_dport, (struct sockaddr *)ip6cp->ip6c_src, th.th_sport, cmd, NULL, notify); } else in6_pcbnotify(&tcb, sa, 0, (struct sockaddr *)sa6_src, 0, cmd, NULL, notify);}#endif /* INET6 *//* * Following is where TCP initial sequence number generation occurs. * * There are two places where we must use initial sequence numbers: * 1. In SYN-ACK packets. * 2. In SYN packets. * * The ISNs in SYN-ACK packets have no monotonicity requirement, * and should be as unpredictable as possible to avoid the possibility * of spoofing and/or connection hijacking. To satisfy this * requirement, SYN-ACK ISNs are generated via the arc4random() * function. If exact RFC 1948 compliance is requested via sysctl, * these ISNs will be generated just like those in SYN packets. * * The ISNs in SYN packets must be monotonic; TIME_WAIT recycling * depends on this property. In addition, these ISNs should be * unguessable so as to prevent connection hijacking. To satisfy * the requirements of this situation, the algorithm outlined in * RFC 1948 is used to generate sequence numbers. * * For more information on the theory of operation, please see * RFC 1948. * * Implementation details: * * Time is based off the system timer, and is corrected so that it * increases by one megabyte per second. This allows for proper * recycling on high speed LANs while still leaving over an hour * before rollover. * * Two sysctls control the generation of ISNs: * * net.inet.tcp.isn_reseed_interval controls the number of seconds * between seeding of isn_secret. This is normally set to zero, * as reseeding should not be necessary. * * net.inet.tcp.strict_rfc1948 controls whether RFC 1948 is followed * strictly. When strict compliance is requested, reseeding is * disabled and SYN-ACKs will be generated in the same manner as * SYNs. Strict mode is disabled by default. * */#define ISN_BYTES_PER_SECOND 1048576u_char isn_secret[32];int isn_last_reseed;MD5_CTX isn_ctx;tcp_seqtcp_new_isn(tp) struct tcpcb *tp;{ u_int32_t md5_buffer[4]; tcp_seq new_isn; /* Use arc4random for SYN-ACKs when not in exact RFC1948 mode. */ if (((tp->t_state == TCPS_LISTEN) || (tp->t_state == TCPS_TIME_WAIT)) && tcp_strict_rfc1948 == 0) return arc4random(); /* Seed if this is the first use, reseed if requested. */ if ((isn_last_reseed == 0) || ((tcp_strict_rfc1948 == 0) && (tcp_isn_reseed_interval > 0) && (((u_int)isn_last_reseed + (u_int)tcp_isn_reseed_interval*hz) < (u_int)ticks))) { read_random_unlimited(&isn_secret, sizeof(isn_secret)); isn_last_reseed = ticks; } /* Compute the md5 hash and return the ISN. */ MD5Init(&isn_ctx); MD5Update(&isn_ctx, (u_char *) &tp->t_inpcb->inp_fport, sizeof(u_short)); MD5Update(&isn_ctx, (u_char *) &tp->t_inpcb->inp_lport, sizeof(u_short));#ifdef INET6 if ((tp->t_inpcb->inp_vflag & INP_IPV6) != 0) { MD5Update(&isn_ctx, (u_char *) &tp->t_inpcb->in6p_faddr, sizeof(struct in6_addr)); MD5Update(&isn_ctx, (u_char *) &tp->t_inpcb->in6p_laddr, sizeof(struct in6_addr)); } else#endif { MD5Update(&isn_ctx, (u_char *) &tp->t_inpcb->inp_faddr, sizeof(struct in_addr)); MD5Update(&isn_ctx, (u_char *) &tp->t_inpcb->inp_laddr, sizeof(struct in_addr)); } MD5Update(&isn_ctx, (u_char *) &isn_secret, sizeof(isn_secret)); MD5Final((u_char *) &md5_buffer, &isn_ctx); new_isn = (tcp_seq) md5_buffer[0]; new_isn += ticks * (ISN_BYTES_PER_SECOND / hz); return new_isn;}/* * When a source quench is received, close congestion window * to one segment. We will gradually open it again as we proceed. */voidtcp_quench(inp, _errno) struct inpcb *inp; int _errno;{ struct tcpcb *tp = intotcpcb(inp); if (tp) tp->snd_cwnd = tp->t_maxseg;}/* * When a specific ICMP unreachable message is received and the * connection state is SYN-SENT, drop the connection. This behavior * is controlled by the icmp_may_rst sysctl. */voidtcp_drop_syn_sent(inp, _errno) struct inpcb *inp; int _errno;{ struct tcpcb *tp = intotcpcb(inp); if (tp && tp->t_state == TCPS_SYN_SENT) tcp_drop(tp, _errno);}/* * When `need fragmentation' ICMP is received, update our idea of the MSS * based on the new value in the route. Also nudge TCP to send something, * since we know the packet we just sent was dropped. * This duplicates some code in the tcp_mss() function in tcp_input.c. */voidtcp_mtudisc(inp, _errno) struct inpcb *inp; int _errno;{ struct tcpcb *tp = intotcpcb(inp); struct rtentry *rt; struct rmxp_tao *taop; struct socket *so = inp->inp_socket; int offered; int mss;#ifdef INET6 int isipv6 = (tp->t_inpcb->inp_vflag & INP_IPV6) != 0;#endif /* INET6 */ if (tp) {#ifdef INET6 if (isipv6) rt = tcp_rtlookup6(inp); else#endif /* INET6 */ rt = tcp_rtlookup(inp); if (!rt || !rt->rt_rmx.rmx_mtu) { tp->t_maxopd = tp->t_maxseg =#ifdef INET6 isipv6 ? tcp_v6mssdflt :#endif /* INET6 */ tcp_mssdflt; return; } taop = rmx_taop(rt->rt_rmx); offered = taop->tao_mssopt; mss = rt->rt_rmx.rmx_mtu -#ifdef INET6 (isipv6 ? sizeof(struct ip6_hdr) + sizeof(struct tcphdr) :#endif /* INET6 */ sizeof(struct tcpiphdr)#ifdef INET6 )#endif /* INET6 */ ; if (offered) mss = min(mss, offered); /* * XXX - The above conditional probably violates the TCP * spec. The problem is that, since we don't know the * other end's MSS, we are supposed to use a conservative * default. But, if we do that, then MTU discovery will * never actually take place, because the conservative * default is much less than the MTUs typically seen * on the Internet today. For the moment, we'll sweep * this under the carpet. * * The conservative default might not actually be a problem * if the only case this occurs is when sending an initial * SYN with options and data to a host we've never talked * to before. Then, they will reply with an MSS value which * will get recorded and the new parameters should get * recomputed. For Further Study. */ if (tp->t_maxopd <= mss) return; tp->t_maxopd = mss; if ((tp->t_flags & (TF_REQ_TSTMP|TF_NOOPT)) == TF_REQ_TSTMP && (tp->t_flags & TF_RCVD_TSTMP) == TF_RCVD_TSTMP) mss -= TCPOLEN_TSTAMP_APPA; if ((tp->t_flags & (TF_REQ_CC|TF_NOOPT)) == TF_REQ_CC && (tp->t_flags & TF_RCVD_CC) == TF_RCVD_CC) mss -= TCPOLEN_CC_APPA;#if (MCLBYTES & (MCLBYTES - 1)) == 0 if (mss > MCLBYTES) mss &= ~(MCLBYTES-1);#else if (mss > MCLBYTES) mss = mss / MCLBYTES * MCLBYTES;#endif if (so->so_snd.sb_hiwat < mss) mss = so->so_snd.sb_hiwat; tp->t_maxseg = mss; tcpstat.tcps_mturesent++; tp->t_rtttime = 0; tp->snd_nxt = tp->snd_una; tcp_output(tp); }}/* * Look-up the routing entry to the peer of this inpcb. If no route * is found and it cannot be allocated the return NULL. This routine * is called by TCP routines that access the rmx structure and by tcp_mss * to get the interface MTU. */struct rtentry *tcp_rtlookup(inp) struct inpcb *inp;{ struct route *ro; struct rtentry *rt; ro = &inp->inp_route; rt = ro->ro_rt; if (rt == NULL || !(rt->rt_flags & RTF_UP)) { /* No route yet, so try to acquire one */ if (inp->inp_faddr.s_addr != INADDR_ANY) { ro->ro_dst.sa_family = AF_INET; ro->ro_dst.sa_len = sizeof(struct sockaddr_in); ((struct sockaddr_in *) &ro->ro_dst)->sin_addr = inp->inp_faddr; rtalloc(ro); rt = ro->ro_rt; } } return rt;}#ifdef INET6struct rtentry *tcp_rtlookup6(inp) struct inpcb *inp;{#ifdef NEW_STRUCT_ROUTE struct route *ro6;#else struct route_in6 *ro6;#endif struct rtentry *rt; ro6 = &inp->in6p_route; rt = ro6->ro_rt; if (rt == NULL || !(rt->rt_flags & RTF_UP)) { /* No route yet, so try to acquire one */ if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) { struct sockaddr_in6 *dst6; dst6 = (struct sockaddr_in6 *)&ro6->ro_dst; dst6->sin6_family = AF_INET6; dst6->sin6_len = sizeof(*dst6); dst6->sin6_addr = inp->in6p_faddr; rtalloc((struct route *)ro6); rt = ro6->ro_rt; } } return rt;}#endif /* INET6 */#ifdef IPSEC/* compute ESP/AH header size for TCP, including outer IP header. */size_tipsec_hdrsiz_tcp(tp) struct tcpcb *tp;{ struct inpcb *inp; struct mbuf *m; size_t hdrsiz; struct ip *ip;#ifdef INET6 struct ip6_hdr *ip6;#endif /* INET6 */ struct tcphdr *th; if ((tp == NULL) || ((inp = tp->t_inpcb) == NULL)) return 0; MGETHDR(m, M_DONTWAIT, MT_DATA); if (!m) return 0;#ifdef INET6 if ((inp->inp_vflag & INP_IPV6) != 0) { ip6 = mtod(m, struct ip6_hdr *); th = (struct tcphdr *)(ip6 + 1); m->m_pkthdr.len = m->m_len = sizeof(struct ip6_hdr) + sizeof(struct tcphdr); tcp_fillheaders(tp, ip6, th); hdrsiz = ipsec6_hdrsiz(m, IPSEC_DIR_OUTBOUND, inp); } else#endif /* INET6 */ { ip = mtod(m, struct ip *); th = (struct tcphdr *)(ip + 1); m->m_pkthdr.len = m->m_len = sizeof(struct tcpiphdr); tcp_fillheaders(tp, ip, th); hdrsiz = ipsec4_hdrsiz(m, IPSEC_DIR_OUTBOUND, inp); } m_free(m); return hdrsiz;}#endif /*IPSEC*//* * Return a pointer to the cached information about the remote host. * The cached information is stored in the protocol specific part of * the route metrics. */struct rmxp_tao *tcp_gettaocache(inp) struct inpcb *inp;{ struct rtentry *rt;#ifdef INET6 if ((inp->inp_vflag & INP_IPV6) != 0) rt = tcp_rtlookup6(inp); else#endif /* INET6 */ rt = tcp_rtlookup(inp); /* Make sure this is a host route and is up. */ if (rt == NULL || (rt->rt_flags & (RTF_UP|RTF_HOST)) != (RTF_UP|RTF_HOST)) return NULL; return rmx_taop(rt->rt_rmx);}/* * Clear all the TAO cache entries, called from tcp_init. * * XXX * This routine is just an empty one, because we assume that the routing * routing tables are initialized at the same time when TCP, so there is * nothing in the cache left over. */static voidtcp_cleartaocache(){}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?