📄 tcp_input.c
字号:
#ifndef lintstatic char *sccsid = "@(#)tcp_input.c 4.9 (ULTRIX) 3/8/91";#endif lint/************************************************************************ * * * Copyright (c) 1985 by * * Digital Equipment Corporation, Maynard, MA * * All rights reserved. * * * * This software is furnished under a license and may be used and * * copied only in accordance with the terms of such license and * * with the inclusion of the above copyright notice. This * * software or any other copies thereof may not be provided or * * otherwise made available to any other person. No title to and * * ownership of the software is hereby transferred. * * * * This software is derived from software received from the * * University of California, Berkeley, and from Bell * * Laboratories. Use, duplication, or disclosure is subject to * * restrictions under license agreements with University of * * California and with AT&T. * * * * The information in this software is subject to change without * * notice and should not be construed as a commitment by Digital * * Equipment Corporation. * * * * Digital assumes no responsibility for the use or reliability * * of its software on equipment which is not supplied by Digital. * * * ************************************************************************//************************************************************************ * Modification History * * * 03-Mar-91 - Michael G. Mc Menemy * Fix oob code to handle both XTI and Berkeley style oob data. * * 03-Mar-91 - Michael G. Mc Menemy * Fix rexmt when all outstanding packets have been acked. * * 03-Mar-91 - Michael G. Mc Menemy * Fix unaligned access panic in oob code. * * 16-Jan-91 - U. Sinkewicz * Fix to stack overwrite panic in LOOPBACK mode from tcp_output() * and tcp_input() thrashing. * * 09-oct-90 - jaw * merge in mm fix for deadlock caused by bug in tcp_input. * * 17-Jul-90 - jsd * remove so->ref panic since it's optimized out for single-cpu * * 16-July-90 - lp * Leave trailers for machines that use them (IFF_NOTRAILERS). * * 18-June-90 - lp * Remove trailers in max seg calculation for FDDI. Note that * ethernet will now no longer do trailers encapsulation. * * 14-May-90 - R. Bhanukitsiri * Fix "m_free has bad m_cltype" panic by not freeing up old * out-of-band data when a new out-of-band data arrives. * * 26-Jan-90 - gmm * Make socket pointer in tcp_input() volatile * * 3-Jan-90 - U. Sinkewicz * Performance enhancements to uniprocessor kernel. * * 2-Dec-89 - jsd * Panic during so->ref check for single-cpu so we don't hang * * 9-Nov-89 - Ursula Sinkewicz * Fix to the case when we have a SYN in the window and are * responding with an RST. * * 30-May-89 - Ursula Sinkewicz * Added so->ref field which is used in conjunction with SO_LOCK * to fix smp hole caused by unlocking the socket and locking it * again. Problem is that the socket may have changed or been * freed while unlocked. The unlocking is necessary to accommodate * the lock heirarchy and sleeps. * * 05-05-89 - Michael G. Mc Menemy * Add XTI support. * * 27-2-89 - Ursula Sinkewicz * Lowered ipl on lk_rtentry, lk_ifnet, lk_in_ifaddr; * replace tcpstatictics with a macro, as per lp changes * from 3/16/89. * * 3-3-89 - Ursula Sinkewicz * Added support for new directory layout to smp file. * * 2-23-89 - Ursula Sinkewicz * Spool dangling reference info to error logger. Added * change to eleminate willbefreed flag which coincides * with uipc_socket.c changes. * * 12-5-88 - Ursula Sinkewicz * SMP - release memory for socket/pcb on close/shutdown/ * abort. * * 15-Jan-88 lp * Merge of final 43BSD changes. * * * 6/25/87 - Ursula Sinkewicz * * Major cleanup of freeondrop flag. * * * 04/27/87 - Larry Cohen * Send response to everything except a reset. Code * effected is right after "dropafterack:" * * 01/28/87 - Larry Cohen * Look for resets before checking to see if input is * within acceptable range. This is because a response * to KEEPALIVE messages is not within an acceptable range. * If the response to our KEEPALIVE message is a reset * (which is the case if the remote side has crashed and * come up again soon) we would otherwise drop the RST * message and leave local processes hanging. * * 01/28/87 - Larry Cohen * update max_sndwnd * 12/16/86 - lp * * Start timer on FIN_WAIT_2 state if CANTRECVMORE * * Larry Cohen - 09/16/85 * * Add 43bsd alpha tape changes for subnet routing * * * ************************************************************************//* * Copyright (c) 1982, 1986 Regents of the University of California. * All rights reserved. The Berkeley software License Agreement * specifies the terms and conditions for redistribution. * * tcp_input.c 7.13 (Berkeley) 11/13/87 */#include "../h/param.h"#include "../h/systm.h"#include "../h/smp_lock.h"#include "../h/mbuf.h"#include "../h/protosw.h"#include "../h/socket.h"#include "../h/socketvar.h"#include "../h/errno.h"#include "../net/net/if.h"#include "../net/net/route.h"#include "../net/netinet/in.h"#include "../net/netinet/in_pcb.h"#include "../net/netinet/in_systm.h"#include "../net/netinet/ip.h"#include "../net/netinet/ip_var.h"#include "../net/netinet/tcp.h"#include "../net/netinet/tcp_fsm.h"#include "../net/netinet/tcp_seq.h"#include "../net/netinet/tcp_timer.h"#include "../net/netinet/tcp_var.h"#include "../net/netinet/tcpip.h"#include "../net/netinet/tcp_debug.h"#ifdef XTIextern char *tcpstates[];extern int xti_debug; /* general debug */#define PRINTXTID(level, msg) \ /* \ * level: \ * 0x01 = generate events; \ * 0x04 = acceptchk/abort support; \ * 0x08 = peek events; \ * 0x10 = tpdu T_MORE support; \ * 0x20 = oob mark; \ * 0x40 = option neg. \ * 0x80 = protocol; \ */ \ if (xti_debug & (level)) \ cprintf((msg))#else#define PRINTXTID(level, msg)#endif XTIint tcpprintfs = 0;int tcpcksum = 1;int tcprexmtthresh = 3;struct tcpiphdr tcp_saveti;extern tcpnodelack;struct tcpcb *tcp_newtcpcb();/* * Insert segment ti into reassembly queue of tcp with * control block tp. Return TH_FIN if reassembly now includes * a segment with FIN. The macro form does the common case inline * (segment is the next to be received on an established connection, * and the queue is empty), avoiding linkage into and removal * from the queue and repetition of various conversions. */#ifdef XTI#define TCP_REASS(tp, ti, m, so, flags) { \ if ((ti)->ti_seq == (tp)->rcv_nxt && \ (tp)->seg_next == (struct tcpiphdr *)(tp) && \ (tp)->t_state == TCPS_ESTABLISHED) { \ (tp)->rcv_nxt += (ti)->ti_len; \ flags = (ti)->ti_flags & TH_FIN; \ TCPSTAT(tcps_rcvpack++);\ TCPSTAT(tcps_rcvbyte += (ti)->ti_len);\/*#ifdef XTI */\ if ((so)->so_xticb.xti_epvalid) { \ if ((so)->so_xticb.xti_evtenabled) { \ if (mbuf_any_len((m)) > 0) { \ (so)->so_xticb.xti_evtarray[XTI_EVT_T_DATA]++; \ PRINTXTID(1, ("T_DATA (#1) 1 event generated\n")); \ }}} \/*#endif XTI */\ sbappend(&(so)->so_rcv, (m)); \ sorwakeup(so); \ } else \ (flags) = tcp_reass((tp), (ti)); \}#else#define TCP_REASS(tp, ti, m, so, flags) { \ if ((ti)->ti_seq == (tp)->rcv_nxt && \ (tp)->seg_next == (struct tcpiphdr *)(tp) && \ (tp)->t_state == TCPS_ESTABLISHED) { \ (tp)->rcv_nxt += (ti)->ti_len; \ flags = (ti)->ti_flags & TH_FIN; \ TCPSTAT(tcps_rcvpack++);\ TCPSTAT(tcps_rcvbyte += (ti)->ti_len);\ sbappend(&(so)->so_rcv, (m)); \ sorwakeup(so); \ } else \ (flags) = tcp_reass((tp), (ti)); \}#endif XTItcp_reass(tp, ti) register struct tcpcb *tp; register struct tcpiphdr *ti;{ register struct tcpiphdr *q; struct socket *so = tp->t_inpcb->inp_socket; struct mbuf *m; int flags; /* * Call with ti==0 after become established to * force pre-ESTABLISHED data up to user socket. */ if (ti == 0) goto present; /* * Find a segment which begins after this one does. */ for (q = tp->seg_next; q != (struct tcpiphdr *)tp; q = (struct tcpiphdr *)q->ti_next) if (SEQ_GT(q->ti_seq, ti->ti_seq)) break; /* * If there is a preceding segment, it may provide some of * our data already. If so, drop the data from the incoming * segment. If it provides all of our data, drop us. */ if ((struct tcpiphdr *)q->ti_prev != (struct tcpiphdr *)tp) { register int i; q = (struct tcpiphdr *)q->ti_prev; /* conversion to int (in i) handles seq wraparound */ i = q->ti_seq + q->ti_len - ti->ti_seq; if (i > 0) { if (i >= ti->ti_len) { TCPSTAT(tcps_rcvduppack++); TCPSTAT(tcps_rcvdupbyte += ti->ti_len); goto drop; } m_adj(dtom(ti), i); ti->ti_len -= i; ti->ti_seq += i; } q = (struct tcpiphdr *)(q->ti_next); } TCPSTAT(tcps_rcvoopack++); TCPSTAT(tcps_rcvoobyte += ti->ti_len); /* * While we overlap succeeding segments trim them or, * if they are completely covered, dequeue them. */ while (q != (struct tcpiphdr *)tp) { register int i = (ti->ti_seq + ti->ti_len) - q->ti_seq; if (i <= 0) break; if (i < q->ti_len) { q->ti_seq += i; q->ti_len -= i; m_adj(dtom(q), i); break; } q = (struct tcpiphdr *)q->ti_next; m = dtom(q->ti_prev); remque(q->ti_prev); m_freem(m); } /* * Stick new segment in its place. */ insque(ti, q->ti_prev);present: /* * Present data to user, advancing rcv_nxt through * completed sequence space. */ if (TCPS_HAVERCVDSYN(tp->t_state) == 0) return (0); ti = tp->seg_next; if (ti == (struct tcpiphdr *)tp || ti->ti_seq != tp->rcv_nxt) return (0); if (tp->t_state == TCPS_SYN_RECEIVED && ti->ti_len) return (0); do { tp->rcv_nxt += ti->ti_len; flags = ti->ti_flags & TH_FIN; remque(ti); m = dtom(ti); ti = (struct tcpiphdr *)ti->ti_next; if (so->so_state & SS_CANTRCVMORE){ m_freem(m); }#ifdef XTI else { sbappend(&so->so_rcv, m); if (so->so_xticb.xti_epvalid) if (so->so_xticb.xti_evtenabled) { if (ti->ti_len) { so->so_xticb.xti_evtarray[XTI_EVT_T_DATA] ++; PRINTXTID(1, ("T_DATA (#2) 1 event generated\n")); } } }#else else sbappend(&so->so_rcv, m);#endif XTI } while (ti != (struct tcpiphdr *)tp && ti->ti_seq == tp->rcv_nxt); sorwakeup(so); return (flags);drop: m_freem(dtom(ti));return (0);}/* * TCP input routine, follows pages 65-76 of the * protocol specification dated September, 1981 very closely. *//* * SMP: enter without socket lock set. Come into the routine only * through the interrupt handler and in LOOPBACK mode. */tcp_input(m0) struct mbuf *m0;{ register struct tcpiphdr *ti; struct inpcb *inp; struct inpcb *inp_temp; register struct mbuf *m; struct mbuf *om = 0; int len, tlen, off; register struct tcpcb *tp = 0; register int tiflags; int todrop, acked, ourfinisacked, needoutput = 0; volatile struct socket *so = NULL; /* SMP */ short ostate; struct in_addr laddr; int dropsocket = 0; int iss = 0; int freeondrop = 1; /* SMP */ struct socket *so_tmp; /* SMP */ int status = 0; /* SMP */ struct socket *so_addr = NULL; /* SMP */ int owner = 0; /* SMP */ int error = 0; int waitcnt; /*SMP*/#ifdef XTI short xti_precedence; struct secoptions xti_secopt;#endif XTI TCPSTAT(tcps_rcvtotal++); /* * Get IP and TCP header together in first mbuf. * Note: IP leaves IP header in first mbuf. */ m = m0; ti = mtod(m, struct tcpiphdr *);#ifdef XTI /* get precedence from IP header */ xti_precedence = (((struct ip *)ti)->ip_tos & (0x07)); /* get IP Security options */ if (xti_ip_dooptions(((struct ip *) ti), &xti_secopt)) { xti_secopt.security = T_UNUSED; xti_secopt.compartment = T_UNUSED; xti_secopt.handling = T_UNUSED; xti_secopt.tcc = T_UNUSED; }#endif XTI if (((struct ip *)ti)->ip_hl > (sizeof (struct ip) >> 2)) ip_stripoptions((struct ip *)ti, (struct mbuf *)0); if (m->m_off > MMAXOFF || m->m_len < sizeof (struct tcpiphdr)) { if ((m = m_pullup(m, sizeof (struct tcpiphdr))) == 0) { TCPSTAT(tcps_rcvshort++); return; } ti = mtod(m, struct tcpiphdr *); } /* * Checksum extended TCP header and data. */ tlen = ((struct ip *)ti)->ip_len; len = sizeof (struct ip) + tlen;#ifdef TCPLOOPBACK if (tcpcksum && (ti->ti_src.s_addr != ti->ti_dst.s_addr)) {#else if (tcpcksum) {#endif TCPLOOPBACK ti->ti_next = ti->ti_prev = 0; ti->ti_x1 = 0; ti->ti_len = (u_short)tlen; ti->ti_len = htons((u_short)ti->ti_len); if (ti->ti_sum = in_cksum(m, len)) { if (tcpprintfs) printf("tcp sum: src %x\n", ti->ti_src); TCPSTAT(tcps_rcvbadsum++); freeondrop = 0; goto drop; } } /* * Check that TCP offset makes sense, * pull out TCP options and adjust length. */ off = ti->ti_off << 2; if (off < sizeof (struct tcphdr) || off > tlen) { if (tcpprintfs) printf("tcp off: src %x off %d\n", ti->ti_src, off); TCPSTAT(tcps_rcvbadoff++); freeondrop = 0; goto drop; } tlen -= off; ti->ti_len = tlen; if (off > sizeof (struct tcphdr)) { if (m->m_len < sizeof(struct ip) + off) { if ((m = m_pullup(m, sizeof (struct ip) + off)) == 0) { TCPSTAT(tcps_rcvshort++); return; } ti = mtod(m, struct tcpiphdr *); } om = m_get(M_DONTWAIT, MT_DATA); if (om == 0) { freeondrop = 0; goto drop; } om->m_len = off - sizeof (struct tcphdr); { caddr_t op = mtod(m, caddr_t) + sizeof (struct tcpiphdr); bcopy(op, mtod(om, caddr_t), (unsigned)om->m_len); m->m_len -= om->m_len; bcopy(op+om->m_len, op, (unsigned)(m->m_len-sizeof (struct tcpiphdr))); } } tiflags = ti->ti_flags; /* * Drop TCP and IP headers; TCP options were dropped above. */ m->m_off += sizeof(struct tcpiphdr); m->m_len -= sizeof(struct tcpiphdr); /* * Convert TCP protocol specific fields to host format. */ ti->ti_seq = ntohl(ti->ti_seq); ti->ti_ack = ntohl(ti->ti_ack); ti->ti_win = ntohs(ti->ti_win); ti->ti_urp = ntohs(ti->ti_urp); /* * Locate pcb for segment. */ /* 4.13.89.us You need to start with an owner check on * the tcb because there is an obscure path here from * the slow timers which set lk_tcb. */findpcb: if ( smp && !(smp_owner(&lk_tcb)) ){ owner = 1; smp_lock(&lk_tcb, LK_RETRY); } else owner = 0; inp = in_pcblookup (&tcb, ti->ti_src, ti->ti_sport, ti->ti_dst, ti->ti_dport, INPLOOKUP_WILDCARD);loop1: if (inp == 0) { freeondrop = 0; tp = 0; so = NULL; /* This is for tcp_respond() locking. */ if ( owner){ smp_unlock(&lk_tcb); owner = 0; } goto dropwithreset; } so = inp->inp_socket; if (smp){ /* try only once to avoid DEADLOCK. we have lk_tcb and need to get it released as soon as possible. */ if (smp_lock(&so->lk_socket, LK_ONCE) || smp_lock(&so->lk_socket, LK_ONCE)) { if (so->ref > 0){ /* if some one owns it then backoff */ smp_unlock(&so->lk_socket); smp_unlock(&lk_tcb); waitcnt = 1000000; /* need some limit to wait */ while (so->ref > 0 && waitcnt--) ; if (owner) owner=0; else smp_lock(&lk_tcb,LK_RETRY); goto findpcb;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -