/* dhcp_bpf_filter taken from bpf.c in dhcp-3.1.0
 *
 * Copyright (c) 2004,2007 by Internet Systems Consortium, Inc. ("ISC")
 * Copyright (c) 1996-2003 by Internet Software Consortium
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 *   Internet Systems Consortium, Inc.
 *   950 Charter Street
 *   Redwood City, CA 94063
 *   <info@isc.org>
 *   http://www.isc.org/
 */

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>

#include <net/ethernet.h>

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <fcntl.h>

#include "caml/memory.h"
#include "caml/fail.h"
#include "caml/unixsupport.h"
#include "caml/signals.h"
#include "caml/alloc.h"
#include "caml/custom.h"
#include "caml/bigarray.h"

#ifdef __linux__

#include <linux/if_packet.h>
#include <linux/filter.h>

#include <net/if.h>

#include <arpa/inet.h>

#define BOOTPC          68
#define BPF_WHOLEPACKET 0x0fffffff

#ifndef BPF_ETHCOOK
# define BPF_ETHCOOK 0
#endif

static const struct sock_filter bootp_bpf_filter [] = {
  /* Make sure this is an IP packet... */
  BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 12),
  BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 0, 8),
  /* Make sure it's a UDP packet... */
  BPF_STMT(BPF_LD + BPF_B + BPF_ABS, 23 + BPF_ETHCOOK),
  BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 0, 6),
  /* Make sure this isn't a fragment... */
  BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 20 + BPF_ETHCOOK),
  BPF_JUMP(BPF_JMP + BPF_JSET + BPF_K, 0x1fff, 4, 0),
  /* Get the IP header length... */
  BPF_STMT(BPF_LDX + BPF_B + BPF_MSH, 14 + BPF_ETHCOOK),
  /* Make sure it's to the right port... */
  BPF_STMT(BPF_LD + BPF_H + BPF_IND, 16 + BPF_ETHCOOK),
  BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, BOOTPC, 0, 1),
  /* If we passed all the tests, ask for the whole packet. */
  BPF_STMT(BPF_RET + BPF_K, BPF_WHOLEPACKET),
  /* Otherwise, drop it. */
  BPF_STMT(BPF_RET + BPF_K, 0),
};

#else

struct sock_filter {};
static const struct sock_filter bootp_bpf_filter [] = {};

#endif

/* Filters */
CAMLprim value bpf_filter(value vunit)
{
  CAMLparam0();
  CAMLlocal1(vfilter);
  vfilter = caml_alloc_string(sizeof(bootp_bpf_filter));
  memcpy(String_val(vfilter), bootp_bpf_filter, sizeof(bootp_bpf_filter));
  CAMLreturn (vfilter);
}
