int fr_checkstate(ip, fin) ip_t *ip; fr_info_t *fin;
fr_checkstate(ip, fin) ip_t *ip; fr_info_t *fin;
int fr_checkstate(ip, fin)ip_t *ip;fr_info_t *fin;{	register struct in_addr dst, src;	register ipstate_t *is, **isp;	register u_char pr;	struct icmp *ic;	tcphdr_t *tcp;	u_int hv, hlen;	if ((ip->ip_off & 0x1fff) && !(fin->fin_fi.fi_fl & FI_SHORT))		return 0;	hlen = fin->fin_hlen;	tcp = (tcphdr_t *)((char *)ip + hlen);	ic = (struct icmp *)tcp;	hv = (pr = ip->ip_p);	hv += (src.s_addr = ip->ip_src.s_addr);	hv += (dst.s_addr = ip->ip_dst.s_addr);	/*	 * Search the hash table for matching packet header info.	 */	switch (ip->ip_p)	{	case IPPROTO_ICMP :		hv += ic->icmp_id;		hv += ic->icmp_seq;		hv %= IPSTATE_SIZE;		MUTEX_ENTER(&ipf_state);		for (isp = &ips_table[hv]; (is = *isp); isp = &is->is_next)			if ((is->is_p == pr) &&			    (ic->icmp_id == is->is_icmp.ics_id) &&			    (ic->icmp_seq == is->is_icmp.ics_seq) &&			    IPPAIR(src, dst, is->is_src, is->is_dst)) {				/*				 * If we have type 0 stored, allow any icmp				 * replies through.				 */				if (is->is_icmp.ics_type &&				    is->is_icmp.ics_type != ic->icmp_type)					continue;				is->is_age = 120;				ips_stats.iss_hits++;				MUTEX_EXIT(&ipf_state);				return is->is_pass;			}		MUTEX_EXIT(&ipf_state);		break;	case IPPROTO_TCP :	    {		register u_short dport = tcp->th_dport, sport = tcp->th_sport;		register u_short win = ntohs(tcp->th_win);		tcp_seq seq, ack;		hv += dport;		hv += sport;		hv %= IPSTATE_SIZE;		MUTEX_ENTER(&ipf_state);		for (isp = &ips_table[hv]; (is = *isp); isp = &is->is_next) {			register int dl, seqskew, ackskew;			if ((is->is_p == pr) &&			    PAIRS(sport, dport, is->is_sport, is->is_dport) &&			    IPPAIR(src, dst, is->is_src, is->is_dst)) {				dl = ip->ip_len - hlen - sizeof(tcphdr_t);				/*				 * Find difference between last checked packet				 * and this packet.				 */				seq = ntohl(tcp->th_seq);				ack = ntohl(tcp->th_ack);				if (sport == is->is_sport) {					seqskew = seq - is->is_seq;					ackskew = ack - is->is_ack;				} else {					seqskew = ack - is->is_seq;					if (!is->is_ack) {						/*						 * Must be a SYN-ACK in reply						 * to a SYN.  Set age timeout						 * to 0 to stop deletion.						 */						is->is_ack = seq;						is->is_age = 0;					}					ackskew = seq - is->is_ack;				}				/*				 * Make skew values absolute				 */				if (seqskew < 0)					seqskew = -seqskew;				if (ackskew < 0)					ackskew = -ackskew;				/*				 * If the difference in sequence and ack				 * numbers is within the window size of the				 * connection, store these values and match				 * the packet.				 */				if ((seqskew <= win) && (ackskew <= win)) {					is->is_win = win;					if (sport == is->is_sport) {						is->is_seq = seq;						is->is_ack = ack;					} else {						is->is_seq = ack;						is->is_ack = seq;					}					ips_stats.iss_hits++;					/*					 * Nearing end of connection, start					 * timeout.					 */#ifdef	_KERNEL					if (!is->is_age) {						if (tcp->th_flags & TH_FIN)							is->is_age = 120;						if (tcp->th_flags & TH_RST)							is->is_age = 1;					}					MUTEX_EXIT(&ipf_state);					return is->is_pass;#else					if (tcp->th_flags & TCP_CLOSE) {						int pass = is->is_pass;						*isp = is->is_next;						isp = &ips_table[hv];						KFREE(is);						return pass;					}					return is->is_pass;#endif				}			}		}		MUTEX_EXIT(&ipf_state);		break;	    }	case IPPROTO_UDP :	    {		register u_short dport = tcp->th_dport, sport = tcp->th_sport;		hv += dport;		hv += sport;		hv %= IPSTATE_SIZE;		/*		 * Nothing else to match on but ports. and IP#'s		 */		MUTEX_ENTER(&ipf_state);		for (is = ips_table[hv]; is; is = is->is_next)			if ((is->is_p == pr) &&			    PAIRS(sport, dport, is->is_sport, is->is_dport) &&			    IPPAIR(src, dst, is->is_src, is->is_dst)) {				ips_stats.iss_hits++;				is->is_age = 120;				MUTEX_EXIT(&ipf_state);				return is->is_pass;			}		MUTEX_EXIT(&ipf_state);		break;	    }	default :		break;	}	ips_stats.iss_miss++;	return 0;}