[VOL-3610] implementing a fake DHCP server within BBSim

Change-Id: If291a0ca7f78909c3713ef0e6831e381304fc2c9
diff --git a/Makefile b/Makefile
index c96ffeb..1d84999 100644
--- a/Makefile
+++ b/Makefile
@@ -30,22 +30,12 @@
 
 GO                = docker run --rm --user $$(id -u):$$(id -g) -v ${CURDIR}:/app $(shell test -t 0 && echo "-it") -v gocache:/.cache -v gocache-${VOLTHA_TOOLS_VERSION}:/go/pkg voltha/voltha-ci-tools:${VOLTHA_TOOLS_VERSION}-golang go
 GO_SH             = docker run --rm --user $$(id -u):$$(id -g) -v ${CURDIR}:/app $(shell test -t 0 && echo "-it") -v gocache:/.cache -v gocache-${VOLTHA_TOOLS_VERSION}:/go/pkg voltha/voltha-ci-tools:${VOLTHA_TOOLS_VERSION}-golang sh -c '
-BBSIM_BUILDER     = docker run --rm --user $$(id -u):$$(id -g) -v ${CURDIR}:/app $(shell test -t 0 && echo "-it") -v gocache:/.cache -v gocache-${VOLTHA_TOOLS_VERSION}:/go/pkg bbsim-builder go
 GO_JUNIT_REPORT   = docker run --rm --user $$(id -u):$$(id -g) -v ${CURDIR}:/app -i voltha/voltha-ci-tools:${VOLTHA_TOOLS_VERSION}-go-junit-report go-junit-report
 GOCOVER_COBERTURA = docker run --rm --user $$(id -u):$$(id -g) -v ${CURDIR}:/app -i voltha/voltha-ci-tools:${VOLTHA_TOOLS_VERSION}-gocover-cobertura gocover-cobertura
-BBSIM_LINTER      = docker run --rm --user $$(id -u):$$(id -g) -v ${CURDIR}:/app $(shell test -t 0 && echo "-it") -v gocache:/.cache -v gocache-${VOLTHA_TOOLS_VERSION}:/go/pkg bbsim-linter:${VOLTHA_TOOLS_VERSION}-golangci-lint golangci-lint
+GOLANGCI_LINT     = docker run --rm --user $$(id -u):$$(id -g) -v ${CURDIR}:/app $(shell test -t 0 && echo "-it") -v gocache:/.cache -v gocache-${VOLTHA_TOOLS_VERSION}:/go/pkg voltha/voltha-ci-tools:${VOLTHA_TOOLS_VERSION}-golangci-lint golangci-lint
 HADOLINT          = docker run --rm --user $$(id -u):$$(id -g) -v ${CURDIR}:/app $(shell test -t 0 && echo "-it") voltha/voltha-ci-tools:${VOLTHA_TOOLS_VERSION}-hadolint hadolint
 PROTOC            = docker run --rm --user $$(id -u):$$(id -g) -v ${CURDIR}:/app $(shell test -t 0 && echo "-it") -v gocache-${VOLTHA_TOOLS_VERSION}:/go/pkg voltha/voltha-ci-tools:${VOLTHA_TOOLS_VERSION}-protoc protoc
 
-builder:
-	@docker build -t bbsim-builder:latest -f build/ci/builder.Dockerfile build/ci/
-
-linter:
-	# since this repo depends on C libs (libpcap), they are first added into a local container
-	@[[ "$(docker images -q bbsim-linter:${VOLTHA_TOOLS_VERSION}-golangci-lint 2> /dev/null)" != "" ]] || \
-	  docker build --build-arg=VOLTHA_TOOLS_VERSION=${VOLTHA_TOOLS_VERSION} -t bbsim-linter:${VOLTHA_TOOLS_VERSION}-golangci-lint -f build/ci/linter.Dockerfile build/ci/
-
-
 # Public targets
 all: help
 
@@ -77,19 +67,20 @@
 
 lint: lint-mod lint-dockerfile
 
-sca: linter
+sca:
 	@rm -rf ./sca-report
 	@mkdir -p ./sca-report
 	@echo "Running static code analysis..."
-	@${BBSIM_LINTER} run --deadline=4m --out-format junit-xml ./... | tee ./sca-report/sca-report.xml
+	@${GOLANGCI_LINT} run --deadline=4m --out-format junit-xml ./... | tee ./sca-report/sca-report.xml
 	@echo ""
 	@echo "Static code analysis OK"
 
 test: docs-lint test-unit test-bbr
 
-test-unit: clean local-omci-sim builder # @HELP Execute unit tests
+test-unit: clean local-omci-sim # @HELP Execute unit tests
+	@echo "Running unit tests..."
 	@mkdir -p ./tests/results
-	@${BBSIM_BUILDER} test -mod=vendor -v -coverprofile ./tests/results/go-test-coverage.out -covermode count ./... 2>&1 | tee ./tests/results/go-test-results.out ;\
+	@${GO} test -mod=vendor -v -coverprofile ./tests/results/go-test-coverage.out -covermode count ./... 2>&1 | tee ./tests/results/go-test-results.out ;\
 	RETURN=$$? ;\
 	${GO_JUNIT_REPORT} < ./tests/results/go-test-results.out > ./tests/results/go-test-results.xml ;\
 	${GOCOVER_COBERTURA} < ./tests/results/go-test-coverage.out > ./tests/results/go-test-coverage.xml ;\
@@ -141,18 +132,18 @@
 RELEASE_BBSIM_NAME    ?= bbsim
 RELEASE_BBSIMCTL_NAME ?= bbsimctl
 
-release-bbr: builder
+release-bbr:
 	@echo "$(RELEASE_BBR_NAME)-linux-amd64"
-	@${BBSIM_BUILDER} build -mod vendor \
+	@${GO} build -mod vendor \
 	  -ldflags "-w -X main.buildTime=$(shell date +%Y/%m/%d-%H:%M:%S) \
 	    -X main.commitHash=$(shell git log --pretty=format:%H -n 1) \
 	    -X main.gitStatus=${GIT_STATUS} \
 	    -X main.version=${VERSION}" \
 	  -o "$(RELEASE_DIR)/$(RELEASE_BBR_NAME)-linux-amd64" ./cmd/bbr
 
-release-bbsim: builder
+release-bbsim:
 	@echo "$(RELEASE_BBSIM_NAME)-linux-amd64"
-	@${BBSIM_BUILDER} build -mod vendor \
+	@${GO} build -mod vendor \
 	  -ldflags "-w -X main.buildTime=$(shell date +%Y/%m/%d-%H:%M:%S) \
 	    -X main.commitHash=$(shell git log --pretty=format:%H -n 1) \
 	    -X main.gitStatus=${GIT_STATUS} \
diff --git a/VERSION b/VERSION
index f0bb29e..88c5fb8 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.3.0
+1.4.0
diff --git a/build/ci/builder.Dockerfile b/build/ci/builder.Dockerfile
deleted file mode 100644
index 94ab871..0000000
--- a/build/ci/builder.Dockerfile
+++ /dev/null
@@ -1,23 +0,0 @@
-# Copyright 2020-present Open Networking Foundation
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-FROM golang:1.13.8-stretch
-
-RUN apt-get update && apt-get install -y \
-    build-essential libpcap-dev && \
-    mkdir -m 777 /.cache /go/pkg
-
-ENV CGO_ENABLED=1
-
-WORKDIR /app
\ No newline at end of file
diff --git a/build/ci/linter.Dockerfile b/build/ci/linter.Dockerfile
deleted file mode 100644
index bc3274a..0000000
--- a/build/ci/linter.Dockerfile
+++ /dev/null
@@ -1,19 +0,0 @@
-# Copyright 2020-present Open Networking Foundation
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-ARG VOLTHA_TOOLS_VERSION
-FROM voltha/voltha-ci-tools:${VOLTHA_TOOLS_VERSION}-golangci-lint
-
-# install repo-specific C dependencies
-RUN apk add --no-cache build-base libpcap-dev
diff --git a/build/package/Dockerfile b/build/package/Dockerfile
index ae3b919..ba3954c 100644
--- a/build/package/Dockerfile
+++ b/build/package/Dockerfile
@@ -17,8 +17,6 @@
 # builder parent
 FROM golang:1.13.8-stretch as builder
 
-RUN apt-get update && apt-get install -y build-essential=12.3 libpcap-dev=1.8.1-3 --no-install-recommends
-
 ENV CGO_ENABLED=1
 
 WORKDIR /app
@@ -41,29 +39,28 @@
 
 # runtime parent
 FROM ubuntu:18.04
-
-# runtime prereqs
-# the symlink on libpcap is because both alpine and debian come with 1.8.x, but
-# debian symlinks it to 0.8 for historical reasons:
-# https://packages.debian.org/stretch/libpcap0.8-dev
-RUN apt-get update \
- && apt-get install -y libpcap-dev=1.8.1-6ubuntu1.18.04.1 isc-dhcp-server=4.3.5-3ubuntu7.1 \
- network-manager=1.10.6-2ubuntu1.4 tcpdump=4.9.3-0ubuntu0.18.04.1 --no-install-recommends \
- && apt-get clean \
- && rm -rf /var/lib/apt/lists/* \
- && ln -s /usr/lib/libpcap.so.1.8.1 /usr/lib/libpcap.so.0.9
-
-COPY ./configs/dhcpd.conf /etc/dhcp/
-RUN mv /usr/sbin/dhcpd /usr/local/bin/ \
-&& mv /sbin/dhclient /usr/local/bin/ \
-&& touch /var/lib/dhcp/dhcpd.leases
-
 WORKDIR /app
 COPY --from=builder /app/bbsim /app/bbsim
 COPY --from=builder /app/bbsimctl /usr/bin/bbsimctl
-RUN mv /usr/sbin/tcpdump /usr/bin/tcpdump
+COPY ./configs/ ./configs/
 RUN chmod a+x /app/bbsim
 RUN chmod a+x /usr/bin/bbsimctl
-COPY ./configs/ ./configs/
 RUN bbsimctl completion bash >> "$HOME/.bashrc"
 CMD [ "/app/bbsim" ]
+
+# Label image
+ARG org_label_schema_version=unknown
+ARG org_label_schema_vcs_url=unknown
+ARG org_label_schema_vcs_ref=unknown
+ARG org_label_schema_build_date=unknown
+ARG org_opencord_vcs_commit_date=unknown
+ARG org_opencord_vcs_dirty=unknown
+
+LABEL org.label-schema.schema-version=1.0 \
+      org.label-schema.name=voltha-rw-core \
+      org.label-schema.version=$org_label_schema_version \
+      org.label-schema.vcs-url=$org_label_schema_vcs_url \
+      org.label-schema.vcs-ref=$org_label_schema_vcs_ref \
+      org.label-schema.build-date=$org_label_schema_build_date \
+      org.opencord.vcs-commit-date=$org_opencord_vcs_commit_date \
+      org.opencord.vcs-dirty=$org_opencord_vcs_dirty
diff --git a/configs/dhcpd.conf b/configs/dhcpd.conf
deleted file mode 100644
index 9a480fe..0000000
--- a/configs/dhcpd.conf
+++ /dev/null
@@ -1,17 +0,0 @@
-#
-# Sample configuration file for ISC dhcpd for Debian
-#
-
-ddns-update-style none;
-
-option domain-name "example.org";
-# option domain-name-servers ns1.example.org, ns2.example.org;
-
-default-lease-time 600;
-max-lease-time 7200;
-
-# This is a very basic subnet declaration.
-subnet 192.168.0.0 netmask 255.255.0.0 {
-  range 192.168.0.1 192.168.253.254;
-  option routers 192.168.254.254;
-}
\ No newline at end of file
diff --git a/internal/bbsim/devices/nni.go b/internal/bbsim/devices/nni.go
index fe092e8..32fffaa 100644
--- a/internal/bbsim/devices/nni.go
+++ b/internal/bbsim/devices/nni.go
@@ -17,68 +17,42 @@
 package devices
 
 import (
-	"bytes"
 	"encoding/hex"
-	"os/exec"
-
 	"github.com/google/gopacket"
-	"github.com/google/gopacket/pcap"
 	"github.com/looplab/fsm"
 	"github.com/opencord/bbsim/internal/bbsim/packetHandlers"
-	"github.com/opencord/bbsim/internal/bbsim/types"
+	"github.com/opencord/voltha-protos/v4/go/openolt"
 	log "github.com/sirupsen/logrus"
 )
 
-var (
-	nniLogger    = log.WithFields(log.Fields{"module": "NNI"})
-	dhcpServerIp = "192.168.254.1"
-)
-
-type Executor interface {
-	Command(name string, arg ...string) Runnable
-}
-
-type DefaultExecutor struct{}
-
-func (d DefaultExecutor) Command(name string, arg ...string) Runnable {
-	return exec.Command(name, arg...)
-}
-
-type Runnable interface {
-	Run() error
-}
-
-var executor = DefaultExecutor{}
+var nniLogger = log.WithFields(log.Fields{"module": "NNI"})
 
 type NniPort struct {
 	// BBSIM Internals
-	ID           uint32
-	nniVeth      string
-	upstreamVeth string
-	PacketCount  uint64
+	ID  uint32
+	Olt *OltDevice
 
 	// PON Attributes
-	OperState *fsm.FSM
-	Type      string
+	OperState   *fsm.FSM
+	Type        string
+	PacketCount uint64 // dummy value for the stats
 }
 
 func CreateNNI(olt *OltDevice) (NniPort, error) {
 	nniPort := NniPort{
-		ID:           uint32(0),
-		nniVeth:      "nni",
-		upstreamVeth: "upstream",
+		ID: uint32(0),
 		OperState: getOperStateFSM(func(e *fsm.Event) {
 			oltLogger.Debugf("Changing NNI OperState from %s to %s", e.Src, e.Dst)
 		}),
 		Type: "nni",
+		Olt:  olt,
 	}
-	_ = createNNIPair(executor, olt, &nniPort)
+
 	return nniPort, nil
 }
 
-// sendNniPacket will send a packet out of the NNI interface.
-// We will send upstream only DHCP packets and drop anything else
-func (n *NniPort) sendNniPacket(packet gopacket.Packet) error {
+// handleNniPacket will send a packet to a fake DHCP server implementation
+func (n *NniPort) handleNniPacket(packet gopacket.Packet) error {
 	isDhcp := packetHandlers.IsDhcpPacket(packet)
 	isLldp := packetHandlers.IsLldpPacket(packet)
 
@@ -90,152 +64,33 @@
 	}
 
 	if isDhcp {
-		packet, err := packetHandlers.PopDoubleTag(packet)
+
+		// get a response packet from the DHCP server
+		pkt, err := n.Olt.dhcpServer.HandleServerPacket(packet)
 		if err != nil {
 			nniLogger.WithFields(log.Fields{
-				"packet": packet,
-			}).Errorf("Can't remove double tags from packet: %v", err)
+				"SourcePkt": hex.EncodeToString(packet.Data()),
+				"Err":       err,
+			}).Error("DHCP Server can't handle packet")
 			return err
 		}
 
-		handle, err := getVethHandler(n.nniVeth)
-		if err != nil {
+		// send packetIndication to VOLTHA
+		data := &openolt.Indication_PktInd{PktInd: &openolt.PacketIndication{
+			IntfType: "nni",
+			IntfId:   n.ID,
+			Pkt:      pkt.Data()}}
+		if err := n.Olt.OpenoltStream.Send(&openolt.Indication{Data: data}); err != nil {
+			oltLogger.WithFields(log.Fields{
+				"IntfType": data.PktInd.IntfType,
+				"IntfId":   n.ID,
+				"Pkt":      hex.EncodeToString(pkt.Data()),
+			}).Errorf("Fail to send PktInd indication: %v", err)
 			return err
 		}
-
-		err = handle.WritePacketData(packet.Data())
-		if err != nil {
-			nniLogger.WithFields(log.Fields{
-				"packet": packet,
-			}).Errorf("Failed to send packet out of the NNI: %s", err)
-			return err
-		}
-
-		nniLogger.WithFields(log.Fields{
-			"packet": hex.EncodeToString(packet.Data()),
-		}).Trace("Sent packet out of NNI")
 	} else if isLldp {
 		// TODO rework this when BBSim supports data-plane packets
 		nniLogger.Trace("Received LLDP Packet, ignoring it")
 	}
 	return nil
 }
-
-//createNNIBridge will create a veth bridge to fake the connection between the NNI port
-//and something upstream, in this case a DHCP server.
-//It is also responsible to start the DHCP server itself
-func createNNIPair(executor Executor, olt *OltDevice, nniPort *NniPort) error {
-
-	if err := executor.Command("ip", "link", "add", nniPort.nniVeth, "type", "veth", "peer", "name", nniPort.upstreamVeth).Run(); err != nil {
-		nniLogger.Errorf("Couldn't create veth pair between %s and %s", nniPort.nniVeth, nniPort.upstreamVeth)
-		return err
-	}
-
-	if err := setVethUp(executor, nniPort.nniVeth); err != nil {
-		return err
-	}
-
-	if err := setVethUp(executor, nniPort.upstreamVeth); err != nil {
-		return err
-	}
-
-	// TODO should be moved out of this function in case there are multiple NNI interfaces.
-	// Only one DHCP server should be running and listening on all NNI interfaces
-	if err := startDHCPServer(nniPort.upstreamVeth, dhcpServerIp); err != nil {
-		return err
-	}
-
-	return nil
-}
-
-// NewVethChan returns a new channel for receiving packets over the NNI interface
-func (n *NniPort) NewVethChan() (chan *types.PacketMsg, *pcap.Handle, error) {
-	ch, handle, err := listenOnVeth(n.nniVeth)
-	if err != nil {
-		return nil, nil, err
-	}
-	return ch, handle, err
-}
-
-// setVethUp is responsible to activate a virtual interface
-func setVethUp(executor Executor, vethName string) error {
-	if err := executor.Command("ip", "link", "set", vethName, "up").Run(); err != nil {
-		nniLogger.Errorf("Couldn't change interface %s state to up: %v", vethName, err)
-		return err
-	}
-	return nil
-}
-
-var startDHCPServer = func(upstreamVeth string, dhcpServerIp string) error {
-	// TODO the DHCP server should support multiple interfaces
-	if err := exec.Command("ip", "addr", "add", dhcpServerIp, "dev", upstreamVeth).Run(); err != nil {
-		nniLogger.Errorf("Couldn't assing ip %s to interface %s: %v", dhcpServerIp, upstreamVeth, err)
-		return err
-	}
-
-	if err := setVethUp(executor, upstreamVeth); err != nil {
-		return err
-	}
-
-	dhcp := "/usr/local/bin/dhcpd"
-	conf := "/etc/dhcp/dhcpd.conf" // copied in the container from configs/dhcpd.conf
-	logfile := "/tmp/dhcplog"
-	var stderr bytes.Buffer
-	cmd := exec.Command(dhcp, "-cf", conf, upstreamVeth, "-tf", logfile, "-4")
-	cmd.Stderr = &stderr
-	err := cmd.Run()
-	if err != nil {
-		nniLogger.Errorf("Fail to start DHCP Server: %s, %s", err, stderr.String())
-		return err
-	}
-	nniLogger.Info("Successfully activated DHCP Server")
-	return nil
-}
-
-func getVethHandler(vethName string) (*pcap.Handle, error) {
-	var (
-		device            = vethName
-		snapshotLen int32 = 1518
-		promiscuous       = false
-		timeout           = pcap.BlockForever
-	)
-	handle, err := pcap.OpenLive(device, snapshotLen, promiscuous, timeout)
-	if err != nil {
-		nniLogger.Errorf("Can't retrieve handler for interface %s", vethName)
-		return nil, err
-	}
-	return handle, nil
-}
-
-var listenOnVeth = func(vethName string) (chan *types.PacketMsg, *pcap.Handle, error) {
-
-	handle, err := getVethHandler(vethName)
-	if err != nil {
-		return nil, nil, err
-	}
-
-	channel := make(chan *types.PacketMsg, 1024)
-
-	go func() {
-		nniLogger.Info("Start listening on NNI for packets")
-		packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
-		for packet := range packetSource.Packets() {
-
-			if !packetHandlers.IsIncomingPacket(packet) {
-				nniLogger.Tracef("Ignoring packet as it's going out")
-				continue
-			}
-
-			nniLogger.WithFields(log.Fields{
-				"packet": packet.Dump(),
-			}).Tracef("Received packet on NNI Port")
-			pkt := types.PacketMsg{
-				Pkt: packet,
-			}
-			channel <- &pkt
-		}
-		nniLogger.Info("Stop listening on NNI for packets")
-	}()
-
-	return channel, handle, nil
-}
diff --git a/internal/bbsim/devices/nni_test.go b/internal/bbsim/devices/nni_test.go
index 9ee945e..4f93bb8 100644
--- a/internal/bbsim/devices/nni_test.go
+++ b/internal/bbsim/devices/nni_test.go
@@ -19,88 +19,82 @@
 
 import (
 	"errors"
-	"github.com/google/gopacket/pcap"
+	"github.com/google/gopacket"
+	"github.com/google/gopacket/layers"
+	"github.com/opencord/voltha-protos/v4/go/openolt"
+	"github.com/stretchr/testify/assert"
 	"testing"
-
-	"github.com/opencord/bbsim/internal/bbsim/types"
-	"gotest.tools/assert"
 )
 
-func TestSetVethUpSuccess(t *testing.T) {
-	spy := &ExecutorSpy{
-		Calls: make(map[int][]string),
+func TestCreateNNI(t *testing.T) {
+	olt := OltDevice{
+		ID: 0,
 	}
-	err := setVethUp(spy, "test_veth")
-	assert.Equal(t, spy.CommandCallCount, 1)
-	assert.Equal(t, spy.Calls[1][2], "test_veth")
-	assert.Equal(t, err, nil)
+	nni, err := CreateNNI(&olt)
+
+	assert.Nil(t, err)
+	assert.Equal(t, "nni", nni.Type)
+	assert.Equal(t, uint32(0), nni.ID)
+	assert.Equal(t, "down", nni.OperState.Current())
 }
 
-func TestSetVethUpFail(t *testing.T) {
-	spy := &ExecutorSpy{
-		failRun: true,
-		Calls:   make(map[int][]string),
+func TestSendNniPacket(t *testing.T) {
+
+	stream := &mockStream{
+		CallCount: 0,
+		Calls:     make(map[int]*openolt.Indication),
+		fail:      false,
+		channel:   make(chan int, 10),
 	}
-	err := setVethUp(spy, "test_veth")
-	assert.Equal(t, spy.CommandCallCount, 1)
-	assert.Equal(t, err.Error(), "fake-error")
+
+	dhcpServer := &mockDhcpServer{
+		callCount: 0,
+		fail:      false,
+	}
+
+	nni := NniPort{
+		Olt: &OltDevice{
+			OpenoltStream: stream,
+			dhcpServer:    dhcpServer,
+		},
+		ID: 12,
+	}
+
+	// the DHCP server is mocked, so we don't really care about the packet we send in
+	pkt := createTestDhcpPacket(t)
+	err := nni.handleNniPacket(pkt)
+	assert.Nil(t, err)
+	assert.Equal(t, stream.CallCount, 1)
+	indication := stream.Calls[1].GetPktInd()
+	assert.Equal(t, "nni", indication.IntfType)
+	assert.Equal(t, nni.ID, indication.IntfId)
+	assert.Equal(t, pkt.Data(), indication.Pkt)
 }
 
-func TestCreateNNIPair(t *testing.T) {
-
-	startDHCPServerCalled := false
-	_startDHCPServer := startDHCPServer
-	defer func() { startDHCPServer = _startDHCPServer }()
-	startDHCPServer = func(upstreamVeth string, dhcpServerIp string) error {
-		startDHCPServerCalled = true
-		return nil
-	}
-
-	listenOnVethCalled := false
-	_listenOnVeth := listenOnVeth
-	defer func() { listenOnVeth = _listenOnVeth }()
-	listenOnVeth = func(vethName string) (chan *types.PacketMsg, *pcap.Handle, error) {
-		listenOnVethCalled = true
-		return make(chan *types.PacketMsg, 1), nil, nil
-	}
-	spy := &ExecutorSpy{
-		failRun: false,
-		Calls:   make(map[int][]string),
-	}
-
-	olt := OltDevice{}
-	nni := NniPort{}
-
-	err := createNNIPair(spy, &olt, &nni)
-	olt.nniPktInChannel, olt.nniHandle, _ = nni.NewVethChan()
-
-	assert.Equal(t, spy.CommandCallCount, 3)
-	assert.Equal(t, startDHCPServerCalled, true)
-	assert.Equal(t, listenOnVethCalled, true)
-	assert.Equal(t, err, nil)
-	assert.Assert(t, olt.nniPktInChannel != nil)
+type mockDhcpServer struct {
+	callCount int
+	fail      bool
 }
 
-type ExecutorSpy struct {
-	failRun bool
-
-	CommandCallCount int
-	RunCallCount     int
-	Calls            map[int][]string
-}
-
-func (s *ExecutorSpy) Command(name string, arg ...string) Runnable {
-	s.CommandCallCount++
-
-	s.Calls[s.CommandCallCount] = arg
-
-	return s
-}
-
-func (s *ExecutorSpy) Run() error {
-	s.RunCallCount++
-	if s.failRun {
-		return errors.New("fake-error")
+// being a Mock I just return the same packet I got
+func (s mockDhcpServer) HandleServerPacket(pkt gopacket.Packet) (gopacket.Packet, error) {
+	if s.fail {
+		return nil, errors.New("mocked-error")
 	}
-	return nil
+	return pkt, nil
+}
+
+func createTestDhcpPacket(t *testing.T) gopacket.Packet {
+	dhcp := &layers.DHCPv4{
+		Operation: layers.DHCPOpRequest,
+	}
+
+	buffer := gopacket.NewSerializeBuffer()
+	opts := gopacket.SerializeOptions{FixLengths: true}
+	err := gopacket.SerializeLayers(buffer, opts, dhcp)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	return gopacket.NewPacket(buffer.Bytes(), layers.LayerTypeDHCPv4, gopacket.DecodeOptions{})
 }
diff --git a/internal/bbsim/devices/olt.go b/internal/bbsim/devices/olt.go
index c3e0866..beeffce 100644
--- a/internal/bbsim/devices/olt.go
+++ b/internal/bbsim/devices/olt.go
@@ -20,6 +20,7 @@
 	"context"
 	"encoding/hex"
 	"fmt"
+	"github.com/opencord/bbsim/internal/bbsim/responders/dhcp"
 	"github.com/opencord/voltha-protos/v4/go/ext/config"
 	"net"
 	"sync"
@@ -27,10 +28,8 @@
 
 	"github.com/google/gopacket"
 	"github.com/google/gopacket/layers"
-	"github.com/google/gopacket/pcap"
 	"github.com/looplab/fsm"
 	"github.com/opencord/bbsim/internal/bbsim/packetHandlers"
-	bbsim "github.com/opencord/bbsim/internal/bbsim/types"
 	"github.com/opencord/bbsim/internal/common"
 	omcisim "github.com/opencord/omci-sim"
 	common_protos "github.com/opencord/voltha-protos/v4/go/common"
@@ -58,8 +57,7 @@
 	NumOnuPerPon         int
 	InternalState        *fsm.FSM
 	channel              chan Message
-	nniPktInChannel      chan *bbsim.PacketMsg // packets coming in from the NNI and going to VOLTHA
-	nniHandle            *pcap.Handle          // handle on the NNI interface, close it when shutting down the NNI channel
+	dhcpServer           dhcp.DHCPServerIf
 	Flows                map[FlowKey]openolt.Flow
 	Delay                int
 	ControlledActivation mode
@@ -111,6 +109,7 @@
 		enablePerf:        options.BBSim.EnablePerf,
 		PublishEvents:     options.BBSim.Events,
 		PortStatsInterval: options.Olt.PortStatsInterval,
+		dhcpServer:        dhcp.NewDHCPServer(),
 	}
 
 	if val, ok := ControlledActivationModes[options.BBSim.ControlledActivation]; ok {
@@ -235,25 +234,12 @@
 	// create new channel for processOltMessages Go routine
 	o.channel = make(chan Message)
 
-	o.nniPktInChannel = make(chan *bbsim.PacketMsg, 1024)
 	// FIXME we are assuming we have only one NNI
 	if o.Nnis[0] != nil {
 		// NOTE we want to make sure the state is down when we initialize the OLT,
 		// the NNI may be in a bad state after a disable/reboot as we are not disabling it for
 		// in-band management
 		o.Nnis[0].OperState.SetState("down")
-		ch, handle, err := o.Nnis[0].NewVethChan()
-		if err == nil {
-			oltLogger.WithFields(log.Fields{
-				"Type":      o.Nnis[0].Type,
-				"IntfId":    o.Nnis[0].ID,
-				"OperState": o.Nnis[0].OperState.Current(),
-			}).Info("NNI Channel created")
-			o.nniPktInChannel = ch
-			o.nniHandle = handle
-		} else {
-			oltLogger.Errorf("Error getting NNI channel: %v", err)
-		}
 	}
 }
 
@@ -319,9 +305,7 @@
 
 	// terminate the OLT's processOltMessages go routine
 	close(o.channel)
-	// terminate the OLT's processNniPacketIns go routine
-	go o.nniHandle.Close()
-	close(o.nniPktInChannel)
+
 	o.enableContextCancel()
 
 	time.Sleep(time.Duration(rebootDelay) * time.Second)
@@ -398,7 +382,6 @@
 
 	// create Go routine to process all OLT events
 	go o.processOltMessages(o.enableContext, stream, &wg)
-	go o.processNniPacketIns(o.enableContext, stream, &wg)
 
 	// enable the OLT
 	oltMsg := Message{
@@ -753,82 +736,6 @@
 	oltLogger.Warn("Stopped handling OLT Indication Channel")
 }
 
-// processNniPacketIns handles messages received over the NNI interface
-func (o *OltDevice) processNniPacketIns(ctx context.Context, stream openolt.Openolt_EnableIndicationServer, wg *sync.WaitGroup) {
-	oltLogger.WithFields(log.Fields{
-		"nniChannel": o.nniPktInChannel,
-	}).Debug("Started Processing Packets arriving from the NNI")
-	nniId := o.Nnis[0].ID // FIXME we are assuming we have only one NNI
-
-	ch := o.nniPktInChannel
-
-loop:
-	for {
-		select {
-		case <-ctx.Done():
-			oltLogger.Debug("NNI Indication processing canceled via context")
-			break loop
-		case message, ok := <-ch:
-			if !ok || ctx.Err() != nil {
-				oltLogger.Debug("NNI Indication processing canceled via channel closed")
-				break loop
-			}
-			oltLogger.Tracef("Received packets on NNI Channel")
-
-			onuMac, err := packetHandlers.GetDstMacAddressFromPacket(message.Pkt)
-
-			if err != nil {
-				log.WithFields(log.Fields{
-					"IntfType": "nni",
-					"IntfId":   nniId,
-					"Pkt":      message.Pkt.Data(),
-				}).Error("Can't find Dst MacAddress in packet")
-				return
-			}
-
-			s, err := o.FindServiceByMacAddress(onuMac)
-			if err != nil {
-				log.WithFields(log.Fields{
-					"IntfType":   "nni",
-					"IntfId":     nniId,
-					"Pkt":        message.Pkt.Data(),
-					"MacAddress": onuMac.String(),
-				}).Error("Can't find ONU with MacAddress")
-				return
-			}
-
-			service := s.(*Service)
-
-			doubleTaggedPkt, err := packetHandlers.PushDoubleTag(service.STag, service.CTag, message.Pkt, service.UsPonCTagPriority)
-			if err != nil {
-				log.Error("Fail to add double tag to packet")
-			}
-
-			data := &openolt.Indication_PktInd{PktInd: &openolt.PacketIndication{
-				IntfType: "nni",
-				IntfId:   nniId,
-				Pkt:      doubleTaggedPkt.Data()}}
-			if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
-				oltLogger.WithFields(log.Fields{
-					"IntfType": data.PktInd.IntfType,
-					"IntfId":   nniId,
-					"Pkt":      doubleTaggedPkt.Data(),
-				}).Errorf("Fail to send PktInd indication: %v", err)
-			}
-			oltLogger.WithFields(log.Fields{
-				"IntfType": data.PktInd.IntfType,
-				"IntfId":   nniId,
-				"Pkt":      hex.EncodeToString(doubleTaggedPkt.Data()),
-				"OnuSn":    service.Onu.Sn(),
-			}).Trace("Sent PktInd indication (from NNI to VOLTHA)")
-		}
-	}
-	wg.Done()
-	oltLogger.WithFields(log.Fields{
-		"nniChannel": o.nniPktInChannel,
-	}).Warn("Stopped handling NNI Channel")
-}
-
 // returns an ONU with a given Serial Number
 func (o *OltDevice) FindOnuBySn(serialNumber string) (*Onu, error) {
 	// TODO this function can be a performance bottleneck when we have many ONUs,
@@ -1405,8 +1312,11 @@
 func (o *OltDevice) UplinkPacketOut(context context.Context, packet *openolt.UplinkPacket) (*openolt.Empty, error) {
 	pkt := gopacket.NewPacket(packet.Pkt, layers.LayerTypeEthernet, gopacket.Default)
 
-	_ = o.Nnis[0].sendNniPacket(pkt) // FIXME we are assuming we have only one NNI
-	// NOTE should we return an error if sendNniPakcet fails?
+	err := o.Nnis[0].handleNniPacket(pkt) // FIXME we are assuming we have only one NNI
+
+	if err != nil {
+		return nil, err
+	}
 	return new(openolt.Empty), nil
 }
 
diff --git a/internal/bbsim/packetHandlers/filters.go b/internal/bbsim/packetHandlers/filters.go
index c46f87d..a930b1e 100644
--- a/internal/bbsim/packetHandlers/filters.go
+++ b/internal/bbsim/packetHandlers/filters.go
@@ -44,16 +44,14 @@
 	return false
 }
 
-// return true if the packet is coming in the OLT from the NNI port
-// it uses the ack to check if the source is the one we assigned to the
-// dhcp server
+// return true if the packet is coming in the OLT from the DHCP Server
+// given that we only check DHCP packets we can use the Operation
+// Request are outgoing (toward the server)
+// Replies are incoming (toward the OLT)
 func IsIncomingPacket(packet gopacket.Packet) bool {
-	if ipLayer := packet.Layer(layers.LayerTypeIPv4); ipLayer != nil {
-
-		ip, _ := ipLayer.(*layers.IPv4)
-
-		// FIXME find a better way to filter outgoing packets
-		if ip.SrcIP.Equal(net.ParseIP("192.168.254.1")) {
+	layerDHCP := packet.Layer(layers.LayerTypeDHCPv4)
+	if dhcp, ok := layerDHCP.(*layers.DHCPv4); ok {
+		if dhcp.Operation == layers.DHCPOpReply {
 			return true
 		}
 	}
diff --git a/internal/bbsim/packetHandlers/filters_test.go b/internal/bbsim/packetHandlers/filters_test.go
index c182e82..5be7db2 100644
--- a/internal/bbsim/packetHandlers/filters_test.go
+++ b/internal/bbsim/packetHandlers/filters_test.go
@@ -131,9 +131,8 @@
 }
 
 func Test_IsIncomingPacket_True(t *testing.T) {
-	eth := &layers.IPv4{
-		SrcIP: net.ParseIP("192.168.254.1"),
-		DstIP: net.ParseIP("182.21.0.122"),
+	eth := &layers.DHCPv4{
+		Operation: layers.DHCPOpReply,
 	}
 
 	buffer := gopacket.NewSerializeBuffer()
@@ -143,16 +142,15 @@
 		t.Fatal(err)
 	}
 
-	ethernetPkt := gopacket.NewPacket(buffer.Bytes(), layers.LayerTypeIPv4, gopacket.DecodeOptions{})
+	ethernetPkt := gopacket.NewPacket(buffer.Bytes(), layers.LayerTypeDHCPv4, gopacket.DecodeOptions{})
 
 	res := packetHandlers.IsIncomingPacket(ethernetPkt)
 	assert.Equal(t, res, true)
 }
 
 func Test_IsIncomingPacket_False(t *testing.T) {
-	eth := &layers.IPv4{
-		SrcIP: net.ParseIP("182.21.0.122"),
-		DstIP: net.ParseIP("192.168.254.1"),
+	eth := &layers.DHCPv4{
+		Operation: layers.DHCPOpRequest,
 	}
 
 	buffer := gopacket.NewSerializeBuffer()
@@ -162,7 +160,7 @@
 		t.Fatal(err)
 	}
 
-	ethernetPkt := gopacket.NewPacket(buffer.Bytes(), layers.LayerTypeIPv4, gopacket.DecodeOptions{})
+	ethernetPkt := gopacket.NewPacket(buffer.Bytes(), layers.LayerTypeDHCPv4, gopacket.DecodeOptions{})
 
 	res := packetHandlers.IsIncomingPacket(ethernetPkt)
 	assert.Equal(t, res, false)
diff --git a/internal/bbsim/packetHandlers/packet_tags.go b/internal/bbsim/packetHandlers/packet_tags.go
index 1ea7be7..90186a8 100644
--- a/internal/bbsim/packetHandlers/packet_tags.go
+++ b/internal/bbsim/packetHandlers/packet_tags.go
@@ -144,3 +144,21 @@
 	}
 	return dot1q.Priority, nil
 }
+
+// godet inner and outer tag from a packet
+// TODO unit test
+func GetTagsFromPacket(pkt gopacket.Packet) (uint16, uint16, error) {
+	sTag, err := GetVlanTag(pkt)
+	if err != nil {
+		return 0, 0, err
+	}
+	singleTagPkt, err := PopSingleTag(pkt)
+	if err != nil {
+		return 0, 0, err
+	}
+	cTag, err := GetVlanTag(singleTagPkt)
+	if err != nil {
+		return 0, 0, err
+	}
+	return sTag, cTag, nil
+}
diff --git a/internal/bbsim/responders/dhcp/dhcp.go b/internal/bbsim/responders/dhcp/dhcp.go
index f3c7e72..850d160 100644
--- a/internal/bbsim/responders/dhcp/dhcp.go
+++ b/internal/bbsim/responders/dhcp/dhcp.go
@@ -158,7 +158,7 @@
 	return &dhcpLayer
 }
 
-func serializeDHCPPacket(intfId uint32, onuId uint32, cTag int, srcMac net.HardwareAddr, dhcp *layers.DHCPv4, pbit uint8) ([]byte, error) {
+func serializeDHCPPacket(cTag int, srcMac net.HardwareAddr, dhcp *layers.DHCPv4, pbit uint8) (gopacket.Packet, error) {
 	buffer := gopacket.NewSerializeBuffer()
 
 	options := gopacket.SerializeOptions{
@@ -200,7 +200,7 @@
 		return nil, err
 	}
 
-	return gopacket.Payload(taggedPkt.Data()), nil
+	return taggedPkt, nil
 }
 
 func GetDhcpLayer(pkt gopacket.Packet) (*layers.DHCPv4, error) {
@@ -277,7 +277,7 @@
 	cTag int, gemPortId uint32, onuStateMachine *fsm.FSM, onuHwAddress net.HardwareAddr,
 	offeredIp net.IP, pbit uint8, stream bbsim.Stream) error {
 	dhcp := createDHCPReq(ponPortId, onuId, onuHwAddress, offeredIp, gemPortId)
-	pkt, err := serializeDHCPPacket(ponPortId, onuId, cTag, onuHwAddress, dhcp, pbit)
+	pkt, err := serializeDHCPPacket(cTag, onuHwAddress, dhcp, pbit)
 
 	if err != nil {
 		dhcpLogger.WithFields(log.Fields{
@@ -297,7 +297,7 @@
 	msg := bbsim.ByteMsg{
 		IntfId: ponPortId,
 		OnuId:  onuId,
-		Bytes:  pkt,
+		Bytes:  pkt.Data(),
 	}
 
 	if err := sendDHCPPktIn(msg, portNo, gemPortId, stream); err != nil {
@@ -339,7 +339,7 @@
 	pbit uint8, stream bbsim.Stream) error {
 
 	dhcp := createDHCPDisc(ponPortId, onuId, gemPortId, onuHwAddress)
-	pkt, err := serializeDHCPPacket(ponPortId, onuId, cTag, onuHwAddress, dhcp, pbit)
+	pkt, err := serializeDHCPPacket(cTag, onuHwAddress, dhcp, pbit)
 
 	if err != nil {
 		dhcpLogger.WithFields(log.Fields{
@@ -359,7 +359,7 @@
 	msg := bbsim.ByteMsg{
 		IntfId: ponPortId,
 		OnuId:  onuId,
-		Bytes:  pkt,
+		Bytes:  pkt.Data(),
 	}
 
 	if err := sendDHCPPktIn(msg, portNo, gemPortId, stream); err != nil {
@@ -574,6 +574,7 @@
 				"Type":   dhcpType,
 				"error":  err,
 			}).Error("Failed to send DHCP packet out of the NNI Port")
+			return err
 		}
 		dhcpLogger.WithFields(log.Fields{
 			"OnuId":  onuId,
diff --git a/internal/bbsim/responders/dhcp/dhcp_server.go b/internal/bbsim/responders/dhcp/dhcp_server.go
new file mode 100644
index 0000000..7e7f361
--- /dev/null
+++ b/internal/bbsim/responders/dhcp/dhcp_server.go
@@ -0,0 +1,322 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dhcp
+
+import (
+	"encoding/hex"
+	"errors"
+	"fmt"
+	"github.com/google/gopacket"
+	"github.com/google/gopacket/layers"
+	"github.com/opencord/bbsim/internal/bbsim/packetHandlers"
+	log "github.com/sirupsen/logrus"
+	"net"
+)
+
+type DHCPServerIf interface {
+	HandleServerPacket(pkt gopacket.Packet) (gopacket.Packet, error)
+}
+
+type DHCPServer struct {
+	DHCPServerMacAddress net.HardwareAddr
+}
+
+func NewDHCPServer() *DHCPServer {
+	return &DHCPServer{
+		// NOTE we may need to make this configurable in case we'll need multiple servers
+		DHCPServerMacAddress: net.HardwareAddr{0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff},
+	}
+}
+
+func (s *DHCPServer) getClientMacAddress(pkt gopacket.Packet) (net.HardwareAddr, error) {
+	dhcpLayer, err := GetDhcpLayer(pkt)
+	if err != nil {
+		return nil, err
+	}
+	return dhcpLayer.ClientHWAddr, nil
+}
+
+func (s *DHCPServer) getTxId(pkt gopacket.Packet) (uint32, error) {
+	dhcpLayer, err := GetDhcpLayer(pkt)
+	if err != nil {
+		return 0, err
+	}
+	return dhcpLayer.Xid, nil
+}
+
+func (s *DHCPServer) getPacketHostName(pkt gopacket.Packet) ([]byte, error) {
+	dhcpLayer, err := GetDhcpLayer(pkt)
+	if err != nil {
+		return nil, err
+	}
+	for _, option := range dhcpLayer.Options {
+		if option.Type == layers.DHCPOptHostname {
+			return option.Data, nil
+		}
+	}
+	return nil, errors.New("hostname-not-found")
+}
+
+func (s *DHCPServer) getOption82(pkt gopacket.Packet) ([]byte, error) {
+	dhcpLayer, err := GetDhcpLayer(pkt)
+	if err != nil {
+		return nil, err
+	}
+	for _, option := range dhcpLayer.Options {
+		if option.Type == 82 {
+			return option.Data, nil
+		}
+	}
+	log.WithFields(log.Fields{
+		"pkt": hex.EncodeToString(pkt.Data()),
+	}).Debug("option82-not-found")
+	return []byte{}, nil
+}
+
+func (s *DHCPServer) createDefaultDhcpReply(xid uint32, mac net.HardwareAddr) layers.DHCPv4 {
+	clientIp := s.createIpFromMacAddress(mac)
+	return layers.DHCPv4{
+		Operation:    layers.DHCPOpReply,
+		HardwareType: layers.LinkTypeEthernet,
+		HardwareLen:  6,
+		HardwareOpts: 0,
+		Xid:          xid,
+		ClientHWAddr: mac,
+		ClientIP:     clientIp,
+		YourClientIP: clientIp,
+	}
+}
+
+func (s *DHCPServer) createIpFromMacAddress(mac net.HardwareAddr) net.IP {
+	ip := []byte{}
+	for i := 2; i < 6; i++ {
+		ip = append(ip, mac[i])
+	}
+	return net.IPv4(10+ip[0], ip[1], ip[2], ip[3])
+}
+
+func (s *DHCPServer) serializeServerDHCPPacket(clientMac net.HardwareAddr, dhcpLayer *layers.DHCPv4) (gopacket.Packet, error) {
+	buffer := gopacket.NewSerializeBuffer()
+
+	options := gopacket.SerializeOptions{
+		ComputeChecksums: true,
+		FixLengths:       true,
+	}
+
+	ethernetLayer := &layers.Ethernet{
+		SrcMAC:       s.DHCPServerMacAddress,
+		DstMAC:       clientMac,
+		EthernetType: layers.EthernetTypeIPv4,
+	}
+
+	ipLayer := &layers.IPv4{
+		Version:  4,
+		TOS:      0x10,
+		TTL:      128,
+		SrcIP:    []byte{0, 0, 0, 0},
+		DstIP:    []byte{255, 255, 255, 255},
+		Protocol: layers.IPProtocolUDP,
+	}
+
+	udpLayer := &layers.UDP{
+		SrcPort: 67,
+		DstPort: 68,
+	}
+
+	_ = udpLayer.SetNetworkLayerForChecksum(ipLayer)
+	if err := gopacket.SerializeLayers(buffer, options, ethernetLayer, ipLayer, udpLayer, dhcpLayer); err != nil {
+		dhcpLogger.Error("SerializeLayers")
+		return nil, err
+	}
+
+	return gopacket.NewPacket(buffer.Bytes(), layers.LayerTypeEthernet, gopacket.Default), nil
+
+}
+
+func (s *DHCPServer) getDefaultDhcpServerOptions(hostname []byte, option82 []byte) []layers.DHCPOption {
+	defaultOpts := []layers.DHCPOption{}
+	defaultOpts = append(defaultOpts, layers.DHCPOption{
+		Type:   layers.DHCPOptHostname,
+		Data:   hostname,
+		Length: uint8(len(hostname)),
+	})
+
+	defaultOpts = append(defaultOpts, layers.DHCPOption{
+		Type:   82,
+		Data:   option82,
+		Length: uint8(len(option82)),
+	})
+
+	return defaultOpts
+}
+
+// get a Discover packet an return a valid Offer
+func (s *DHCPServer) handleDiscover(pkt gopacket.Packet) (gopacket.Packet, error) {
+
+	sTag, cTag, err := packetHandlers.GetTagsFromPacket(pkt)
+	if err != nil {
+		return nil, err
+	}
+
+	clientMac, err := s.getClientMacAddress(pkt)
+	if err != nil {
+		return nil, err
+	}
+
+	txId, err := s.getTxId(pkt)
+	if err != nil {
+		return nil, err
+	}
+
+	hostname, err := s.getPacketHostName(pkt)
+	if err != nil {
+		return nil, err
+	}
+
+	option82, err := s.getOption82(pkt)
+	if err != nil {
+		return nil, err
+	}
+
+	dhcpLogger.WithFields(log.Fields{
+		"sTag":      sTag,
+		"cTag":      cTag,
+		"clientMac": clientMac,
+		"txId":      txId,
+		"hostname":  string(hostname),
+		"option82":  string(option82),
+	}).Debug("Handling DHCP Discovery packet")
+
+	dhcpLayer := s.createDefaultDhcpReply(txId, clientMac)
+	defaultOpts := s.getDefaultDhcpServerOptions(hostname, option82)
+
+	dhcpLayer.Options = append([]layers.DHCPOption{{
+		Type:   layers.DHCPOptMessageType,
+		Data:   []byte{byte(layers.DHCPMsgTypeOffer)},
+		Length: 1,
+	}}, defaultOpts...)
+
+	data := []byte{01}
+	data = append(data, clientMac...)
+	dhcpLayer.Options = append(dhcpLayer.Options, layers.DHCPOption{
+		Type:   layers.DHCPOptClientID,
+		Data:   data,
+		Length: uint8(len(data)),
+	})
+
+	// serialize the packet
+	responsePkt, err := s.serializeServerDHCPPacket(clientMac, &dhcpLayer)
+	if err != nil {
+		return nil, err
+	}
+
+	taggedResponsePkt, err := packetHandlers.PushDoubleTag(int(sTag), int(cTag), responsePkt, 0)
+	if err != nil {
+		return nil, err
+	}
+	return taggedResponsePkt, nil
+}
+
+func (s *DHCPServer) handleRequest(pkt gopacket.Packet) (gopacket.Packet, error) {
+	sTag, cTag, err := packetHandlers.GetTagsFromPacket(pkt)
+	if err != nil {
+		return nil, err
+	}
+
+	clientMac, err := s.getClientMacAddress(pkt)
+	if err != nil {
+		return nil, err
+	}
+
+	txId, err := s.getTxId(pkt)
+	if err != nil {
+		return nil, err
+	}
+
+	hostname, err := s.getPacketHostName(pkt)
+	if err != nil {
+		return nil, err
+	}
+
+	option82, err := s.getOption82(pkt)
+	if err != nil {
+		return nil, err
+	}
+
+	dhcpLogger.WithFields(log.Fields{
+		"sTag":      sTag,
+		"cTag":      cTag,
+		"clientMac": clientMac,
+		"txId":      txId,
+		"hostname":  string(hostname),
+		"option82":  string(option82),
+	}).Debug("Handling DHCP Request packet")
+
+	dhcpLayer := s.createDefaultDhcpReply(txId, clientMac)
+	defaultOpts := s.getDefaultDhcpServerOptions(hostname, option82)
+
+	dhcpLayer.Options = append([]layers.DHCPOption{{
+		Type:   layers.DHCPOptMessageType,
+		Data:   []byte{byte(layers.DHCPMsgTypeAck)},
+		Length: 1,
+	}}, defaultOpts...)
+
+	// TODO can we move this in getDefaultDhcpServerOptions?
+	data := []byte{01}
+	data = append(data, clientMac...)
+	dhcpLayer.Options = append(dhcpLayer.Options, layers.DHCPOption{
+		Type:   layers.DHCPOptClientID,
+		Data:   data,
+		Length: uint8(len(data)),
+	})
+
+	// serialize the packet
+	responsePkt, err := s.serializeServerDHCPPacket(clientMac, &dhcpLayer)
+	if err != nil {
+		return nil, err
+	}
+
+	taggedResponsePkt, err := packetHandlers.PushDoubleTag(int(sTag), int(cTag), responsePkt, 0)
+	if err != nil {
+		return nil, err
+	}
+	return taggedResponsePkt, nil
+}
+
+// HandleServerPacket is a very simple implementation of a DHCP server
+// that only replies to DHCPDiscover and DHCPRequest packets
+func (s DHCPServer) HandleServerPacket(pkt gopacket.Packet) (gopacket.Packet, error) {
+	dhcpLayer, _ := GetDhcpLayer(pkt)
+
+	if dhcpLayer.Operation == layers.DHCPOpReply {
+		dhcpLogger.WithFields(log.Fields{
+			"pkt": hex.EncodeToString(pkt.Data()),
+		}).Error("Received DHCP Reply on the server. Ignoring the packet but this is a serious error.")
+	}
+
+	dhcpMessageType, _ := GetDhcpMessageType(dhcpLayer)
+
+	switch dhcpMessageType {
+	case layers.DHCPMsgTypeDiscover:
+		dhcpLogger.Info("Received DHCP Discover")
+		return s.handleDiscover(pkt)
+	case layers.DHCPMsgTypeRequest:
+		dhcpLogger.Info("Received DHCP Request")
+		return s.handleRequest(pkt)
+	}
+	return nil, fmt.Errorf("cannot-handle-dhcp-packet-of-type-%s", dhcpMessageType.String())
+}
diff --git a/internal/bbsim/responders/dhcp/dhcp_server_test.go b/internal/bbsim/responders/dhcp/dhcp_server_test.go
new file mode 100644
index 0000000..fa4a58d
--- /dev/null
+++ b/internal/bbsim/responders/dhcp/dhcp_server_test.go
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dhcp
+
+import (
+	"gotest.tools/assert"
+	"net"
+	"testing"
+)
+
+func TestCreateIpFromMacAddress(t *testing.T) {
+	dhcpServer := NewDHCPServer()
+
+	mac1 := net.HardwareAddr{0x2e, 0x60, 0x00, 0x0c, 0x0f, 0x02}
+	ip1 := dhcpServer.createIpFromMacAddress(mac1)
+	assert.Equal(t, "10.12.15.2", ip1.String())
+
+	mac2 := net.HardwareAddr{0x2e, 0x60, 0x00, 0x00, 0x00, 0x00}
+	ip2 := dhcpServer.createIpFromMacAddress(mac2)
+	assert.Equal(t, "10.0.0.0", ip2.String())
+}
diff --git a/vendor/github.com/google/gopacket/pcap/defs_windows_386.go b/vendor/github.com/google/gopacket/pcap/defs_windows_386.go
deleted file mode 100644
index 774e907..0000000
--- a/vendor/github.com/google/gopacket/pcap/defs_windows_386.go
+++ /dev/null
@@ -1,74 +0,0 @@
-// Copyright 2019 The GoPacket Authors. All rights reserved.
-//
-// Use of this source code is governed by a BSD-style license
-// that can be found in the LICENSE file in the root of the source
-// tree.
-
-// This file contains necessary structs/constants generated from libpcap headers with cgo -godefs
-// generated with: generate_defs.exe
-// DO NOT MODIFY
-
-package pcap
-
-import "syscall"
-
-const errorBufferSize = 0x100
-
-const (
-	pcapErrorNotActivated    = -0x3
-	pcapErrorActivated       = -0x4
-	pcapWarningPromisc       = 0x2
-	pcapErrorNoSuchDevice    = -0x5
-	pcapErrorDenied          = -0x8
-	pcapErrorNotUp           = -0x9
-	pcapError                = -0x1
-	pcapWarning              = 0x1
-	pcapDIN                  = 0x1
-	pcapDOUT                 = 0x2
-	pcapDINOUT               = 0x0
-	pcapNetmaskUnknown       = 0xffffffff
-	pcapTstampPrecisionMicro = 0x0
-	pcapTstampPrecisionNano  = 0x1
-)
-
-type timeval struct {
-	Sec  int32
-	Usec int32
-}
-type pcapPkthdr struct {
-	Ts     timeval
-	Caplen uint32
-	Len    uint32
-}
-type pcapTPtr uintptr
-type pcapBpfInstruction struct {
-	Code uint16
-	Jt   uint8
-	Jf   uint8
-	K    uint32
-}
-type pcapBpfProgram struct {
-	Len   uint32
-	Insns *pcapBpfInstruction
-}
-type pcapStats struct {
-	Recv   uint32
-	Drop   uint32
-	Ifdrop uint32
-}
-type pcapCint int32
-type pcapIf struct {
-	Next        *pcapIf
-	Name        *int8
-	Description *int8
-	Addresses   *pcapAddr
-	Flags       uint32
-}
-
-type pcapAddr struct {
-	Next      *pcapAddr
-	Addr      *syscall.RawSockaddr
-	Netmask   *syscall.RawSockaddr
-	Broadaddr *syscall.RawSockaddr
-	Dstaddr   *syscall.RawSockaddr
-}
diff --git a/vendor/github.com/google/gopacket/pcap/defs_windows_amd64.go b/vendor/github.com/google/gopacket/pcap/defs_windows_amd64.go
deleted file mode 100644
index 9619215..0000000
--- a/vendor/github.com/google/gopacket/pcap/defs_windows_amd64.go
+++ /dev/null
@@ -1,76 +0,0 @@
-// Copyright 2019 The GoPacket Authors. All rights reserved.
-//
-// Use of this source code is governed by a BSD-style license
-// that can be found in the LICENSE file in the root of the source
-// tree.
-
-// This file contains necessary structs/constants generated from libpcap headers with cgo -godefs
-// generated with: generate_defs.exe
-// DO NOT MODIFY
-
-package pcap
-
-import "syscall"
-
-const errorBufferSize = 0x100
-
-const (
-	pcapErrorNotActivated    = -0x3
-	pcapErrorActivated       = -0x4
-	pcapWarningPromisc       = 0x2
-	pcapErrorNoSuchDevice    = -0x5
-	pcapErrorDenied          = -0x8
-	pcapErrorNotUp           = -0x9
-	pcapError                = -0x1
-	pcapWarning              = 0x1
-	pcapDIN                  = 0x1
-	pcapDOUT                 = 0x2
-	pcapDINOUT               = 0x0
-	pcapNetmaskUnknown       = 0xffffffff
-	pcapTstampPrecisionMicro = 0x0
-	pcapTstampPrecisionNano  = 0x1
-)
-
-type timeval struct {
-	Sec  int32
-	Usec int32
-}
-type pcapPkthdr struct {
-	Ts     timeval
-	Caplen uint32
-	Len    uint32
-}
-type pcapTPtr uintptr
-type pcapBpfInstruction struct {
-	Code uint16
-	Jt   uint8
-	Jf   uint8
-	K    uint32
-}
-type pcapBpfProgram struct {
-	Len       uint32
-	Pad_cgo_0 [4]byte
-	Insns     *pcapBpfInstruction
-}
-type pcapStats struct {
-	Recv   uint32
-	Drop   uint32
-	Ifdrop uint32
-}
-type pcapCint int32
-type pcapIf struct {
-	Next        *pcapIf
-	Name        *int8
-	Description *int8
-	Addresses   *pcapAddr
-	Flags       uint32
-	Pad_cgo_0   [4]byte
-}
-
-type pcapAddr struct {
-	Next      *pcapAddr
-	Addr      *syscall.RawSockaddr
-	Netmask   *syscall.RawSockaddr
-	Broadaddr *syscall.RawSockaddr
-	Dstaddr   *syscall.RawSockaddr
-}
diff --git a/vendor/github.com/google/gopacket/pcap/doc.go b/vendor/github.com/google/gopacket/pcap/doc.go
deleted file mode 100644
index 38b3141..0000000
--- a/vendor/github.com/google/gopacket/pcap/doc.go
+++ /dev/null
@@ -1,112 +0,0 @@
-// Copyright 2012 Google, Inc. All rights reserved.
-//
-// Use of this source code is governed by a BSD-style license
-// that can be found in the LICENSE file in the root of the source
-// tree.
-
-/*
-Package pcap allows users of gopacket to read packets off the wire or from
-pcap files.
-
-This package is meant to be used with its parent,
-http://github.com/google/gopacket, although it can also be used independently
-if you just want to get packet data from the wire.
-
-Depending on libpcap version, os support, or file timestamp resolution,
-nanosecond resolution is used for the internal timestamps. Returned timestamps
-are always scaled to nanosecond resolution due to the usage of time.Time.
-libpcap must be at least version 1.5 to support nanosecond timestamps. OpenLive
-supports only microsecond resolution.
-
-Reading PCAP Files
-
-The following code can be used to read in data from a pcap file.
-
- if handle, err := pcap.OpenOffline("/path/to/my/file"); err != nil {
-   panic(err)
- } else {
-   packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
-   for packet := range packetSource.Packets() {
-     handlePacket(packet)  // Do something with a packet here.
-   }
- }
-
-Reading Live Packets
-
-The following code can be used to read in data from a live device, in this case
-"eth0". Be aware, that OpenLive only supports microsecond resolution.
-
- if handle, err := pcap.OpenLive("eth0", 1600, true, pcap.BlockForever); err != nil {
-   panic(err)
- } else if err := handle.SetBPFFilter("tcp and port 80"); err != nil {  // optional
-   panic(err)
- } else {
-   packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
-   for packet := range packetSource.Packets() {
-     handlePacket(packet)  // Do something with a packet here.
-   }
- }
-
-Inactive Handles
-
-Newer PCAP functionality requires the concept of an 'inactive' PCAP handle.
-Instead of constantly adding new arguments to pcap_open_live, users now call
-pcap_create to create a handle, set it up with a bunch of optional function
-calls, then call pcap_activate to activate it.  This library mirrors that
-mechanism, for those that want to expose/use these new features:
-
-  inactive, err := pcap.NewInactiveHandle(deviceName)
-  if err != nil {
-    log.Fatal(err)
-  }
-  defer inactive.CleanUp()
-
-  // Call various functions on inactive to set it up the way you'd like:
-  if err = inactive.SetTimeout(time.Minute); err != nil {
-    log.Fatal(err)
-  } else if err = inactive.SetTimestampSource("foo"); err != nil {
-    log.Fatal(err)
-  }
-
-  // Finally, create the actual handle by calling Activate:
-  handle, err := inactive.Activate()  // after this, inactive is no longer valid
-  if err != nil {
-    log.Fatal(err)
-  }
-  defer handle.Close()
-
-  // Now use your handle as you see fit.
-
-PCAP Timeouts
-
-pcap.OpenLive and pcap.SetTimeout both take timeouts.
-If you don't care about timeouts, just pass in BlockForever,
-which should do what you expect with minimal fuss.
-
-A timeout of 0 is not recommended.  Some platforms, like Macs
-(http://www.manpages.info/macosx/pcap.3.html) say:
-  The read timeout is used to arrange that the read not necessarily return
-  immediately when a packet is seen, but that it wait for some amount of time
-  to allow more packets to arrive and to read multiple packets from the OS
-  kernel in one operation.
-This means that if you only capture one packet, the kernel might decide to wait
-'timeout' for more packets to batch with it before returning.  A timeout of
-0, then, means 'wait forever for more packets', which is... not good.
-
-To get around this, we've introduced the following behavior:  if a negative
-timeout is passed in, we set the positive timeout in the handle, then loop
-internally in ReadPacketData/ZeroCopyReadPacketData when we see timeout
-errors.
-
-PCAP File Writing
-
-This package does not implement PCAP file writing.  However, gopacket/pcapgo
-does!  Look there if you'd like to write PCAP files.
-
-Note For Windows Users
-
-gopacket can use winpcap or npcap. If both are installed at the same time,
-npcap is preferred. Make sure the right windows service is loaded (npcap for npcap
-and npf for winpcap).
-*/
-package pcap
diff --git a/vendor/github.com/google/gopacket/pcap/pcap.go b/vendor/github.com/google/gopacket/pcap/pcap.go
deleted file mode 100644
index 6a4ef63..0000000
--- a/vendor/github.com/google/gopacket/pcap/pcap.go
+++ /dev/null
@@ -1,866 +0,0 @@
-// Copyright 2012 Google, Inc. All rights reserved.
-// Copyright 2009-2011 Andreas Krennmair. All rights reserved.
-//
-// Use of this source code is governed by a BSD-style license
-// that can be found in the LICENSE file in the root of the source
-// tree.
-
-package pcap
-
-import (
-	"errors"
-	"fmt"
-	"io"
-	"net"
-	"os"
-	"reflect"
-	"runtime"
-	"strconv"
-	"sync"
-	"sync/atomic"
-	"syscall"
-	"time"
-	"unsafe"
-
-	"github.com/google/gopacket"
-	"github.com/google/gopacket/layers"
-)
-
-// ErrNotActive is returned if handle is not activated
-const ErrNotActive = pcapErrorNotActivated
-
-// MaxBpfInstructions is the maximum number of BPF instructions supported (BPF_MAXINSNS),
-// taken from Linux kernel: include/uapi/linux/bpf_common.h
-//
-// https://github.com/torvalds/linux/blob/master/include/uapi/linux/bpf_common.h
-const MaxBpfInstructions = 4096
-
-// 8 bytes per instruction, max 4096 instructions
-const bpfInstructionBufferSize = 8 * MaxBpfInstructions
-
-// Handle provides a connection to a pcap handle, allowing users to read packets
-// off the wire (Next), inject packets onto the wire (Inject), and
-// perform a number of other functions to affect and understand packet output.
-//
-// Handles are already pcap_activate'd
-type Handle struct {
-	// stop is set to a non-zero value by Handle.Close to signal to
-	// getNextBufPtrLocked to stop trying to read packets
-	// This must be the first entry to ensure alignment for sync.atomic
-	stop uint64
-	// cptr is the handle for the actual pcap C object.
-	cptr           pcapTPtr
-	timeout        time.Duration
-	device         string
-	deviceIndex    int
-	mu             sync.Mutex
-	closeMu        sync.Mutex
-	nanoSecsFactor int64
-
-	// Since pointers to these objects are passed into a C function, if
-	// they're declared locally then the Go compiler thinks they may have
-	// escaped into C-land, so it allocates them on the heap.  This causes a
-	// huge memory hit, so to handle that we store them here instead.
-	pkthdr *pcapPkthdr
-	bufptr *uint8
-}
-
-// Stats contains statistics on how many packets were handled by a pcap handle,
-// and what was done with those packets.
-type Stats struct {
-	PacketsReceived  int
-	PacketsDropped   int
-	PacketsIfDropped int
-}
-
-// Interface describes a single network interface on a machine.
-type Interface struct {
-	Name        string
-	Description string
-	Flags       uint32
-	Addresses   []InterfaceAddress
-}
-
-// Datalink describes the datalink
-type Datalink struct {
-	Name        string
-	Description string
-}
-
-// InterfaceAddress describes an address associated with an Interface.
-// Currently, it's IPv4/6 specific.
-type InterfaceAddress struct {
-	IP        net.IP
-	Netmask   net.IPMask // Netmask may be nil if we were unable to retrieve it.
-	Broadaddr net.IP     // Broadcast address for this IP may be nil
-	P2P       net.IP     // P2P destination address for this IP may be nil
-}
-
-// BPF is a compiled filter program, useful for offline packet matching.
-type BPF struct {
-	orig string
-	bpf  pcapBpfProgram // takes a finalizer, not overriden by outsiders
-	hdr  pcapPkthdr     // allocate on the heap to enable optimizations
-}
-
-// BPFInstruction is a byte encoded structure holding a BPF instruction
-type BPFInstruction struct {
-	Code uint16
-	Jt   uint8
-	Jf   uint8
-	K    uint32
-}
-
-// BlockForever causes it to block forever waiting for packets, when passed
-// into SetTimeout or OpenLive, while still returning incoming packets to userland relatively
-// quickly.
-const BlockForever = -time.Millisecond * 10
-
-func timeoutMillis(timeout time.Duration) int {
-	// Flip sign if necessary.  See package docs on timeout for reasoning behind this.
-	if timeout < 0 {
-		timeout *= -1
-	}
-	// Round up
-	if timeout != 0 && timeout < time.Millisecond {
-		timeout = time.Millisecond
-	}
-	return int(timeout / time.Millisecond)
-}
-
-// OpenLive opens a device and returns a *Handle.
-// It takes as arguments the name of the device ("eth0"), the maximum size to
-// read for each packet (snaplen), whether to put the interface in promiscuous
-// mode, and a timeout. Warning: this function supports only microsecond timestamps.
-// For nanosecond resolution use an InactiveHandle.
-//
-// See the package documentation for important details regarding 'timeout'.
-func OpenLive(device string, snaplen int32, promisc bool, timeout time.Duration) (handle *Handle, _ error) {
-	var pro int
-	if promisc {
-		pro = 1
-	}
-
-	p, err := pcapOpenLive(device, int(snaplen), pro, timeoutMillis(timeout))
-	if err != nil {
-		return nil, err
-	}
-	p.timeout = timeout
-	p.device = device
-
-	ifc, err := net.InterfaceByName(device)
-	if err != nil {
-		// The device wasn't found in the OS, but could be "any"
-		// Set index to 0
-		p.deviceIndex = 0
-	} else {
-		p.deviceIndex = ifc.Index
-	}
-
-	p.nanoSecsFactor = 1000
-
-	// Only set the PCAP handle into non-blocking mode if we have a timeout
-	// greater than zero. If the user wants to block forever, we'll let libpcap
-	// handle that.
-	if p.timeout > 0 {
-		if err := p.setNonBlocking(); err != nil {
-			p.pcapClose()
-			return nil, err
-		}
-	}
-
-	return p, nil
-}
-
-// OpenOffline opens a file and returns its contents as a *Handle. Depending on libpcap support and
-// on the timestamp resolution used in the file, nanosecond or microsecond resolution is used
-// internally. All returned timestamps are scaled to nanosecond resolution. Resolution() can be used
-// to query the actual resolution used.
-func OpenOffline(file string) (handle *Handle, err error) {
-	handle, err = openOffline(file)
-	if err != nil {
-		return
-	}
-	if pcapGetTstampPrecision(handle.cptr) == pcapTstampPrecisionNano {
-		handle.nanoSecsFactor = 1
-	} else {
-		handle.nanoSecsFactor = 1000
-	}
-	return
-}
-
-// OpenOfflineFile returns contents of input file as a *Handle. Depending on libpcap support and
-// on the timestamp resolution used in the file, nanosecond or microsecond resolution is used
-// internally. All returned timestamps are scaled to nanosecond resolution. Resolution() can be used
-// to query the actual resolution used.
-func OpenOfflineFile(file *os.File) (handle *Handle, err error) {
-	handle, err = openOfflineFile(file)
-	if err != nil {
-		return
-	}
-	if pcapGetTstampPrecision(handle.cptr) == pcapTstampPrecisionNano {
-		handle.nanoSecsFactor = 1
-	} else {
-		handle.nanoSecsFactor = 1000
-	}
-	return
-}
-
-// NextError is the return code from a call to Next.
-type NextError int32
-
-// NextError implements the error interface.
-func (n NextError) Error() string {
-	switch n {
-	case NextErrorOk:
-		return "OK"
-	case NextErrorTimeoutExpired:
-		return "Timeout Expired"
-	case NextErrorReadError:
-		return "Read Error"
-	case NextErrorNoMorePackets:
-		return "No More Packets In File"
-	case NextErrorNotActivated:
-		return "Not Activated"
-	}
-	return strconv.Itoa(int(n))
-}
-
-// NextError values.
-const (
-	NextErrorOk             NextError = 1
-	NextErrorTimeoutExpired NextError = 0
-	NextErrorReadError      NextError = -1
-	// NextErrorNoMorePackets is returned when reading from a file (OpenOffline) and
-	// EOF is reached.  When this happens, Next() returns io.EOF instead of this.
-	NextErrorNoMorePackets NextError = -2
-	NextErrorNotActivated  NextError = -3
-)
-
-// ReadPacketData returns the next packet read from the pcap handle, along with an error
-// code associated with that packet.  If the packet is read successfully, the
-// returned error is nil.
-func (p *Handle) ReadPacketData() (data []byte, ci gopacket.CaptureInfo, err error) {
-	p.mu.Lock()
-	err = p.getNextBufPtrLocked(&ci)
-	if err == nil {
-		data = make([]byte, ci.CaptureLength)
-		copy(data, (*(*[1 << 30]byte)(unsafe.Pointer(p.bufptr)))[:])
-	}
-	p.mu.Unlock()
-	if err == NextErrorTimeoutExpired {
-		runtime.Gosched()
-	}
-	return
-}
-
-type activateError int
-
-const (
-	aeNoError      = activateError(0)
-	aeActivated    = activateError(pcapErrorActivated)
-	aePromisc      = activateError(pcapWarningPromisc)
-	aeNoSuchDevice = activateError(pcapErrorNoSuchDevice)
-	aeDenied       = activateError(pcapErrorDenied)
-	aeNotUp        = activateError(pcapErrorNotUp)
-	aeWarning      = activateError(pcapWarning)
-)
-
-func (a activateError) Error() string {
-	switch a {
-	case aeNoError:
-		return "No Error"
-	case aeActivated:
-		return "Already Activated"
-	case aePromisc:
-		return "Cannot set as promisc"
-	case aeNoSuchDevice:
-		return "No Such Device"
-	case aeDenied:
-		return "Permission Denied"
-	case aeNotUp:
-		return "Interface Not Up"
-	case aeWarning:
-		return fmt.Sprintf("Warning: %v", activateErrMsg.Error())
-	default:
-		return fmt.Sprintf("unknown activated error: %d", a)
-	}
-}
-
-// getNextBufPtrLocked is shared code for ReadPacketData and
-// ZeroCopyReadPacketData.
-func (p *Handle) getNextBufPtrLocked(ci *gopacket.CaptureInfo) error {
-	if !p.isOpen() {
-		return io.EOF
-	}
-
-	// set after we have call waitForPacket for the first time
-	var waited bool
-
-	for atomic.LoadUint64(&p.stop) == 0 {
-		// try to read a packet if one is immediately available
-		result := p.pcapNextPacketEx()
-
-		switch result {
-		case NextErrorOk:
-			sec := p.pkthdr.getSec()
-			// convert micros to nanos
-			nanos := int64(p.pkthdr.getUsec()) * p.nanoSecsFactor
-
-			ci.Timestamp = time.Unix(sec, nanos)
-			ci.CaptureLength = p.pkthdr.getCaplen()
-			ci.Length = p.pkthdr.getLen()
-			ci.InterfaceIndex = p.deviceIndex
-
-			return nil
-		case NextErrorNoMorePackets:
-			// no more packets, return EOF rather than libpcap-specific error
-			return io.EOF
-		case NextErrorTimeoutExpired:
-			// we've already waited for a packet and we're supposed to time out
-			//
-			// we should never actually hit this if we were passed BlockForever
-			// since we should block on C.pcap_next_ex until there's a packet
-			// to read.
-			if waited && p.timeout > 0 {
-				return result
-			}
-
-			// wait for packet before trying again
-			p.waitForPacket()
-			waited = true
-		default:
-			return result
-		}
-	}
-
-	// stop must be set
-	return io.EOF
-}
-
-// ZeroCopyReadPacketData reads the next packet off the wire, and returns its data.
-// The slice returned by ZeroCopyReadPacketData points to bytes owned by the
-// the Handle.  Each call to ZeroCopyReadPacketData invalidates any data previously
-// returned by ZeroCopyReadPacketData.  Care must be taken not to keep pointers
-// to old bytes when using ZeroCopyReadPacketData... if you need to keep data past
-// the next time you call ZeroCopyReadPacketData, use ReadPacketData, which copies
-// the bytes into a new buffer for you.
-//  data1, _, _ := handle.ZeroCopyReadPacketData()
-//  // do everything you want with data1 here, copying bytes out of it if you'd like to keep them around.
-//  data2, _, _ := handle.ZeroCopyReadPacketData()  // invalidates bytes in data1
-func (p *Handle) ZeroCopyReadPacketData() (data []byte, ci gopacket.CaptureInfo, err error) {
-	p.mu.Lock()
-	err = p.getNextBufPtrLocked(&ci)
-	if err == nil {
-		slice := (*reflect.SliceHeader)(unsafe.Pointer(&data))
-		slice.Data = uintptr(unsafe.Pointer(p.bufptr))
-		slice.Len = ci.CaptureLength
-		slice.Cap = ci.CaptureLength
-	}
-	p.mu.Unlock()
-	if err == NextErrorTimeoutExpired {
-		runtime.Gosched()
-	}
-	return
-}
-
-// Close closes the underlying pcap handle.
-func (p *Handle) Close() {
-	p.closeMu.Lock()
-	defer p.closeMu.Unlock()
-
-	if !p.isOpen() {
-		return
-	}
-
-	atomic.StoreUint64(&p.stop, 1)
-
-	// wait for packet reader to stop
-	p.mu.Lock()
-	defer p.mu.Unlock()
-
-	p.pcapClose()
-}
-
-// Error returns the current error associated with a pcap handle (pcap_geterr).
-func (p *Handle) Error() error {
-	return p.pcapGeterr()
-}
-
-// Stats returns statistics on the underlying pcap handle.
-func (p *Handle) Stats() (stat *Stats, err error) {
-	return p.pcapStats()
-}
-
-// ListDataLinks obtains a list of all possible data link types supported for an interface.
-func (p *Handle) ListDataLinks() (datalinks []Datalink, err error) {
-	return p.pcapListDatalinks()
-}
-
-// compileBPFFilter always returns an allocated C.struct_bpf_program
-// It is the callers responsibility to free the memory again, e.g.
-//
-//    C.pcap_freecode(&bpf)
-//
-func (p *Handle) compileBPFFilter(expr string) (pcapBpfProgram, error) {
-	var maskp = uint32(pcapNetmaskUnknown)
-
-	// Only do the lookup on network interfaces.
-	// No device indicates we're handling a pcap file.
-	if len(p.device) > 0 {
-		var err error
-		_, maskp, err = pcapLookupnet(p.device)
-		if err != nil {
-			// We can't lookup the network, but that could be because the interface
-			// doesn't have an IPv4.
-			maskp = uint32(pcapNetmaskUnknown)
-		}
-	}
-
-	return p.pcapCompile(expr, maskp)
-}
-
-// CompileBPFFilter compiles and returns a BPF filter with given a link type and capture length.
-func CompileBPFFilter(linkType layers.LinkType, captureLength int, expr string) ([]BPFInstruction, error) {
-	h, err := pcapOpenDead(linkType, captureLength)
-	if err != nil {
-		return nil, err
-	}
-	defer h.Close()
-	return h.CompileBPFFilter(expr)
-}
-
-// CompileBPFFilter compiles and returns a BPF filter for the pcap handle.
-func (p *Handle) CompileBPFFilter(expr string) ([]BPFInstruction, error) {
-	bpf, err := p.compileBPFFilter(expr)
-	defer bpf.free()
-	if err != nil {
-		return nil, err
-	}
-
-	return bpf.toBPFInstruction(), nil
-}
-
-// SetBPFFilter compiles and sets a BPF filter for the pcap handle.
-func (p *Handle) SetBPFFilter(expr string) (err error) {
-	bpf, err := p.compileBPFFilter(expr)
-	defer bpf.free()
-	if err != nil {
-		return err
-	}
-
-	return p.pcapSetfilter(bpf)
-}
-
-// SetBPFInstructionFilter may be used to apply a filter in BPF asm byte code format.
-//
-// Simplest way to generate BPF asm byte code is with tcpdump:
-//     tcpdump -dd 'udp'
-//
-// The output may be used directly to add a filter, e.g.:
-//     bpfInstructions := []pcap.BpfInstruction{
-//			{0x28, 0, 0, 0x0000000c},
-//			{0x15, 0, 9, 0x00000800},
-//			{0x30, 0, 0, 0x00000017},
-//			{0x15, 0, 7, 0x00000006},
-//			{0x28, 0, 0, 0x00000014},
-//			{0x45, 5, 0, 0x00001fff},
-//			{0xb1, 0, 0, 0x0000000e},
-//			{0x50, 0, 0, 0x0000001b},
-//			{0x54, 0, 0, 0x00000012},
-//			{0x15, 0, 1, 0x00000012},
-//			{0x6, 0, 0, 0x0000ffff},
-//			{0x6, 0, 0, 0x00000000},
-//		}
-//
-// An other posibility is to write the bpf code in bpf asm.
-// Documentation: https://www.kernel.org/doc/Documentation/networking/filter.txt
-//
-// To compile the code use bpf_asm from
-// https://github.com/torvalds/linux/tree/master/tools/net
-//
-// The following command may be used to convert bpf_asm output to c/go struct, usable for SetBPFFilterByte:
-// bpf_asm -c tcp.bpf
-func (p *Handle) SetBPFInstructionFilter(bpfInstructions []BPFInstruction) (err error) {
-	bpf, err := bpfInstructionFilter(bpfInstructions)
-	if err != nil {
-		return err
-	}
-	defer bpf.free()
-
-	return p.pcapSetfilter(bpf)
-}
-
-func bpfInstructionFilter(bpfInstructions []BPFInstruction) (bpf pcapBpfProgram, err error) {
-	if len(bpfInstructions) < 1 {
-		return bpf, errors.New("bpfInstructions must not be empty")
-	}
-
-	if len(bpfInstructions) > MaxBpfInstructions {
-		return bpf, fmt.Errorf("bpfInstructions must not be larger than %d", MaxBpfInstructions)
-	}
-
-	return pcapBpfProgramFromInstructions(bpfInstructions), nil
-}
-
-// NewBPF compiles the given string into a new filter program.
-//
-// BPF filters need to be created from activated handles, because they need to
-// know the underlying link type to correctly compile their offsets.
-func (p *Handle) NewBPF(expr string) (*BPF, error) {
-	bpf := &BPF{orig: expr}
-
-	var err error
-	bpf.bpf, err = p.pcapCompile(expr, pcapNetmaskUnknown)
-	if err != nil {
-		return nil, err
-	}
-
-	runtime.SetFinalizer(bpf, destroyBPF)
-	return bpf, nil
-}
-
-// NewBPF allows to create a BPF without requiring an existing handle.
-// This allows to match packets obtained from a-non GoPacket capture source
-// to be matched.
-//
-// 	buf := make([]byte, MaxFrameSize)
-// 	bpfi, _ := pcap.NewBPF(layers.LinkTypeEthernet, MaxFrameSize, "icmp")
-// 	n, _ := someIO.Read(buf)
-// 	ci := gopacket.CaptureInfo{CaptureLength: n, Length: n}
-// 	if bpfi.Matches(ci, buf) {
-// 		doSomething()
-// 	}
-func NewBPF(linkType layers.LinkType, captureLength int, expr string) (*BPF, error) {
-	h, err := pcapOpenDead(linkType, captureLength)
-	if err != nil {
-		return nil, err
-	}
-	defer h.Close()
-	return h.NewBPF(expr)
-}
-
-// NewBPFInstructionFilter sets the given BPFInstructions as new filter program.
-//
-// More details see func SetBPFInstructionFilter
-//
-// BPF filters need to be created from activated handles, because they need to
-// know the underlying link type to correctly compile their offsets.
-func (p *Handle) NewBPFInstructionFilter(bpfInstructions []BPFInstruction) (*BPF, error) {
-	var err error
-	bpf := &BPF{orig: "BPF Instruction Filter"}
-
-	bpf.bpf, err = bpfInstructionFilter(bpfInstructions)
-	if err != nil {
-		return nil, err
-	}
-
-	runtime.SetFinalizer(bpf, destroyBPF)
-	return bpf, nil
-}
-func destroyBPF(bpf *BPF) {
-	bpf.bpf.free()
-}
-
-// String returns the original string this BPF filter was compiled from.
-func (b *BPF) String() string {
-	return b.orig
-}
-
-// Matches returns true if the given packet data matches this filter.
-func (b *BPF) Matches(ci gopacket.CaptureInfo, data []byte) bool {
-	return b.pcapOfflineFilter(ci, data)
-}
-
-// Version returns pcap_lib_version.
-func Version() string {
-	return pcapLibVersion()
-}
-
-// LinkType returns pcap_datalink, as a layers.LinkType.
-func (p *Handle) LinkType() layers.LinkType {
-	return p.pcapDatalink()
-}
-
-// SetLinkType calls pcap_set_datalink on the pcap handle.
-func (p *Handle) SetLinkType(dlt layers.LinkType) error {
-	return p.pcapSetDatalink(dlt)
-}
-
-// DatalinkValToName returns pcap_datalink_val_to_name as string
-func DatalinkValToName(dlt int) string {
-	return pcapDatalinkValToName(dlt)
-}
-
-// DatalinkValToDescription returns pcap_datalink_val_to_description as string
-func DatalinkValToDescription(dlt int) string {
-	return pcapDatalinkValToDescription(dlt)
-}
-
-// DatalinkNameToVal returns pcap_datalink_name_to_val as int
-func DatalinkNameToVal(name string) int {
-	return pcapDatalinkNameToVal(name)
-}
-
-// FindAllDevs attempts to enumerate all interfaces on the current machine.
-func FindAllDevs() (ifs []Interface, err error) {
-	alldevsp, err := pcapFindAllDevs()
-	if err != nil {
-		return nil, err
-	}
-	defer alldevsp.free()
-
-	for alldevsp.next() {
-		var iface Interface
-		iface.Name = alldevsp.name()
-		iface.Description = alldevsp.description()
-		iface.Addresses = findalladdresses(alldevsp.addresses())
-		iface.Flags = alldevsp.flags()
-		ifs = append(ifs, iface)
-	}
-	return
-}
-
-func findalladdresses(addresses pcapAddresses) (retval []InterfaceAddress) {
-	// TODO - make it support more than IPv4 and IPv6?
-	retval = make([]InterfaceAddress, 0, 1)
-	for addresses.next() {
-		// Strangely, it appears that in some cases, we get a pcap address back from
-		// pcap_findalldevs with a nil .addr.  It appears that we can skip over
-		// these.
-		if addresses.addr() == nil {
-			continue
-		}
-		var a InterfaceAddress
-		var err error
-		if a.IP, err = sockaddrToIP(addresses.addr()); err != nil {
-			continue
-		}
-		// To be safe, we'll also check for netmask.
-		if addresses.netmask() == nil {
-			continue
-		}
-		if a.Netmask, err = sockaddrToIP(addresses.netmask()); err != nil {
-			// If we got an IP address but we can't get a netmask, just return the IP
-			// address.
-			a.Netmask = nil
-		}
-		if a.Broadaddr, err = sockaddrToIP(addresses.broadaddr()); err != nil {
-			a.Broadaddr = nil
-		}
-		if a.P2P, err = sockaddrToIP(addresses.dstaddr()); err != nil {
-			a.P2P = nil
-		}
-		retval = append(retval, a)
-	}
-	return
-}
-
-func sockaddrToIP(rsa *syscall.RawSockaddr) (IP []byte, err error) {
-	if rsa == nil {
-		err = errors.New("Value not set")
-		return
-	}
-	switch rsa.Family {
-	case syscall.AF_INET:
-		pp := (*syscall.RawSockaddrInet4)(unsafe.Pointer(rsa))
-		IP = make([]byte, 4)
-		for i := 0; i < len(IP); i++ {
-			IP[i] = pp.Addr[i]
-		}
-		return
-	case syscall.AF_INET6:
-		pp := (*syscall.RawSockaddrInet6)(unsafe.Pointer(rsa))
-		IP = make([]byte, 16)
-		for i := 0; i < len(IP); i++ {
-			IP[i] = pp.Addr[i]
-		}
-		return
-	}
-	err = errors.New("Unsupported address type")
-	return
-}
-
-// WritePacketData calls pcap_sendpacket, injecting the given data into the pcap handle.
-func (p *Handle) WritePacketData(data []byte) (err error) {
-	return p.pcapSendpacket(data)
-}
-
-// Direction is used by Handle.SetDirection.
-type Direction uint8
-
-// Direction values for Handle.SetDirection.
-const (
-	DirectionIn    = Direction(pcapDIN)
-	DirectionOut   = Direction(pcapDOUT)
-	DirectionInOut = Direction(pcapDINOUT)
-)
-
-// SetDirection sets the direction for which packets will be captured.
-func (p *Handle) SetDirection(direction Direction) error {
-	if direction != DirectionIn && direction != DirectionOut && direction != DirectionInOut {
-		return fmt.Errorf("Invalid direction: %v", direction)
-	}
-	return p.pcapSetdirection(direction)
-}
-
-// SnapLen returns the snapshot length
-func (p *Handle) SnapLen() int {
-	return p.pcapSnapshot()
-}
-
-// Resolution returns the timestamp resolution of acquired timestamps before scaling to NanosecondTimestampResolution.
-func (p *Handle) Resolution() gopacket.TimestampResolution {
-	if p.nanoSecsFactor == 1 {
-		return gopacket.TimestampResolutionMicrosecond
-	}
-	return gopacket.TimestampResolutionNanosecond
-}
-
-// TimestampSource tells PCAP which type of timestamp to use for packets.
-type TimestampSource int
-
-// String returns the timestamp type as a human-readable string.
-func (t TimestampSource) String() string {
-	return t.pcapTstampTypeValToName()
-}
-
-// TimestampSourceFromString translates a string into a timestamp type, case
-// insensitive.
-func TimestampSourceFromString(s string) (TimestampSource, error) {
-	return pcapTstampTypeNameToVal(s)
-}
-
-// InactiveHandle allows you to call pre-pcap_activate functions on your pcap
-// handle to set it up just the way you'd like.
-type InactiveHandle struct {
-	// cptr is the handle for the actual pcap C object.
-	cptr        pcapTPtr
-	device      string
-	deviceIndex int
-	timeout     time.Duration
-}
-
-// holds the err messoge in case activation returned a Warning
-var activateErrMsg error
-
-// Error returns the current error associated with a pcap handle (pcap_geterr).
-func (p *InactiveHandle) Error() error {
-	return p.pcapGeterr()
-}
-
-// Activate activates the handle.  The current InactiveHandle becomes invalid
-// and all future function calls on it will fail.
-func (p *InactiveHandle) Activate() (*Handle, error) {
-	// ignore error with set_tstamp_precision, since the actual precision is queried later anyway
-	pcapSetTstampPrecision(p.cptr, pcapTstampPrecisionNano)
-	handle, err := p.pcapActivate()
-	if err != aeNoError {
-		if err == aeWarning {
-			activateErrMsg = p.Error()
-		}
-		return nil, err
-	}
-	handle.timeout = p.timeout
-	if p.timeout > 0 {
-		if err := handle.setNonBlocking(); err != nil {
-			handle.pcapClose()
-			return nil, err
-		}
-	}
-	handle.device = p.device
-	handle.deviceIndex = p.deviceIndex
-	if pcapGetTstampPrecision(handle.cptr) == pcapTstampPrecisionNano {
-		handle.nanoSecsFactor = 1
-	} else {
-		handle.nanoSecsFactor = 1000
-	}
-	return handle, nil
-}
-
-// CleanUp cleans up any stuff left over from a successful or failed building
-// of a handle.
-func (p *InactiveHandle) CleanUp() {
-	p.pcapClose()
-}
-
-// NewInactiveHandle creates a new InactiveHandle, which wraps an un-activated PCAP handle.
-// Callers of NewInactiveHandle should immediately defer 'CleanUp', as in:
-//   inactive := NewInactiveHandle("eth0")
-//   defer inactive.CleanUp()
-func NewInactiveHandle(device string) (*InactiveHandle, error) {
-	// Try to get the interface index, but iy could be something like "any"
-	// in which case use 0, which doesn't exist in nature
-	deviceIndex := 0
-	ifc, err := net.InterfaceByName(device)
-	if err == nil {
-		deviceIndex = ifc.Index
-	}
-
-	// This copies a bunch of the pcap_open_live implementation from pcap.c:
-	handle, err := pcapCreate(device)
-	if err != nil {
-		return nil, err
-	}
-	handle.device = device
-	handle.deviceIndex = deviceIndex
-	return handle, nil
-}
-
-// SetSnapLen sets the snap length (max bytes per packet to capture).
-func (p *InactiveHandle) SetSnapLen(snaplen int) error {
-	return p.pcapSetSnaplen(snaplen)
-}
-
-// SetPromisc sets the handle to either be promiscuous (capture packets
-// unrelated to this host) or not.
-func (p *InactiveHandle) SetPromisc(promisc bool) error {
-	return p.pcapSetPromisc(promisc)
-}
-
-// SetTimeout sets the read timeout for the handle.
-//
-// See the package documentation for important details regarding 'timeout'.
-func (p *InactiveHandle) SetTimeout(timeout time.Duration) error {
-	err := p.pcapSetTimeout(timeout)
-	if err != nil {
-		return err
-	}
-	p.timeout = timeout
-	return nil
-}
-
-// SupportedTimestamps returns a list of supported timstamp types for this
-// handle.
-func (p *InactiveHandle) SupportedTimestamps() (out []TimestampSource) {
-	return p.pcapListTstampTypes()
-}
-
-// SetTimestampSource sets the type of timestamp generator PCAP uses when
-// attaching timestamps to packets.
-func (p *InactiveHandle) SetTimestampSource(t TimestampSource) error {
-	return p.pcapSetTstampType(t)
-}
-
-// CannotSetRFMon is returned by SetRFMon if the handle does not allow
-// setting RFMon because pcap_can_set_rfmon returns 0.
-var CannotSetRFMon = errors.New("Cannot set rfmon for this handle")
-
-// SetRFMon turns on radio monitoring mode, similar to promiscuous mode but for
-// wireless networks.  If this mode is enabled, the interface will not need to
-// associate with an access point before it can receive traffic.
-func (p *InactiveHandle) SetRFMon(monitor bool) error {
-	return p.pcapSetRfmon(monitor)
-}
-
-// SetBufferSize sets the buffer size (in bytes) of the handle.
-func (p *InactiveHandle) SetBufferSize(bufferSize int) error {
-	return p.pcapSetBufferSize(bufferSize)
-}
-
-// SetImmediateMode sets (or unsets) the immediate mode of the
-// handle. In immediate mode, packets are delivered to the application
-// as soon as they arrive.  In other words, this overrides SetTimeout.
-func (p *InactiveHandle) SetImmediateMode(mode bool) error {
-	return p.pcapSetImmediateMode(mode)
-}
diff --git a/vendor/github.com/google/gopacket/pcap/pcap_unix.go b/vendor/github.com/google/gopacket/pcap/pcap_unix.go
deleted file mode 100644
index 4d6a4fb..0000000
--- a/vendor/github.com/google/gopacket/pcap/pcap_unix.go
+++ /dev/null
@@ -1,709 +0,0 @@
-// Copyright 2012 Google, Inc. All rights reserved.
-// Copyright 2009-2011 Andreas Krennmair. All rights reserved.
-//
-// Use of this source code is governed by a BSD-style license
-// that can be found in the LICENSE file in the root of the source
-// tree.
-//
-// +build !windows
-
-package pcap
-
-import (
-	"errors"
-	"os"
-	"sync"
-	"syscall"
-	"time"
-	"unsafe"
-
-	"github.com/google/gopacket"
-
-	"github.com/google/gopacket/layers"
-)
-
-/*
-#cgo solaris LDFLAGS: -L /opt/local/lib -lpcap
-#cgo linux LDFLAGS: -lpcap
-#cgo dragonfly LDFLAGS: -lpcap
-#cgo freebsd LDFLAGS: -lpcap
-#cgo openbsd LDFLAGS: -lpcap
-#cgo netbsd LDFLAGS: -lpcap
-#cgo darwin LDFLAGS: -lpcap
-#include <stdlib.h>
-#include <pcap.h>
-#include <stdint.h>
-
-// Some old versions of pcap don't define this constant.
-#ifndef PCAP_NETMASK_UNKNOWN
-#define PCAP_NETMASK_UNKNOWN 0xffffffff
-#endif
-
-// libpcap doesn't actually export its version in a #define-guardable way,
-// so we have to use other defined things to differentiate versions.
-// We assume at least libpcap v1.1 at the moment.
-// See http://upstream-tracker.org/versions/libpcap.html
-
-#ifndef PCAP_ERROR_TSTAMP_PRECISION_NOTSUP  // < v1.5
-#define PCAP_ERROR_TSTAMP_PRECISION_NOTSUP -12
-
-int pcap_set_immediate_mode(pcap_t *p, int mode) {
-  return PCAP_ERROR;
-}
-
-//  libpcap version < v1.5 doesn't have timestamp precision (everything is microsecond)
-//
-//  This means *_tstamp_* functions and macros are missing. Therefore, we emulate these
-//  functions here and pretend the setting the precision works. This is actually the way
-//  the pcap_open_offline_with_tstamp_precision works, because it doesn't return an error
-//  if it was not possible to set the precision, which depends on support by the given file.
-//  => The rest of the functions always pretend as if they could set nano precision and
-//  verify the actual precision with pcap_get_tstamp_precision, which is emulated for <v1.5
-//  to always return micro resolution.
-
-#define PCAP_TSTAMP_PRECISION_MICRO	0
-#define PCAP_TSTAMP_PRECISION_NANO	1
-
-pcap_t *pcap_open_offline_with_tstamp_precision(const char *fname, u_int precision,
-  char *errbuf) {
-  return pcap_open_offline(fname, errbuf);
-}
-
-pcap_t *pcap_fopen_offline_with_tstamp_precision(FILE *fp, u_int precision,
-  char *errbuf) {
-  return pcap_fopen_offline(fp, errbuf);
-}
-
-int pcap_set_tstamp_precision(pcap_t *p, int tstamp_precision) {
-  if (tstamp_precision == PCAP_TSTAMP_PRECISION_MICRO)
-    return 0;
-  return PCAP_ERROR_TSTAMP_PRECISION_NOTSUP;
-}
-
-int pcap_get_tstamp_precision(pcap_t *p) {
-  return PCAP_TSTAMP_PRECISION_MICRO;
-}
-
-#ifndef PCAP_TSTAMP_HOST  // < v1.2
-
-int pcap_set_tstamp_type(pcap_t* p, int t) { return -1; }
-int pcap_list_tstamp_types(pcap_t* p, int** t) { return 0; }
-void pcap_free_tstamp_types(int *tstamp_types) {}
-const char* pcap_tstamp_type_val_to_name(int t) {
-	return "pcap timestamp types not supported";
-}
-int pcap_tstamp_type_name_to_val(const char* t) {
-	return PCAP_ERROR;
-}
-
-#endif  // < v1.2
-#endif  // < v1.5
-
-#ifndef PCAP_ERROR_PROMISC_PERM_DENIED
-#define PCAP_ERROR_PROMISC_PERM_DENIED -11
-#endif
-
-// Windows, Macs, and Linux all use different time types.  Joy.
-#ifdef __APPLE__
-#define gopacket_time_secs_t __darwin_time_t
-#define gopacket_time_usecs_t __darwin_suseconds_t
-#elif __ANDROID__
-#define gopacket_time_secs_t __kernel_time_t
-#define gopacket_time_usecs_t __kernel_suseconds_t
-#elif __GLIBC__
-#define gopacket_time_secs_t __time_t
-#define gopacket_time_usecs_t __suseconds_t
-#else  // Some form of linux/bsd/etc...
-#include <sys/param.h>
-#ifdef __OpenBSD__
-#define gopacket_time_secs_t u_int32_t
-#define gopacket_time_usecs_t u_int32_t
-#else
-#define gopacket_time_secs_t time_t
-#define gopacket_time_usecs_t suseconds_t
-#endif
-#endif
-
-// The things we do to avoid pointers escaping to the heap...
-// According to https://github.com/the-tcpdump-group/libpcap/blob/1131a7c26c6f4d4772e4a2beeaf7212f4dea74ac/pcap.c#L398-L406 ,
-// the return value of pcap_next_ex could be greater than 1 for success.
-// Let's just make it 1 if it comes bigger than 1.
-int pcap_next_ex_escaping(pcap_t *p, uintptr_t pkt_hdr, uintptr_t pkt_data) {
-  int ex = pcap_next_ex(p, (struct pcap_pkthdr**)(pkt_hdr), (const u_char**)(pkt_data));
-  if (ex > 1) {
-    ex = 1;
-  }
-  return ex;
-}
-
-int pcap_offline_filter_escaping(struct bpf_program *fp, uintptr_t pkt_hdr, uintptr_t pkt) {
-	return pcap_offline_filter(fp, (struct pcap_pkthdr*)(pkt_hdr), (const u_char*)(pkt));
-}
-
-// pcap_wait returns when the next packet is available or the timeout expires.
-// Since it uses pcap_get_selectable_fd, it will not work in Windows.
-int pcap_wait(pcap_t *p, int usec) {
-	fd_set fds;
-	int fd;
-	struct timeval tv;
-
-	fd = pcap_get_selectable_fd(p);
-	if(fd < 0) {
-		return fd;
-	}
-
-	FD_ZERO(&fds);
-	FD_SET(fd, &fds);
-
-	tv.tv_sec = 0;
-	tv.tv_usec = usec;
-
-	if(usec != 0) {
-		return select(fd+1, &fds, NULL, NULL, &tv);
-	}
-
-	// block indefinitely if no timeout provided
-	return select(fd+1, &fds, NULL, NULL, NULL);
-}
-
-*/
-import "C"
-
-const errorBufferSize = C.PCAP_ERRBUF_SIZE
-
-const (
-	pcapErrorNotActivated    = C.PCAP_ERROR_NOT_ACTIVATED
-	pcapErrorActivated       = C.PCAP_ERROR_ACTIVATED
-	pcapWarningPromisc       = C.PCAP_WARNING_PROMISC_NOTSUP
-	pcapErrorNoSuchDevice    = C.PCAP_ERROR_NO_SUCH_DEVICE
-	pcapErrorDenied          = C.PCAP_ERROR_PERM_DENIED
-	pcapErrorNotUp           = C.PCAP_ERROR_IFACE_NOT_UP
-	pcapWarning              = C.PCAP_WARNING
-	pcapDIN                  = C.PCAP_D_IN
-	pcapDOUT                 = C.PCAP_D_OUT
-	pcapDINOUT               = C.PCAP_D_INOUT
-	pcapNetmaskUnknown       = C.PCAP_NETMASK_UNKNOWN
-	pcapTstampPrecisionMicro = C.PCAP_TSTAMP_PRECISION_MICRO
-	pcapTstampPrecisionNano  = C.PCAP_TSTAMP_PRECISION_NANO
-)
-
-type pcapPkthdr C.struct_pcap_pkthdr
-type pcapTPtr *C.struct_pcap
-type pcapBpfProgram C.struct_bpf_program
-
-func (h *pcapPkthdr) getSec() int64 {
-	return int64(h.ts.tv_sec)
-}
-
-func (h *pcapPkthdr) getUsec() int64 {
-	return int64(h.ts.tv_usec)
-}
-
-func (h *pcapPkthdr) getLen() int {
-	return int(h.len)
-}
-
-func (h *pcapPkthdr) getCaplen() int {
-	return int(h.caplen)
-}
-
-func pcapGetTstampPrecision(cptr pcapTPtr) int {
-	return int(C.pcap_get_tstamp_precision(cptr))
-}
-
-func pcapSetTstampPrecision(cptr pcapTPtr, precision int) error {
-	ret := C.pcap_set_tstamp_precision(cptr, C.int(precision))
-	if ret < 0 {
-		return errors.New(C.GoString(C.pcap_geterr(cptr)))
-	}
-	return nil
-}
-
-func statusError(status C.int) error {
-	return errors.New(C.GoString(C.pcap_statustostr(status)))
-}
-
-func pcapOpenLive(device string, snaplen int, pro int, timeout int) (*Handle, error) {
-	buf := (*C.char)(C.calloc(errorBufferSize, 1))
-	defer C.free(unsafe.Pointer(buf))
-
-	dev := C.CString(device)
-	defer C.free(unsafe.Pointer(dev))
-
-	cptr := C.pcap_open_live(dev, C.int(snaplen), C.int(pro), C.int(timeout), buf)
-	if cptr == nil {
-		return nil, errors.New(C.GoString(buf))
-	}
-	return &Handle{cptr: cptr}, nil
-}
-
-func openOffline(file string) (handle *Handle, err error) {
-	buf := (*C.char)(C.calloc(errorBufferSize, 1))
-	defer C.free(unsafe.Pointer(buf))
-	cf := C.CString(file)
-	defer C.free(unsafe.Pointer(cf))
-
-	cptr := C.pcap_open_offline_with_tstamp_precision(cf, C.PCAP_TSTAMP_PRECISION_NANO, buf)
-	if cptr == nil {
-		return nil, errors.New(C.GoString(buf))
-	}
-	return &Handle{cptr: cptr}, nil
-}
-
-func (p *Handle) pcapClose() {
-	if p.cptr != nil {
-		C.pcap_close(p.cptr)
-	}
-	p.cptr = nil
-}
-
-func (p *Handle) pcapGeterr() error {
-	return errors.New(C.GoString(C.pcap_geterr(p.cptr)))
-}
-
-func (p *Handle) pcapStats() (*Stats, error) {
-	var cstats C.struct_pcap_stat
-	if C.pcap_stats(p.cptr, &cstats) < 0 {
-		return nil, p.pcapGeterr()
-	}
-	return &Stats{
-		PacketsReceived:  int(cstats.ps_recv),
-		PacketsDropped:   int(cstats.ps_drop),
-		PacketsIfDropped: int(cstats.ps_ifdrop),
-	}, nil
-}
-
-// for libpcap < 1.8 pcap_compile is NOT thread-safe, so protect it.
-var pcapCompileMu sync.Mutex
-
-func (p *Handle) pcapCompile(expr string, maskp uint32) (pcapBpfProgram, error) {
-	var bpf pcapBpfProgram
-	cexpr := C.CString(expr)
-	defer C.free(unsafe.Pointer(cexpr))
-
-	pcapCompileMu.Lock()
-	defer pcapCompileMu.Unlock()
-	if C.pcap_compile(p.cptr, (*C.struct_bpf_program)(&bpf), cexpr, 1, C.bpf_u_int32(maskp)) < 0 {
-		return bpf, p.pcapGeterr()
-	}
-	return bpf, nil
-}
-
-func (p pcapBpfProgram) free() {
-	C.pcap_freecode((*C.struct_bpf_program)(&p))
-}
-
-func (p pcapBpfProgram) toBPFInstruction() []BPFInstruction {
-	bpfInsn := (*[bpfInstructionBufferSize]C.struct_bpf_insn)(unsafe.Pointer(p.bf_insns))[0:p.bf_len:p.bf_len]
-	bpfInstruction := make([]BPFInstruction, len(bpfInsn), len(bpfInsn))
-
-	for i, v := range bpfInsn {
-		bpfInstruction[i].Code = uint16(v.code)
-		bpfInstruction[i].Jt = uint8(v.jt)
-		bpfInstruction[i].Jf = uint8(v.jf)
-		bpfInstruction[i].K = uint32(v.k)
-	}
-	return bpfInstruction
-}
-
-func pcapBpfProgramFromInstructions(bpfInstructions []BPFInstruction) pcapBpfProgram {
-	var bpf pcapBpfProgram
-	bpf.bf_len = C.u_int(len(bpfInstructions))
-	cbpfInsns := C.calloc(C.size_t(len(bpfInstructions)), C.size_t(unsafe.Sizeof(bpfInstructions[0])))
-	gbpfInsns := (*[bpfInstructionBufferSize]C.struct_bpf_insn)(cbpfInsns)
-
-	for i, v := range bpfInstructions {
-		gbpfInsns[i].code = C.u_short(v.Code)
-		gbpfInsns[i].jt = C.u_char(v.Jt)
-		gbpfInsns[i].jf = C.u_char(v.Jf)
-		gbpfInsns[i].k = C.bpf_u_int32(v.K)
-	}
-
-	bpf.bf_insns = (*C.struct_bpf_insn)(cbpfInsns)
-	return bpf
-}
-
-func pcapLookupnet(device string) (netp, maskp uint32, err error) {
-	errorBuf := (*C.char)(C.calloc(errorBufferSize, 1))
-	defer C.free(unsafe.Pointer(errorBuf))
-	dev := C.CString(device)
-	defer C.free(unsafe.Pointer(dev))
-	if C.pcap_lookupnet(
-		dev,
-		(*C.bpf_u_int32)(unsafe.Pointer(&netp)),
-		(*C.bpf_u_int32)(unsafe.Pointer(&maskp)),
-		errorBuf,
-	) < 0 {
-		return 0, 0, errors.New(C.GoString(errorBuf))
-		// We can't lookup the network, but that could be because the interface
-		// doesn't have an IPv4.
-	}
-	return
-}
-
-func (b *BPF) pcapOfflineFilter(ci gopacket.CaptureInfo, data []byte) bool {
-	hdr := (*C.struct_pcap_pkthdr)(&b.hdr)
-	hdr.ts.tv_sec = C.gopacket_time_secs_t(ci.Timestamp.Unix())
-	hdr.ts.tv_usec = C.gopacket_time_usecs_t(ci.Timestamp.Nanosecond() / 1000)
-	hdr.caplen = C.bpf_u_int32(len(data)) // Trust actual length over ci.Length.
-	hdr.len = C.bpf_u_int32(ci.Length)
-	dataptr := (*C.u_char)(unsafe.Pointer(&data[0]))
-	return C.pcap_offline_filter_escaping((*C.struct_bpf_program)(&b.bpf),
-		C.uintptr_t(uintptr(unsafe.Pointer(hdr))),
-		C.uintptr_t(uintptr(unsafe.Pointer(dataptr)))) != 0
-}
-
-func (p *Handle) pcapSetfilter(bpf pcapBpfProgram) error {
-	if C.pcap_setfilter(p.cptr, (*C.struct_bpf_program)(&bpf)) < 0 {
-		return p.pcapGeterr()
-	}
-	return nil
-}
-
-func (p *Handle) pcapListDatalinks() (datalinks []Datalink, err error) {
-	var dltbuf *C.int
-
-	n := int(C.pcap_list_datalinks(p.cptr, &dltbuf))
-	if n < 0 {
-		return nil, p.pcapGeterr()
-	}
-
-	defer C.pcap_free_datalinks(dltbuf)
-
-	datalinks = make([]Datalink, n)
-
-	dltArray := (*[1 << 28]C.int)(unsafe.Pointer(dltbuf))
-
-	for i := 0; i < n; i++ {
-		datalinks[i].Name = pcapDatalinkValToName(int((*dltArray)[i]))
-		datalinks[i].Description = pcapDatalinkValToDescription(int((*dltArray)[i]))
-	}
-
-	return datalinks, nil
-}
-
-func pcapOpenDead(linkType layers.LinkType, captureLength int) (*Handle, error) {
-	cptr := C.pcap_open_dead(C.int(linkType), C.int(captureLength))
-	if cptr == nil {
-		return nil, errors.New("error opening dead capture")
-	}
-
-	return &Handle{cptr: cptr}, nil
-}
-
-func (p *Handle) pcapNextPacketEx() NextError {
-	// This horrible magic allows us to pass a ptr-to-ptr to pcap_next_ex
-	// without causing that ptr-to-ptr to itself be allocated on the heap.
-	// Since Handle itself survives through the duration of the pcap_next_ex
-	// call, this should be perfectly safe for GC stuff, etc.
-
-	return NextError(C.pcap_next_ex_escaping(p.cptr, C.uintptr_t(uintptr(unsafe.Pointer(&p.pkthdr))), C.uintptr_t(uintptr(unsafe.Pointer(&p.bufptr)))))
-}
-
-func (p *Handle) pcapDatalink() layers.LinkType {
-	return layers.LinkType(C.pcap_datalink(p.cptr))
-}
-
-func (p *Handle) pcapSetDatalink(dlt layers.LinkType) error {
-	if C.pcap_set_datalink(p.cptr, C.int(dlt)) < 0 {
-		return p.pcapGeterr()
-	}
-	return nil
-}
-
-func pcapDatalinkValToName(dlt int) string {
-	return C.GoString(C.pcap_datalink_val_to_name(C.int(dlt)))
-}
-
-func pcapDatalinkValToDescription(dlt int) string {
-	return C.GoString(C.pcap_datalink_val_to_description(C.int(dlt)))
-}
-
-func pcapDatalinkNameToVal(name string) int {
-	cptr := C.CString(name)
-	defer C.free(unsafe.Pointer(cptr))
-	return int(C.pcap_datalink_name_to_val(cptr))
-}
-
-func pcapLibVersion() string {
-	return C.GoString(C.pcap_lib_version())
-}
-
-func (p *Handle) isOpen() bool {
-	return p.cptr != nil
-}
-
-type pcapDevices struct {
-	all, cur *C.pcap_if_t
-}
-
-func (p pcapDevices) free() {
-	C.pcap_freealldevs((*C.pcap_if_t)(p.all))
-}
-
-func (p *pcapDevices) next() bool {
-	if p.cur == nil {
-		p.cur = p.all
-		if p.cur == nil {
-			return false
-		}
-		return true
-	}
-	if p.cur.next == nil {
-		return false
-	}
-	p.cur = p.cur.next
-	return true
-}
-
-func (p pcapDevices) name() string {
-	return C.GoString(p.cur.name)
-}
-
-func (p pcapDevices) description() string {
-	return C.GoString(p.cur.description)
-}
-
-func (p pcapDevices) flags() uint32 {
-	return uint32(p.cur.flags)
-}
-
-type pcapAddresses struct {
-	all, cur *C.pcap_addr_t
-}
-
-func (p *pcapAddresses) next() bool {
-	if p.cur == nil {
-		p.cur = p.all
-		if p.cur == nil {
-			return false
-		}
-		return true
-	}
-	if p.cur.next == nil {
-		return false
-	}
-	p.cur = p.cur.next
-	return true
-}
-
-func (p pcapAddresses) addr() *syscall.RawSockaddr {
-	return (*syscall.RawSockaddr)(unsafe.Pointer(p.cur.addr))
-}
-
-func (p pcapAddresses) netmask() *syscall.RawSockaddr {
-	return (*syscall.RawSockaddr)(unsafe.Pointer(p.cur.netmask))
-}
-
-func (p pcapAddresses) broadaddr() *syscall.RawSockaddr {
-	return (*syscall.RawSockaddr)(unsafe.Pointer(p.cur.broadaddr))
-}
-
-func (p pcapAddresses) dstaddr() *syscall.RawSockaddr {
-	return (*syscall.RawSockaddr)(unsafe.Pointer(p.cur.dstaddr))
-}
-
-func (p pcapDevices) addresses() pcapAddresses {
-	return pcapAddresses{all: p.cur.addresses}
-}
-
-func pcapFindAllDevs() (pcapDevices, error) {
-	var buf *C.char
-	buf = (*C.char)(C.calloc(errorBufferSize, 1))
-	defer C.free(unsafe.Pointer(buf))
-	var alldevsp pcapDevices
-
-	if C.pcap_findalldevs((**C.pcap_if_t)(&alldevsp.all), buf) < 0 {
-		return pcapDevices{}, errors.New(C.GoString(buf))
-	}
-	return alldevsp, nil
-}
-
-func (p *Handle) pcapSendpacket(data []byte) error {
-	if C.pcap_sendpacket(p.cptr, (*C.u_char)(&data[0]), (C.int)(len(data))) < 0 {
-		return p.pcapGeterr()
-	}
-	return nil
-}
-
-func (p *Handle) pcapSetdirection(direction Direction) error {
-	if status := C.pcap_setdirection(p.cptr, (C.pcap_direction_t)(direction)); status < 0 {
-		return statusError(status)
-	}
-	return nil
-}
-
-func (p *Handle) pcapSnapshot() int {
-	return int(C.pcap_snapshot(p.cptr))
-}
-
-func (t TimestampSource) pcapTstampTypeValToName() string {
-	return C.GoString(C.pcap_tstamp_type_val_to_name(C.int(t)))
-}
-
-func pcapTstampTypeNameToVal(s string) (TimestampSource, error) {
-	cs := C.CString(s)
-	defer C.free(unsafe.Pointer(cs))
-	t := C.pcap_tstamp_type_name_to_val(cs)
-	if t < 0 {
-		return 0, statusError(t)
-	}
-	return TimestampSource(t), nil
-}
-
-func (p *InactiveHandle) pcapGeterr() error {
-	return errors.New(C.GoString(C.pcap_geterr(p.cptr)))
-}
-
-func (p *InactiveHandle) pcapActivate() (*Handle, activateError) {
-	ret := activateError(C.pcap_activate(p.cptr))
-	if ret != aeNoError {
-		return nil, ret
-	}
-	h := &Handle{
-		cptr: p.cptr,
-	}
-	p.cptr = nil
-	return h, ret
-}
-
-func (p *InactiveHandle) pcapClose() {
-	if p.cptr != nil {
-		C.pcap_close(p.cptr)
-	}
-}
-
-func pcapCreate(device string) (*InactiveHandle, error) {
-	buf := (*C.char)(C.calloc(errorBufferSize, 1))
-	defer C.free(unsafe.Pointer(buf))
-	dev := C.CString(device)
-	defer C.free(unsafe.Pointer(dev))
-
-	cptr := C.pcap_create(dev, buf)
-	if cptr == nil {
-		return nil, errors.New(C.GoString(buf))
-	}
-	return &InactiveHandle{cptr: cptr}, nil
-}
-
-func (p *InactiveHandle) pcapSetSnaplen(snaplen int) error {
-	if status := C.pcap_set_snaplen(p.cptr, C.int(snaplen)); status < 0 {
-		return statusError(status)
-	}
-	return nil
-}
-
-func (p *InactiveHandle) pcapSetPromisc(promisc bool) error {
-	var pro C.int
-	if promisc {
-		pro = 1
-	}
-	if status := C.pcap_set_promisc(p.cptr, pro); status < 0 {
-		return statusError(status)
-	}
-	return nil
-}
-
-func (p *InactiveHandle) pcapSetTimeout(timeout time.Duration) error {
-	if status := C.pcap_set_timeout(p.cptr, C.int(timeoutMillis(timeout))); status < 0 {
-		return statusError(status)
-	}
-	return nil
-}
-
-func (p *InactiveHandle) pcapListTstampTypes() (out []TimestampSource) {
-	var types *C.int
-	n := int(C.pcap_list_tstamp_types(p.cptr, &types))
-	if n < 0 {
-		return // public interface doesn't have error :(
-	}
-	defer C.pcap_free_tstamp_types(types)
-	typesArray := (*[1 << 28]C.int)(unsafe.Pointer(types))
-	for i := 0; i < n; i++ {
-		out = append(out, TimestampSource((*typesArray)[i]))
-	}
-	return
-}
-
-func (p *InactiveHandle) pcapSetTstampType(t TimestampSource) error {
-	if status := C.pcap_set_tstamp_type(p.cptr, C.int(t)); status < 0 {
-		return statusError(status)
-	}
-	return nil
-}
-
-func (p *InactiveHandle) pcapSetRfmon(monitor bool) error {
-	var mon C.int
-	if monitor {
-		mon = 1
-	}
-	switch canset := C.pcap_can_set_rfmon(p.cptr); canset {
-	case 0:
-		return CannotSetRFMon
-	case 1:
-		// success
-	default:
-		return statusError(canset)
-	}
-	if status := C.pcap_set_rfmon(p.cptr, mon); status != 0 {
-		return statusError(status)
-	}
-	return nil
-}
-
-func (p *InactiveHandle) pcapSetBufferSize(bufferSize int) error {
-	if status := C.pcap_set_buffer_size(p.cptr, C.int(bufferSize)); status < 0 {
-		return statusError(status)
-	}
-	return nil
-}
-
-func (p *InactiveHandle) pcapSetImmediateMode(mode bool) error {
-	var md C.int
-	if mode {
-		md = 1
-	}
-	if status := C.pcap_set_immediate_mode(p.cptr, md); status < 0 {
-		return statusError(status)
-	}
-	return nil
-}
-
-func (p *Handle) setNonBlocking() error {
-	buf := (*C.char)(C.calloc(errorBufferSize, 1))
-	defer C.free(unsafe.Pointer(buf))
-
-	// Change the device to non-blocking, we'll use pcap_wait to wait until the
-	// handle is ready to read.
-	if v := C.pcap_setnonblock(p.cptr, 1, buf); v < -1 {
-		return errors.New(C.GoString(buf))
-	}
-
-	return nil
-}
-
-// waitForPacket waits for a packet or for the timeout to expire.
-func (p *Handle) waitForPacket() {
-	// need to wait less than the read timeout according to pcap documentation.
-	// timeoutMillis rounds up to at least one millisecond so we can safely
-	// subtract up to a millisecond.
-	usec := timeoutMillis(p.timeout) * 1000
-	usec -= 100
-
-	C.pcap_wait(p.cptr, C.int(usec))
-}
-
-// openOfflineFile returns contents of input file as a *Handle.
-func openOfflineFile(file *os.File) (handle *Handle, err error) {
-	buf := (*C.char)(C.calloc(errorBufferSize, 1))
-	defer C.free(unsafe.Pointer(buf))
-	cmode := C.CString("rb")
-	defer C.free(unsafe.Pointer(cmode))
-	cf := C.fdopen(C.int(file.Fd()), cmode)
-
-	cptr := C.pcap_fopen_offline_with_tstamp_precision(cf, C.PCAP_TSTAMP_PRECISION_NANO, buf)
-	if cptr == nil {
-		return nil, errors.New(C.GoString(buf))
-	}
-	return &Handle{cptr: cptr}, nil
-}
diff --git a/vendor/github.com/google/gopacket/pcap/pcap_windows.go b/vendor/github.com/google/gopacket/pcap/pcap_windows.go
deleted file mode 100644
index 0a53338..0000000
--- a/vendor/github.com/google/gopacket/pcap/pcap_windows.go
+++ /dev/null
@@ -1,885 +0,0 @@
-// Copyright 2012 Google, Inc. All rights reserved.
-// Copyright 2009-2011 Andreas Krennmair. All rights reserved.
-//
-// Use of this source code is governed by a BSD-style license
-// that can be found in the LICENSE file in the root of the source
-// tree.
-
-package pcap
-
-import (
-	"errors"
-	"fmt"
-	"os"
-	"runtime"
-	"sync"
-	"syscall"
-	"time"
-	"unsafe"
-
-	"github.com/google/gopacket"
-	"github.com/google/gopacket/layers"
-)
-
-var pcapLoaded = false
-
-const npcapPath = "\\Npcap"
-
-func initDllPath(kernel32 syscall.Handle) {
-	setDllDirectory, err := syscall.GetProcAddress(kernel32, "SetDllDirectoryA")
-	if err != nil {
-		// we can't do anything since SetDllDirectoryA is missing - fall back to use first wpcap.dll we encounter
-		return
-	}
-	getSystemDirectory, err := syscall.GetProcAddress(kernel32, "GetSystemDirectoryA")
-	if err != nil {
-		// we can't do anything since SetDllDirectoryA is missing - fall back to use first wpcap.dll we encounter
-		return
-	}
-	buf := make([]byte, 4096)
-	r, _, _ := syscall.Syscall(getSystemDirectory, 2, uintptr(unsafe.Pointer(&buf[0])), uintptr(len(buf)), 0)
-	if r == 0 || r > 4096-uintptr(len(npcapPath))-1 {
-		// we can't do anything since SetDllDirectoryA is missing - fall back to use first wpcap.dll we encounter
-		return
-	}
-	copy(buf[r:], npcapPath)
-	_, _, _ = syscall.Syscall(setDllDirectory, 1, uintptr(unsafe.Pointer(&buf[0])), 0, 0)
-	// ignore errors here - we just fallback to load wpcap.dll from default locations
-}
-
-// loadedDllPath will hold the full pathname of the loaded wpcap.dll after init if possible
-var loadedDllPath = "wpcap.dll"
-
-func initLoadedDllPath(kernel32 syscall.Handle) {
-	getModuleFileName, err := syscall.GetProcAddress(kernel32, "GetModuleFileNameA")
-	if err != nil {
-		// we can't get the filename of the loaded module in this case - just leave default of wpcap.dll
-		return
-	}
-	buf := make([]byte, 4096)
-	r, _, _ := syscall.Syscall(getModuleFileName, 3, uintptr(wpcapHandle), uintptr(unsafe.Pointer(&buf[0])), uintptr(len(buf)))
-	if r == 0 {
-		// we can't get the filename of the loaded module in this case - just leave default of wpcap.dll
-		return
-	}
-	loadedDllPath = string(buf[:int(r)])
-}
-
-func mustLoad(fun string) uintptr {
-	addr, err := syscall.GetProcAddress(wpcapHandle, fun)
-	if err != nil {
-		panic(fmt.Sprintf("Couldn't load function %s from %s", fun, loadedDllPath))
-	}
-	return addr
-}
-
-func mightLoad(fun string) uintptr {
-	addr, err := syscall.GetProcAddress(wpcapHandle, fun)
-	if err != nil {
-		return 0
-	}
-	return addr
-}
-
-func byteSliceToString(bval []byte) string {
-	for i := range bval {
-		if bval[i] == 0 {
-			return string(bval[:i])
-		}
-	}
-	return string(bval[:])
-}
-
-// bytePtrToString returns a string copied from pointer to a null terminated byte array
-// WARNING: ONLY SAFE WITH IF r POINTS TO C MEMORY!
-// govet will complain about this function for the reason stated above
-func bytePtrToString(r uintptr) string {
-	if r == 0 {
-		return ""
-	}
-	bval := (*[1 << 30]byte)(unsafe.Pointer(r))
-	return byteSliceToString(bval[:])
-}
-
-var wpcapHandle syscall.Handle
-var msvcrtHandle syscall.Handle
-var (
-	callocPtr,
-	pcapStrerrorPtr,
-	pcapStatustostrPtr,
-	pcapOpenLivePtr,
-	pcapOpenOfflinePtr,
-	pcapClosePtr,
-	pcapGeterrPtr,
-	pcapStatsPtr,
-	pcapCompilePtr,
-	pcapFreecodePtr,
-	pcapLookupnetPtr,
-	pcapOfflineFilterPtr,
-	pcapSetfilterPtr,
-	pcapListDatalinksPtr,
-	pcapFreeDatalinksPtr,
-	pcapDatalinkValToNamePtr,
-	pcapDatalinkValToDescriptionPtr,
-	pcapOpenDeadPtr,
-	pcapNextExPtr,
-	pcapDatalinkPtr,
-	pcapSetDatalinkPtr,
-	pcapDatalinkNameToValPtr,
-	pcapLibVersionPtr,
-	pcapFreealldevsPtr,
-	pcapFindalldevsPtr,
-	pcapSendpacketPtr,
-	pcapSetdirectionPtr,
-	pcapSnapshotPtr,
-	pcapTstampTypeValToNamePtr,
-	pcapTstampTypeNameToValPtr,
-	pcapListTstampTypesPtr,
-	pcapFreeTstampTypesPtr,
-	pcapSetTstampTypePtr,
-	pcapGetTstampPrecisionPtr,
-	pcapSetTstampPrecisionPtr,
-	pcapOpenOfflineWithTstampPrecisionPtr,
-	pcapHOpenOfflineWithTstampPrecisionPtr,
-	pcapActivatePtr,
-	pcapCreatePtr,
-	pcapSetSnaplenPtr,
-	pcapSetPromiscPtr,
-	pcapSetTimeoutPtr,
-	pcapCanSetRfmonPtr,
-	pcapSetRfmonPtr,
-	pcapSetBufferSizePtr,
-	pcapSetImmediateModePtr,
-	pcapHopenOfflinePtr uintptr
-)
-
-func init() {
-	LoadWinPCAP()
-}
-
-// LoadWinPCAP attempts to dynamically load the wpcap DLL and resolve necessary functions
-func LoadWinPCAP() error {
-	if pcapLoaded {
-		return nil
-	}
-
-	kernel32, err := syscall.LoadLibrary("kernel32.dll")
-	if err != nil {
-		return fmt.Errorf("couldn't load kernel32.dll")
-	}
-	defer syscall.FreeLibrary(kernel32)
-
-	initDllPath(kernel32)
-
-	wpcapHandle, err = syscall.LoadLibrary("wpcap.dll")
-	if err != nil {
-		return fmt.Errorf("couldn't load wpcap.dll")
-	}
-	initLoadedDllPath(kernel32)
-	msvcrtHandle, err = syscall.LoadLibrary("msvcrt.dll")
-	if err != nil {
-		return fmt.Errorf("couldn't load msvcrt.dll")
-	}
-	callocPtr, err = syscall.GetProcAddress(msvcrtHandle, "calloc")
-	if err != nil {
-		return fmt.Errorf("couldn't get calloc function")
-	}
-
-	pcapStrerrorPtr = mustLoad("pcap_strerror")
-	pcapStatustostrPtr = mightLoad("pcap_statustostr") // not available on winpcap
-	pcapOpenLivePtr = mustLoad("pcap_open_live")
-	pcapOpenOfflinePtr = mustLoad("pcap_open_offline")
-	pcapClosePtr = mustLoad("pcap_close")
-	pcapGeterrPtr = mustLoad("pcap_geterr")
-	pcapStatsPtr = mustLoad("pcap_stats")
-	pcapCompilePtr = mustLoad("pcap_compile")
-	pcapFreecodePtr = mustLoad("pcap_freecode")
-	pcapLookupnetPtr = mustLoad("pcap_lookupnet")
-	pcapOfflineFilterPtr = mustLoad("pcap_offline_filter")
-	pcapSetfilterPtr = mustLoad("pcap_setfilter")
-	pcapListDatalinksPtr = mustLoad("pcap_list_datalinks")
-	pcapFreeDatalinksPtr = mustLoad("pcap_free_datalinks")
-	pcapDatalinkValToNamePtr = mustLoad("pcap_datalink_val_to_name")
-	pcapDatalinkValToDescriptionPtr = mustLoad("pcap_datalink_val_to_description")
-	pcapOpenDeadPtr = mustLoad("pcap_open_dead")
-	pcapNextExPtr = mustLoad("pcap_next_ex")
-	pcapDatalinkPtr = mustLoad("pcap_datalink")
-	pcapSetDatalinkPtr = mustLoad("pcap_set_datalink")
-	pcapDatalinkNameToValPtr = mustLoad("pcap_datalink_name_to_val")
-	pcapLibVersionPtr = mustLoad("pcap_lib_version")
-	pcapFreealldevsPtr = mustLoad("pcap_freealldevs")
-	pcapFindalldevsPtr = mustLoad("pcap_findalldevs")
-	pcapSendpacketPtr = mustLoad("pcap_sendpacket")
-	pcapSetdirectionPtr = mustLoad("pcap_setdirection")
-	pcapSnapshotPtr = mustLoad("pcap_snapshot")
-	//libpcap <1.2 doesn't have pcap_*_tstamp_* functions
-	pcapTstampTypeValToNamePtr = mightLoad("pcap_tstamp_type_val_to_name")
-	pcapTstampTypeNameToValPtr = mightLoad("pcap_tstamp_type_name_to_val")
-	pcapListTstampTypesPtr = mightLoad("pcap_list_tstamp_types")
-	pcapFreeTstampTypesPtr = mightLoad("pcap_free_tstamp_types")
-	pcapSetTstampTypePtr = mightLoad("pcap_set_tstamp_type")
-	pcapGetTstampPrecisionPtr = mightLoad("pcap_get_tstamp_precision")
-	pcapSetTstampPrecisionPtr = mightLoad("pcap_set_tstamp_precision")
-	pcapOpenOfflineWithTstampPrecisionPtr = mightLoad("pcap_open_offline_with_tstamp_precision")
-	pcapHOpenOfflineWithTstampPrecisionPtr = mightLoad("pcap_hopen_offline_with_tstamp_precision")
-	pcapActivatePtr = mustLoad("pcap_activate")
-	pcapCreatePtr = mustLoad("pcap_create")
-	pcapSetSnaplenPtr = mustLoad("pcap_set_snaplen")
-	pcapSetPromiscPtr = mustLoad("pcap_set_promisc")
-	pcapSetTimeoutPtr = mustLoad("pcap_set_timeout")
-	//winpcap does not support rfmon
-	pcapCanSetRfmonPtr = mightLoad("pcap_can_set_rfmon")
-	pcapSetRfmonPtr = mightLoad("pcap_set_rfmon")
-	pcapSetBufferSizePtr = mustLoad("pcap_set_buffer_size")
-	//libpcap <1.5 does not have pcap_set_immediate_mode
-	pcapSetImmediateModePtr = mightLoad("pcap_set_immediate_mode")
-	pcapHopenOfflinePtr = mustLoad("pcap_hopen_offline")
-
-	pcapLoaded = true
-	return nil
-}
-
-func (h *pcapPkthdr) getSec() int64 {
-	return int64(h.Ts.Sec)
-}
-
-func (h *pcapPkthdr) getUsec() int64 {
-	return int64(h.Ts.Usec)
-}
-
-func (h *pcapPkthdr) getLen() int {
-	return int(h.Len)
-}
-
-func (h *pcapPkthdr) getCaplen() int {
-	return int(h.Caplen)
-}
-
-func statusError(status pcapCint) error {
-	var ret uintptr
-	if pcapStatustostrPtr == 0 {
-		ret, _, _ = syscall.Syscall(pcapStrerrorPtr, 1, uintptr(status), 0, 0)
-	} else {
-		ret, _, _ = syscall.Syscall(pcapStatustostrPtr, 1, uintptr(status), 0, 0)
-	}
-	return errors.New(bytePtrToString(ret))
-}
-
-func pcapGetTstampPrecision(cptr pcapTPtr) int {
-	if pcapGetTstampPrecisionPtr == 0 {
-		return pcapTstampPrecisionMicro
-	}
-	ret, _, _ := syscall.Syscall(pcapGetTstampPrecisionPtr, 1, uintptr(cptr), 0, 0)
-	return int(pcapCint(ret))
-}
-
-func pcapSetTstampPrecision(cptr pcapTPtr, precision int) error {
-	if pcapSetTstampPrecisionPtr == 0 {
-		return errors.New("Not supported")
-	}
-	ret, _, _ := syscall.Syscall(pcapSetTstampPrecisionPtr, 2, uintptr(cptr), uintptr(precision), 0)
-	if pcapCint(ret) < 0 {
-		return errors.New("Not supported")
-	}
-	return nil
-}
-
-func pcapOpenLive(device string, snaplen int, pro int, timeout int) (*Handle, error) {
-	err := LoadWinPCAP()
-	if err != nil {
-		return nil, err
-	}
-
-	buf := make([]byte, errorBufferSize)
-	dev, err := syscall.BytePtrFromString(device)
-	if err != nil {
-		return nil, err
-	}
-
-	cptr, _, _ := syscall.Syscall6(pcapOpenLivePtr, 5, uintptr(unsafe.Pointer(dev)), uintptr(snaplen), uintptr(pro), uintptr(timeout), uintptr(unsafe.Pointer(&buf[0])), 0)
-
-	if cptr == 0 {
-		return nil, errors.New(byteSliceToString(buf))
-	}
-	return &Handle{cptr: pcapTPtr(cptr)}, nil
-}
-
-func openOffline(file string) (handle *Handle, err error) {
-	err = LoadWinPCAP()
-	if err != nil {
-		return nil, err
-	}
-
-	buf := make([]byte, errorBufferSize)
-	f, err := syscall.BytePtrFromString(file)
-	if err != nil {
-		return nil, err
-	}
-
-	var cptr uintptr
-	if pcapOpenOfflineWithTstampPrecisionPtr == 0 {
-		cptr, _, _ = syscall.Syscall(pcapOpenOfflinePtr, 2, uintptr(unsafe.Pointer(f)), uintptr(unsafe.Pointer(&buf[0])), 0)
-	} else {
-		cptr, _, _ = syscall.Syscall(pcapOpenOfflineWithTstampPrecisionPtr, 3, uintptr(unsafe.Pointer(f)), uintptr(pcapTstampPrecisionNano), uintptr(unsafe.Pointer(&buf[0])))
-	}
-
-	if cptr == 0 {
-		return nil, errors.New(byteSliceToString(buf))
-	}
-
-	h := &Handle{cptr: pcapTPtr(cptr)}
-	return h, nil
-}
-
-func (p *Handle) pcapClose() {
-	if p.cptr != 0 {
-		_, _, _ = syscall.Syscall(pcapClosePtr, 1, uintptr(p.cptr), 0, 0)
-	}
-	p.cptr = 0
-}
-
-func (p *Handle) pcapGeterr() error {
-	ret, _, _ := syscall.Syscall(pcapGeterrPtr, 1, uintptr(p.cptr), 0, 0)
-	return errors.New(bytePtrToString(ret))
-}
-
-func (p *Handle) pcapStats() (*Stats, error) {
-	var cstats pcapStats
-	ret, _, _ := syscall.Syscall(pcapStatsPtr, 2, uintptr(p.cptr), uintptr(unsafe.Pointer(&cstats)), 0)
-	if pcapCint(ret) < 0 {
-		return nil, p.pcapGeterr()
-	}
-	return &Stats{
-		PacketsReceived:  int(cstats.Recv),
-		PacketsDropped:   int(cstats.Drop),
-		PacketsIfDropped: int(cstats.Ifdrop),
-	}, nil
-}
-
-// for libpcap < 1.8 pcap_compile is NOT thread-safe, so protect it.
-var pcapCompileMu sync.Mutex
-
-func (p *Handle) pcapCompile(expr string, maskp uint32) (pcapBpfProgram, error) {
-	var bpf pcapBpfProgram
-	cexpr, err := syscall.BytePtrFromString(expr)
-	if err != nil {
-		return pcapBpfProgram{}, err
-	}
-	pcapCompileMu.Lock()
-	defer pcapCompileMu.Unlock()
-	res, _, _ := syscall.Syscall6(pcapCompilePtr, 5, uintptr(p.cptr), uintptr(unsafe.Pointer(&bpf)), uintptr(unsafe.Pointer(cexpr)), uintptr(1), uintptr(maskp), 0)
-	if pcapCint(res) < 0 {
-		return bpf, p.pcapGeterr()
-	}
-	return bpf, nil
-}
-
-func (p pcapBpfProgram) free() {
-	_, _, _ = syscall.Syscall(pcapFreecodePtr, 1, uintptr(unsafe.Pointer(&p)), 0, 0)
-}
-
-func (p pcapBpfProgram) toBPFInstruction() []BPFInstruction {
-	bpfInsn := (*[bpfInstructionBufferSize]pcapBpfInstruction)(unsafe.Pointer(p.Insns))[0:p.Len:p.Len]
-	bpfInstruction := make([]BPFInstruction, len(bpfInsn), len(bpfInsn))
-
-	for i, v := range bpfInsn {
-		bpfInstruction[i].Code = v.Code
-		bpfInstruction[i].Jt = v.Jt
-		bpfInstruction[i].Jf = v.Jf
-		bpfInstruction[i].K = v.K
-	}
-	return bpfInstruction
-}
-
-func pcapBpfProgramFromInstructions(bpfInstructions []BPFInstruction) pcapBpfProgram {
-	var bpf pcapBpfProgram
-	bpf.Len = uint32(len(bpfInstructions))
-	cbpfInsns, _, _ := syscall.Syscall(callocPtr, 2, uintptr(len(bpfInstructions)), uintptr(unsafe.Sizeof(bpfInstructions[0])), 0)
-	gbpfInsns := (*[bpfInstructionBufferSize]pcapBpfInstruction)(unsafe.Pointer(cbpfInsns))
-
-	for i, v := range bpfInstructions {
-		gbpfInsns[i].Code = v.Code
-		gbpfInsns[i].Jt = v.Jt
-		gbpfInsns[i].Jf = v.Jf
-		gbpfInsns[i].K = v.K
-	}
-
-	bpf.Insns = (*pcapBpfInstruction)(unsafe.Pointer(cbpfInsns))
-	return bpf
-}
-
-func pcapLookupnet(device string) (netp, maskp uint32, err error) {
-	err = LoadWinPCAP()
-	if err != nil {
-		return 0, 0, err
-	}
-
-	buf := make([]byte, errorBufferSize)
-	dev, err := syscall.BytePtrFromString(device)
-	if err != nil {
-		return 0, 0, err
-	}
-	e, _, _ := syscall.Syscall6(pcapLookupnetPtr, 4, uintptr(unsafe.Pointer(dev)), uintptr(unsafe.Pointer(&netp)), uintptr(unsafe.Pointer(&maskp)), uintptr(unsafe.Pointer(&buf[0])), 0, 0)
-	if pcapCint(e) < 0 {
-		return 0, 0, errors.New(byteSliceToString(buf))
-	}
-	return
-}
-
-func (b *BPF) pcapOfflineFilter(ci gopacket.CaptureInfo, data []byte) bool {
-	var hdr pcapPkthdr
-	hdr.Ts.Sec = int32(ci.Timestamp.Unix())
-	hdr.Ts.Usec = int32(ci.Timestamp.Nanosecond() / 1000)
-	hdr.Caplen = uint32(len(data)) // Trust actual length over ci.Length.
-	hdr.Len = uint32(ci.Length)
-	e, _, _ := syscall.Syscall(pcapOfflineFilterPtr, 3, uintptr(unsafe.Pointer(&b.bpf)), uintptr(unsafe.Pointer(&hdr)), uintptr(unsafe.Pointer(&data[0])))
-	return e != 0
-}
-
-func (p *Handle) pcapSetfilter(bpf pcapBpfProgram) error {
-	e, _, _ := syscall.Syscall(pcapSetfilterPtr, 2, uintptr(p.cptr), uintptr(unsafe.Pointer(&bpf)), 0)
-	if pcapCint(e) < 0 {
-		return p.pcapGeterr()
-	}
-	return nil
-}
-
-func (p *Handle) pcapListDatalinks() (datalinks []Datalink, err error) {
-	var dltbuf *pcapCint
-	ret, _, _ := syscall.Syscall(pcapListDatalinksPtr, 2, uintptr(p.cptr), uintptr(unsafe.Pointer(&dltbuf)), 0)
-
-	n := int(pcapCint(ret))
-
-	if n < 0 {
-		return nil, p.pcapGeterr()
-	}
-	defer syscall.Syscall(pcapFreeDatalinksPtr, 1, uintptr(unsafe.Pointer(dltbuf)), 0, 0)
-
-	datalinks = make([]Datalink, n)
-
-	dltArray := (*[1 << 28]pcapCint)(unsafe.Pointer(dltbuf))
-
-	for i := 0; i < n; i++ {
-		datalinks[i].Name = pcapDatalinkValToName(int((*dltArray)[i]))
-		datalinks[i].Description = pcapDatalinkValToDescription(int((*dltArray)[i]))
-	}
-
-	return datalinks, nil
-}
-
-func pcapOpenDead(linkType layers.LinkType, captureLength int) (*Handle, error) {
-	err := LoadWinPCAP()
-	if err != nil {
-		return nil, err
-	}
-
-	cptr, _, _ := syscall.Syscall(pcapOpenDeadPtr, 2, uintptr(linkType), uintptr(captureLength), 0)
-	if cptr == 0 {
-		return nil, errors.New("error opening dead capture")
-	}
-
-	return &Handle{cptr: pcapTPtr(cptr)}, nil
-}
-
-func (p *Handle) pcapNextPacketEx() NextError {
-	r, _, _ := syscall.Syscall(pcapNextExPtr, 3, uintptr(p.cptr), uintptr(unsafe.Pointer(&p.pkthdr)), uintptr(unsafe.Pointer(&p.bufptr)))
-	ret := pcapCint(r)
-	// According to https://github.com/the-tcpdump-group/libpcap/blob/1131a7c26c6f4d4772e4a2beeaf7212f4dea74ac/pcap.c#L398-L406 ,
-	// the return value of pcap_next_ex could be greater than 1 for success.
-	// Let's just make it 1 if it comes bigger than 1.
-	if ret > 1 {
-		ret = 1
-	}
-	return NextError(ret)
-}
-
-func (p *Handle) pcapDatalink() layers.LinkType {
-	ret, _, _ := syscall.Syscall(pcapDatalinkPtr, 1, uintptr(p.cptr), 0, 0)
-	return layers.LinkType(ret)
-}
-
-func (p *Handle) pcapSetDatalink(dlt layers.LinkType) error {
-	ret, _, _ := syscall.Syscall(pcapSetDatalinkPtr, 2, uintptr(p.cptr), uintptr(dlt), 0)
-	if pcapCint(ret) < 0 {
-		return p.pcapGeterr()
-	}
-	return nil
-}
-
-func pcapDatalinkValToName(dlt int) string {
-	err := LoadWinPCAP()
-	if err != nil {
-		panic(err)
-	}
-	ret, _, _ := syscall.Syscall(pcapDatalinkValToNamePtr, 1, uintptr(dlt), 0, 0)
-	return bytePtrToString(ret)
-}
-
-func pcapDatalinkValToDescription(dlt int) string {
-	err := LoadWinPCAP()
-	if err != nil {
-		panic(err)
-	}
-	ret, _, _ := syscall.Syscall(pcapDatalinkValToDescriptionPtr, 1, uintptr(dlt), 0, 0)
-	return bytePtrToString(ret)
-}
-
-func pcapDatalinkNameToVal(name string) int {
-	err := LoadWinPCAP()
-	if err != nil {
-		panic(err)
-	}
-	cptr, err := syscall.BytePtrFromString(name)
-	if err != nil {
-		return 0
-	}
-	ret, _, _ := syscall.Syscall(pcapDatalinkNameToValPtr, 1, uintptr(unsafe.Pointer(cptr)), 0, 0)
-	return int(pcapCint(ret))
-}
-
-func pcapLibVersion() string {
-	err := LoadWinPCAP()
-	if err != nil {
-		panic(err)
-	}
-	ret, _, _ := syscall.Syscall(pcapLibVersionPtr, 0, 0, 0, 0)
-	return bytePtrToString(ret)
-}
-
-func (p *Handle) isOpen() bool {
-	return p.cptr != 0
-}
-
-type pcapDevices struct {
-	all, cur *pcapIf
-}
-
-func (p pcapDevices) free() {
-	syscall.Syscall(pcapFreealldevsPtr, 1, uintptr(unsafe.Pointer(p.all)), 0, 0)
-}
-
-func (p *pcapDevices) next() bool {
-	if p.cur == nil {
-		p.cur = p.all
-		if p.cur == nil {
-			return false
-		}
-		return true
-	}
-	if p.cur.Next == nil {
-		return false
-	}
-	p.cur = p.cur.Next
-	return true
-}
-
-func (p pcapDevices) name() string {
-	return bytePtrToString(uintptr(unsafe.Pointer(p.cur.Name)))
-}
-
-func (p pcapDevices) description() string {
-	return bytePtrToString(uintptr(unsafe.Pointer(p.cur.Description)))
-}
-
-func (p pcapDevices) flags() uint32 {
-	return p.cur.Flags
-}
-
-type pcapAddresses struct {
-	all, cur *pcapAddr
-}
-
-func (p *pcapAddresses) next() bool {
-	if p.cur == nil {
-		p.cur = p.all
-		if p.cur == nil {
-			return false
-		}
-		return true
-	}
-	if p.cur.Next == nil {
-		return false
-	}
-	p.cur = p.cur.Next
-	return true
-}
-
-func (p pcapAddresses) addr() *syscall.RawSockaddr {
-	return p.cur.Addr
-}
-
-func (p pcapAddresses) netmask() *syscall.RawSockaddr {
-	return p.cur.Netmask
-}
-
-func (p pcapAddresses) broadaddr() *syscall.RawSockaddr {
-	return p.cur.Broadaddr
-}
-
-func (p pcapAddresses) dstaddr() *syscall.RawSockaddr {
-	return p.cur.Dstaddr
-}
-
-func (p pcapDevices) addresses() pcapAddresses {
-	return pcapAddresses{all: p.cur.Addresses}
-}
-
-func pcapFindAllDevs() (pcapDevices, error) {
-	var alldevsp pcapDevices
-	err := LoadWinPCAP()
-	if err != nil {
-		return alldevsp, err
-	}
-
-	buf := make([]byte, errorBufferSize)
-
-	ret, _, _ := syscall.Syscall(pcapFindalldevsPtr, 2, uintptr(unsafe.Pointer(&alldevsp.all)), uintptr(unsafe.Pointer(&buf[0])), 0)
-
-	if pcapCint(ret) < 0 {
-		return pcapDevices{}, errors.New(byteSliceToString(buf))
-	}
-	return alldevsp, nil
-}
-
-func (p *Handle) pcapSendpacket(data []byte) error {
-	ret, _, _ := syscall.Syscall(pcapSendpacketPtr, 3, uintptr(p.cptr), uintptr(unsafe.Pointer(&data[0])), uintptr(len(data)))
-	if pcapCint(ret) < 0 {
-		return p.pcapGeterr()
-	}
-	return nil
-}
-
-func (p *Handle) pcapSetdirection(direction Direction) error {
-	status, _, _ := syscall.Syscall(pcapSetdirectionPtr, 2, uintptr(p.cptr), uintptr(direction), 0)
-	if pcapCint(status) < 0 {
-		return statusError(pcapCint(status))
-	}
-	return nil
-}
-
-func (p *Handle) pcapSnapshot() int {
-	ret, _, _ := syscall.Syscall(pcapSnapshotPtr, 1, uintptr(p.cptr), 0, 0)
-	return int(pcapCint(ret))
-}
-
-func (t TimestampSource) pcapTstampTypeValToName() string {
-	err := LoadWinPCAP()
-	if err != nil {
-		return err.Error()
-	}
-
-	//libpcap <1.2 doesn't have pcap_*_tstamp_* functions
-	if pcapTstampTypeValToNamePtr == 0 {
-		return "pcap timestamp types not supported"
-	}
-	ret, _, _ := syscall.Syscall(pcapTstampTypeValToNamePtr, 1, uintptr(t), 0, 0)
-	return bytePtrToString(ret)
-}
-
-func pcapTstampTypeNameToVal(s string) (TimestampSource, error) {
-	err := LoadWinPCAP()
-	if err != nil {
-		return 0, err
-	}
-
-	//libpcap <1.2 doesn't have pcap_*_tstamp_* functions
-	if pcapTstampTypeNameToValPtr == 0 {
-		return 0, statusError(pcapCint(pcapError))
-	}
-	cs, err := syscall.BytePtrFromString(s)
-	if err != nil {
-		return 0, err
-	}
-	ret, _, _ := syscall.Syscall(pcapTstampTypeNameToValPtr, 1, uintptr(unsafe.Pointer(cs)), 0, 0)
-	t := pcapCint(ret)
-	if t < 0 {
-		return 0, statusError(pcapCint(t))
-	}
-	return TimestampSource(t), nil
-}
-
-func (p *InactiveHandle) pcapGeterr() error {
-	ret, _, _ := syscall.Syscall(pcapGeterrPtr, 1, uintptr(p.cptr), 0, 0)
-	return errors.New(bytePtrToString(ret))
-}
-
-func (p *InactiveHandle) pcapActivate() (*Handle, activateError) {
-	r, _, _ := syscall.Syscall(pcapActivatePtr, 1, uintptr(p.cptr), 0, 0)
-	ret := activateError(pcapCint(r))
-	if ret != aeNoError {
-		return nil, ret
-	}
-	h := &Handle{
-		cptr: p.cptr,
-	}
-	p.cptr = 0
-	return h, ret
-}
-
-func (p *InactiveHandle) pcapClose() {
-	if p.cptr != 0 {
-		_, _, _ = syscall.Syscall(pcapClosePtr, 1, uintptr(p.cptr), 0, 0)
-	}
-	p.cptr = 0
-}
-
-func pcapCreate(device string) (*InactiveHandle, error) {
-	err := LoadWinPCAP()
-	if err != nil {
-		return nil, err
-	}
-
-	buf := make([]byte, errorBufferSize)
-	dev, err := syscall.BytePtrFromString(device)
-	if err != nil {
-		return nil, err
-	}
-	cptr, _, _ := syscall.Syscall(pcapCreatePtr, 2, uintptr(unsafe.Pointer(dev)), uintptr(unsafe.Pointer(&buf[0])), 0)
-	if cptr == 0 {
-		return nil, errors.New(byteSliceToString(buf))
-	}
-	return &InactiveHandle{cptr: pcapTPtr(cptr)}, nil
-}
-
-func (p *InactiveHandle) pcapSetSnaplen(snaplen int) error {
-	status, _, _ := syscall.Syscall(pcapSetSnaplenPtr, 2, uintptr(p.cptr), uintptr(snaplen), 0)
-	if pcapCint(status) < 0 {
-		return statusError(pcapCint(status))
-	}
-	return nil
-}
-
-func (p *InactiveHandle) pcapSetPromisc(promisc bool) error {
-	var pro uintptr
-	if promisc {
-		pro = 1
-	}
-	status, _, _ := syscall.Syscall(pcapSetPromiscPtr, 2, uintptr(p.cptr), pro, 0)
-	if pcapCint(status) < 0 {
-		return statusError(pcapCint(status))
-	}
-	return nil
-}
-
-func (p *InactiveHandle) pcapSetTimeout(timeout time.Duration) error {
-	status, _, _ := syscall.Syscall(pcapSetTimeoutPtr, 2, uintptr(p.cptr), uintptr(timeoutMillis(timeout)), 0)
-
-	if pcapCint(status) < 0 {
-		return statusError(pcapCint(status))
-	}
-	return nil
-}
-
-func (p *InactiveHandle) pcapListTstampTypes() (out []TimestampSource) {
-	//libpcap <1.2 doesn't have pcap_*_tstamp_* functions
-	if pcapListTstampTypesPtr == 0 {
-		return
-	}
-	var types *pcapCint
-	ret, _, _ := syscall.Syscall(pcapListTstampTypesPtr, 2, uintptr(p.cptr), uintptr(unsafe.Pointer(&types)), 0)
-	n := int(pcapCint(ret))
-	if n < 0 {
-		return // public interface doesn't have error :(
-	}
-	defer syscall.Syscall(pcapFreeTstampTypesPtr, 1, uintptr(unsafe.Pointer(types)), 0, 0)
-	typesArray := (*[1 << 28]pcapCint)(unsafe.Pointer(types))
-	for i := 0; i < n; i++ {
-		out = append(out, TimestampSource((*typesArray)[i]))
-	}
-	return
-}
-
-func (p *InactiveHandle) pcapSetTstampType(t TimestampSource) error {
-	//libpcap <1.2 doesn't have pcap_*_tstamp_* functions
-	if pcapSetTstampTypePtr == 0 {
-		return statusError(pcapError)
-	}
-	status, _, _ := syscall.Syscall(pcapSetTstampTypePtr, 2, uintptr(p.cptr), uintptr(t), 0)
-	if pcapCint(status) < 0 {
-		return statusError(pcapCint(status))
-	}
-	return nil
-}
-
-func (p *InactiveHandle) pcapSetRfmon(monitor bool) error {
-	//winpcap does not support rfmon
-	if pcapCanSetRfmonPtr == 0 {
-		return CannotSetRFMon
-	}
-	var mon uintptr
-	if monitor {
-		mon = 1
-	}
-	canset, _, _ := syscall.Syscall(pcapCanSetRfmonPtr, 1, uintptr(p.cptr), 0, 0)
-	switch canset {
-	case 0:
-		return CannotSetRFMon
-	case 1:
-		// success
-	default:
-		return statusError(pcapCint(canset))
-	}
-	status, _, _ := syscall.Syscall(pcapSetRfmonPtr, 2, uintptr(p.cptr), mon, 0)
-	if status != 0 {
-		return statusError(pcapCint(status))
-	}
-	return nil
-}
-
-func (p *InactiveHandle) pcapSetBufferSize(bufferSize int) error {
-	status, _, _ := syscall.Syscall(pcapSetBufferSizePtr, 2, uintptr(p.cptr), uintptr(bufferSize), 0)
-	if pcapCint(status) < 0 {
-		return statusError(pcapCint(status))
-	}
-	return nil
-}
-
-func (p *InactiveHandle) pcapSetImmediateMode(mode bool) error {
-	//libpcap <1.5 does not have pcap_set_immediate_mode
-	if pcapSetImmediateModePtr == 0 {
-		return statusError(pcapError)
-	}
-	var md uintptr
-	if mode {
-		md = 1
-	}
-	status, _, _ := syscall.Syscall(pcapSetImmediateModePtr, 2, uintptr(p.cptr), md, 0)
-	if pcapCint(status) < 0 {
-		return statusError(pcapCint(status))
-	}
-	return nil
-}
-
-func (p *Handle) setNonBlocking() error {
-	// do nothing
-	return nil
-}
-
-// waitForPacket waits for a packet or for the timeout to expire.
-func (p *Handle) waitForPacket() {
-	// can't use select() so instead just switch goroutines
-	runtime.Gosched()
-}
-
-// openOfflineFile returns contents of input file as a *Handle.
-func openOfflineFile(file *os.File) (handle *Handle, err error) {
-	err = LoadWinPCAP()
-	if err != nil {
-		return nil, err
-	}
-
-	buf := make([]byte, errorBufferSize)
-	cf := file.Fd()
-
-	var cptr uintptr
-	if pcapOpenOfflineWithTstampPrecisionPtr == 0 {
-		cptr, _, _ = syscall.Syscall(pcapHopenOfflinePtr, 2, cf, uintptr(unsafe.Pointer(&buf[0])), 0)
-	} else {
-		cptr, _, _ = syscall.Syscall(pcapHOpenOfflineWithTstampPrecisionPtr, 3, cf, uintptr(pcapTstampPrecisionNano), uintptr(unsafe.Pointer(&buf[0])))
-	}
-
-	if cptr == 0 {
-		return nil, errors.New(byteSliceToString(buf))
-	}
-	return &Handle{cptr: pcapTPtr(cptr)}, nil
-}
diff --git a/vendor/github.com/google/gopacket/pcap/test_dns.pcap b/vendor/github.com/google/gopacket/pcap/test_dns.pcap
deleted file mode 100644
index 3a79f92..0000000
--- a/vendor/github.com/google/gopacket/pcap/test_dns.pcap
+++ /dev/null
Binary files differ
diff --git a/vendor/github.com/google/gopacket/pcap/test_ethernet.pcap b/vendor/github.com/google/gopacket/pcap/test_ethernet.pcap
deleted file mode 100644
index 1d01bd9..0000000
--- a/vendor/github.com/google/gopacket/pcap/test_ethernet.pcap
+++ /dev/null
Binary files differ
diff --git a/vendor/github.com/google/gopacket/pcap/test_loopback.pcap b/vendor/github.com/google/gopacket/pcap/test_loopback.pcap
deleted file mode 100644
index ddeb82c..0000000
--- a/vendor/github.com/google/gopacket/pcap/test_loopback.pcap
+++ /dev/null
Binary files differ
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 5a84d73..545e32f 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -39,7 +39,6 @@
 # github.com/google/gopacket v1.1.17
 github.com/google/gopacket
 github.com/google/gopacket/layers
-github.com/google/gopacket/pcap
 # github.com/google/uuid v1.1.2
 github.com/google/uuid
 # github.com/gorilla/mux v1.7.3