csum = (u16)csum_fold(skb->csum); 
static int ipgre_rcv(struct sk_buff *skb){	struct iphdr *iph;	u8     *h;	u16    flags;	u16    csum = 0;	u32    key = 0;	u32    seqno = 0;	struct ip_tunnel *tunnel;	int    offset = 4;	if (!pskb_may_pull(skb, 16))		goto drop_nolock;	iph = skb->nh.iph;	h = skb->data;	flags = *(u16*)h;	if (flags&(GRE_CSUM|GRE_KEY|GRE_ROUTING|GRE_SEQ|GRE_VERSION)) {		/* - Version must be 0.		   - We do not support routing headers.		 */		if (flags&(GRE_VERSION|GRE_ROUTING))			goto drop_nolock;		if (flags&GRE_CSUM) {			if (skb->ip_summed == CHECKSUM_HW) {				csum = (u16)csum_fold(skb->csum);				if (csum)					skb->ip_summed = CHECKSUM_NONE;			}			if (skb->ip_summed == CHECKSUM_NONE) {				skb->csum = skb_checksum(skb, 0, skb->len, 0);				skb->ip_summed = CHECKSUM_HW;				csum = (u16)csum_fold(skb->csum);			}			offset += 4;		}		if (flags&GRE_KEY) {			key = *(u32*)(h + offset);			offset += 4;		}		if (flags&GRE_SEQ) {			seqno = ntohl(*(u32*)(h + offset));			offset += 4;		}	}	read_lock(&ipgre_lock);	if ((tunnel = ipgre_tunnel_lookup(iph->saddr, iph->daddr, key)) != NULL) {		secpath_reset(skb);		skb->protocol = *(u16*)(h + 2);		/* WCCP version 1 and 2 protocol decoding.		 * - Change protocol to IP		 * - When dealing with WCCPv2, Skip extra 4 bytes in GRE header		 */		if (flags == 0 &&		    skb->protocol == __constant_htons(ETH_P_WCCP)) {			skb->protocol = __constant_htons(ETH_P_IP);			if ((*(h + offset) & 0xF0) != 0x40) 				offset += 4;		}		skb->mac.raw = skb->nh.raw;		skb->nh.raw = __pskb_pull(skb, offset);		skb_postpull_rcsum(skb, skb->mac.raw, offset);		memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options));		skb->pkt_type = PACKET_HOST;#ifdef CONFIG_NET_IPGRE_BROADCAST		if (MULTICAST(iph->daddr)) {			/* Looped back packet, drop it! */			if (((struct rtable*)skb->dst)->fl.iif == 0)				goto drop;			tunnel->stat.multicast++;			skb->pkt_type = PACKET_BROADCAST;		}#endif		if (((flags&GRE_CSUM) && csum) ||		    (!(flags&GRE_CSUM) && tunnel->parms.i_flags&GRE_CSUM)) {			tunnel->stat.rx_crc_errors++;			tunnel->stat.rx_errors++;			goto drop;		}		if (tunnel->parms.i_flags&GRE_SEQ) {			if (!(flags&GRE_SEQ) ||			    (tunnel->i_seqno && (s32)(seqno - tunnel->i_seqno) < 0)) {				tunnel->stat.rx_fifo_errors++;				tunnel->stat.rx_errors++;				goto drop;			}			tunnel->i_seqno = seqno + 1;		}		tunnel->stat.rx_packets++;		tunnel->stat.rx_bytes += skb->len;		skb->dev = tunnel->dev;		dst_release(skb->dst);		skb->dst = NULL;		nf_reset(skb);		ipgre_ecn_decapsulate(iph, skb);		netif_rx(skb);		read_unlock(&ipgre_lock);		return(0);	}	icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PROT_UNREACH, 0);drop:	read_unlock(&ipgre_lock);drop_nolock:	kfree_skb(skb);	return(0);}
4520	/local/tlutelli/issta_data/temp/c/2005_temp/2005/4520/fb286bb2990a107009dbf25f6ffebeb7df77f9be/ip_gre.c/clean/net/ipv4/ip_gre.c