/*
 *    gre.c,v 1.4 2003/06/06 02:25:10 wessels Exp
 *
 * Glenn Chisholm <glenn@ircache.net>
 * Duane Wessels <wessels@squid-cache.org>
 *
 * #define USE_WCCPV2 for WCCPv2 packets.  This adds another
 * 4 octets to the "GRE" header.  See Sec 4.12.1 of
 * http://www.web-cache.com/Writings/Internet-Drafts/draft-wilson-wrec-wccp-v2-00.txt
 *
 * NOTE: Squid may not support WCCPv2 unless you apply the patch from
 * http://devel.squid-cache.org/
 *
 * NOTE: you cannot receive both WCCPv1 and WCCPv2 packets at the
 * same time with this code.
 */

#include "opt_gre.h"

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/proc.h>
#include <sys/protosw.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/sysctl.h>

#include <vm/vm_zone.h>

#include <net/if.h>
#include <net/route.h>

#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/in_pcb.h>
#include <netinet/in_var.h>
#include <netinet/ip_var.h>
#include <netinet/ip_mroute.h>

#define WCCP_PROTOCOL_TYPE 0x883E

struct gre {
    int type;
#if USE_WCCPV2
    int redirect_header;
#endif
};

void
gre_input(m, iphlen, proto)
     register struct mbuf *m;
     int iphlen, proto;
{
    register struct ip *ip = mtod(m, struct ip *);
    register struct gre *gre;
    int len;

    len = iphlen + sizeof(struct gre);
    if (m->m_len < len) {
	if ((m = m_pullup(m, len)) == 0) {
	    printf("gre_input: m_pullup failed\n");
	    return;
	}
	ip = mtod(m, struct ip *);
    }
    gre = (struct gre *) ((caddr_t) ip + iphlen);
    if (ntohl(gre->type) != WCCP_PROTOCOL_TYPE) {
	printf("gre_input: rec'd non-WCCP GRE packet, type %x\n", gre->type);
	rip_input(m, iphlen, proto);
	return;
    }
    if (m->m_len < len) {
	printf("gre_input: small packet?  len=%d, m_len=%d\n", len, m->m_len);
	m_freem(m);
	return;
    }
    /* drop IP and GRE headers */
    m_adj(m, len);
    ip_input(m);
}
