[VOL-3583] Reject unexpected EAPOL packets

Change-Id: I7c164fb2815e2ab573ab3f466a373cb75c61ac86
diff --git a/internal/bbsim/devices/onu_state_machine_test.go b/internal/bbsim/devices/onu_state_machine_test.go
index ab32dd0..c1f6d8e 100644
--- a/internal/bbsim/devices/onu_state_machine_test.go
+++ b/internal/bbsim/devices/onu_state_machine_test.go
@@ -17,9 +17,11 @@
 package devices
 
 import (
+	"testing"
+
+	"github.com/opencord/bbsim/internal/bbsim/responders/eapol"
 	omcilib "github.com/opencord/bbsim/internal/common/omci"
 	me "github.com/opencord/omci-lib-go/v2/generated"
-	"testing"
 
 	"gotest.tools/assert"
 )
@@ -121,7 +123,7 @@
 	assert.Equal(t, onu.InternalState.Current(), OnuStateEnabled)
 
 	// fail as no EapolFlow has been received
-	err := onu.InternalState.Event("start_auth")
+	err := onu.InternalState.Event(eapol.EventStartAuth)
 	if err == nil {
 		t.Fatal("can't start EAPOL without EapolFlow")
 	}
@@ -137,7 +139,7 @@
 	assert.Equal(t, onu.InternalState.Current(), OnuStateEnabled)
 
 	// fail has no GemPort has been set
-	err := onu.InternalState.Event("start_auth")
+	err := onu.InternalState.Event(eapol.EventStartAuth)
 	if err == nil {
 		t.Fatal("can't start EAPOL without GemPort")
 	}
@@ -154,33 +156,33 @@
 	assert.Equal(t, onu.InternalState.Current(), OnuStateEnabled)
 
 	// succeed
-	_ = onu.InternalState.Event("start_auth")
-	assert.Equal(t, onu.InternalState.Current(), "auth_started")
+	_ = onu.InternalState.Event(eapol.EventStartAuth)
+	assert.Equal(t, onu.InternalState.Current(), eapol.StateAuthStarted)
 }
 
 func Test_Onu_StateMachine_eapol_states(t *testing.T) {
 	t.Skip("Needs to be moved in the Service struct")
 	onu := createTestOnu()
 
-	onu.InternalState.SetState("auth_started")
+	onu.InternalState.SetState(eapol.StateAuthStarted)
 
-	assert.Equal(t, onu.InternalState.Current(), "auth_started")
-	_ = onu.InternalState.Event("eap_start_sent")
-	assert.Equal(t, onu.InternalState.Current(), "eap_start_sent")
-	_ = onu.InternalState.Event("eap_response_identity_sent")
-	assert.Equal(t, onu.InternalState.Current(), "eap_response_identity_sent")
-	_ = onu.InternalState.Event("eap_response_challenge_sent")
-	assert.Equal(t, onu.InternalState.Current(), "eap_response_challenge_sent")
-	_ = onu.InternalState.Event("eap_response_success_received")
-	assert.Equal(t, onu.InternalState.Current(), "eap_response_success_received")
+	assert.Equal(t, onu.InternalState.Current(), eapol.StateAuthStarted)
+	_ = onu.InternalState.Event(eapol.EventStartSent)
+	assert.Equal(t, onu.InternalState.Current(), eapol.StateStartSent)
+	_ = onu.InternalState.Event(eapol.EventResponseIdentitySent)
+	assert.Equal(t, onu.InternalState.Current(), eapol.StateResponseIdentitySent)
+	_ = onu.InternalState.Event(eapol.EventResponseChallengeSent)
+	assert.Equal(t, onu.InternalState.Current(), eapol.StateResponseChallengeSent)
+	_ = onu.InternalState.Event(eapol.EventResponseSuccessReceived)
+	assert.Equal(t, onu.InternalState.Current(), eapol.StateResponseSuccessReceived)
 
 	// test that we can retrigger EAPOL
-	states := []string{"eap_start_sent", "eap_response_identity_sent", "eap_response_challenge_sent", "eap_response_success_received", "auth_failed", "dhcp_ack_received", "dhcp_failed"}
+	states := []string{eapol.StateStartSent, eapol.StateResponseIdentitySent, eapol.StateResponseChallengeSent, eapol.StateResponseSuccessReceived, eapol.StateAuthFailed, "dhcp_ack_received", "dhcp_failed"}
 	for _, state := range states {
 		onu.InternalState.SetState(state)
-		err := onu.InternalState.Event("start_auth")
+		err := onu.InternalState.Event(eapol.EventStartAuth)
 		assert.Equal(t, err, nil)
-		assert.Equal(t, onu.InternalState.Current(), "auth_started")
+		assert.Equal(t, onu.InternalState.Current(), eapol.StateAuthStarted)
 	}
 }
 
@@ -205,14 +207,14 @@
 	t.Skip("Needs to be moved in the Service struct")
 	onu := createTestOnu()
 
-	onu.InternalState.SetState("eap_response_success_received")
-	assert.Equal(t, onu.InternalState.Current(), "eap_response_success_received")
+	onu.InternalState.SetState(eapol.StateResponseSuccessReceived)
+	assert.Equal(t, onu.InternalState.Current(), eapol.StateResponseSuccessReceived)
 
 	err := onu.InternalState.Event("start_dhcp")
 	if err == nil {
 		t.Fail()
 	}
-	assert.Equal(t, onu.InternalState.Current(), "eap_response_success_received")
+	assert.Equal(t, onu.InternalState.Current(), eapol.StateResponseSuccessReceived)
 	assert.Equal(t, err.Error(), "transition canceled with error: cannot-go-to-dhcp-started-as-dhcp-flow-is-missing")
 }
 
@@ -221,14 +223,14 @@
 	t.Skip("Needs to be moved in the Service struct")
 	onu := createTestOnu()
 
-	onu.InternalState.SetState("eap_response_success_received")
-	assert.Equal(t, onu.InternalState.Current(), "eap_response_success_received")
+	onu.InternalState.SetState(eapol.StateResponseSuccessReceived)
+	assert.Equal(t, onu.InternalState.Current(), eapol.StateResponseSuccessReceived)
 
 	err := onu.InternalState.Event("start_dhcp")
 	if err == nil {
 		t.Fail()
 	}
-	assert.Equal(t, onu.InternalState.Current(), "eap_response_success_received")
+	assert.Equal(t, onu.InternalState.Current(), eapol.StateResponseSuccessReceived)
 	assert.Equal(t, err.Error(), "transition canceled with error: cannot-go-to-dhcp-started-as-gemport-is-missing")
 }
 
@@ -236,8 +238,8 @@
 	t.Skip("Needs to be moved in the Service struct")
 	onu := createTestOnu()
 
-	onu.InternalState.SetState("eap_response_success_received")
-	assert.Equal(t, onu.InternalState.Current(), "eap_response_success_received")
+	onu.InternalState.SetState(eapol.StateResponseSuccessReceived)
+	assert.Equal(t, onu.InternalState.Current(), eapol.StateResponseSuccessReceived)
 
 	// default transition
 	_ = onu.InternalState.Event("start_dhcp")
@@ -259,7 +261,7 @@
 	assert.Equal(t, onu.InternalState.Current(), "dhcp_ack_received")
 
 	// test that we can retrigger DHCP
-	states := []string{"eap_response_success_received", "dhcp_discovery_sent", "dhcp_request_sent", "dhcp_ack_received", "dhcp_failed"}
+	states := []string{eapol.StateResponseSuccessReceived, "dhcp_discovery_sent", "dhcp_request_sent", "dhcp_ack_received", "dhcp_failed"}
 	for _, state := range states {
 		onu.InternalState.SetState(state)
 		err := onu.InternalState.Event("start_dhcp")
diff --git a/internal/bbsim/devices/service_test.go b/internal/bbsim/devices/service_test.go
index 3285021..12ea230 100644
--- a/internal/bbsim/devices/service_test.go
+++ b/internal/bbsim/devices/service_test.go
@@ -18,13 +18,15 @@
 
 import (
 	"context"
+	"net"
+	"testing"
+	"time"
+
+	"github.com/opencord/bbsim/internal/bbsim/responders/eapol"
 	"github.com/opencord/bbsim/internal/bbsim/types"
 	"github.com/opencord/bbsim/internal/common"
 	"github.com/opencord/voltha-protos/v5/go/openolt"
 	"github.com/stretchr/testify/assert"
-	"net"
-	"testing"
-	"time"
 )
 
 type mockService struct {
@@ -80,12 +82,12 @@
 	assert.NotNil(t, s.Channel)
 
 	// set EAPOL and DHCP states to something else
-	s.EapolState.SetState("eap_response_success_received")
+	s.EapolState.SetState(eapol.StateResponseSuccessReceived)
 	s.DHCPState.SetState("dhcp_ack_received")
 
 	s.Disable()
 	// make sure the EAPOL and DHCP states have been reset after disable
-	assert.Equal(t, "created", s.EapolState.Current())
+	assert.Equal(t, eapol.StateCreated, s.EapolState.Current())
 	assert.Equal(t, "created", s.DHCPState.Current())
 
 	// make sure the channel have been closed
@@ -112,7 +114,7 @@
 	assert.Equal(t, stream.CallCount, 0)
 
 	// state should not change
-	assert.Equal(t, s.EapolState.Current(), "created")
+	assert.Equal(t, s.EapolState.Current(), eapol.StateCreated)
 }
 
 // make sure that if the service does need EAPOL we're sending any packet
@@ -133,7 +135,7 @@
 	assert.Equal(t, stream.CallCount, 1)
 
 	// state should not change
-	assert.Equal(t, s.EapolState.Current(), "eap_start_sent")
+	assert.Equal(t, s.EapolState.Current(), eapol.StateStartSent)
 }
 
 // make sure that if the service does not need DHCP we're not sending any packet
@@ -259,16 +261,16 @@
 	s.Initialize(stream)
 
 	// set to failed if timeout occurs
-	_ = s.EapolState.Event("start_auth")
+	_ = s.EapolState.Event(eapol.EventStartAuth)
 	time.Sleep(1 * time.Second)
-	assert.Equal(t, "auth_failed", s.EapolState.Current())
+	assert.Equal(t, eapol.StateAuthFailed, s.EapolState.Current())
 
 	// do not set to failed if succeeded
-	s.EapolState.SetState("created")
-	_ = s.EapolState.Event("start_auth")
-	s.EapolState.SetState("eap_response_success_received")
+	s.EapolState.SetState(eapol.StateCreated)
+	_ = s.EapolState.Event(eapol.EventStartAuth)
+	s.EapolState.SetState(eapol.StateResponseSuccessReceived)
 	time.Sleep(1 * time.Second)
-	assert.Equal(t, "eap_response_success_received", s.EapolState.Current())
+	assert.Equal(t, eapol.StateResponseSuccessReceived, s.EapolState.Current())
 
 }
 
@@ -291,11 +293,11 @@
 	s.Initialize(stream)
 
 	// set to failed if timeout occurs
-	_ = s.EapolState.Event("start_auth")
+	_ = s.EapolState.Event(eapol.EventStartAuth)
 
 	// after a second EAPOL should have failed and restarted
 	time.Sleep(1 * time.Second)
-	assert.Equal(t, "eap_start_sent", s.EapolState.Current())
+	assert.Equal(t, eapol.StateStartSent, s.EapolState.Current())
 }
 
 // Test that if the DHCP state machine doesn't complete in 30 seconds we
diff --git a/internal/bbsim/devices/services.go b/internal/bbsim/devices/services.go
index 4b94ecf..3546e91 100644
--- a/internal/bbsim/devices/services.go
+++ b/internal/bbsim/devices/services.go
@@ -19,6 +19,9 @@
 import (
 	"encoding/hex"
 	"fmt"
+	"net"
+	"time"
+
 	"github.com/looplab/fsm"
 	"github.com/opencord/bbsim/internal/bbsim/packetHandlers"
 	"github.com/opencord/bbsim/internal/bbsim/responders/dhcp"
@@ -27,8 +30,6 @@
 	bbsimTypes "github.com/opencord/bbsim/internal/bbsim/types"
 	"github.com/opencord/bbsim/internal/common"
 	log "github.com/sirupsen/logrus"
-	"net"
-	"time"
 )
 
 var serviceLogger = log.WithFields(log.Fields{
@@ -138,7 +139,7 @@
 			},
 			fmt.Sprintf("enter_%s", ServiceStateDisabled): func(e *fsm.Event) {
 				// reset the state machines
-				service.EapolState.SetState("created")
+				service.EapolState.SetState(eapol.StateCreated)
 				service.DHCPState.SetState("created")
 
 				// stop listening for packets
@@ -152,26 +153,26 @@
 	)
 
 	service.EapolState = fsm.NewFSM(
-		"created",
+		eapol.StateCreated,
 		fsm.Events{
-			{Name: "start_auth", Src: []string{"created", "eap_response_success_received", "auth_failed"}, Dst: "auth_started"},
-			{Name: "eap_start_sent", Src: []string{"auth_started"}, Dst: "eap_start_sent"},
-			{Name: "eap_response_identity_sent", Src: []string{"eap_start_sent"}, Dst: "eap_response_identity_sent"},
-			{Name: "eap_response_challenge_sent", Src: []string{"eap_response_identity_sent"}, Dst: "eap_response_challenge_sent"},
-			{Name: "eap_response_success_received", Src: []string{"eap_response_challenge_sent"}, Dst: "eap_response_success_received"},
-			{Name: "auth_failed", Src: []string{"auth_started", "eap_start_sent", "eap_response_identity_sent", "eap_response_challenge_sent"}, Dst: "auth_failed"},
+			{Name: eapol.EventStartAuth, Src: []string{eapol.StateCreated, eapol.StateResponseSuccessReceived, eapol.StateAuthFailed}, Dst: eapol.StateAuthStarted},
+			{Name: eapol.EventStartSent, Src: []string{eapol.StateAuthStarted}, Dst: eapol.StateStartSent},
+			{Name: eapol.EventResponseIdentitySent, Src: []string{eapol.StateStartSent}, Dst: eapol.StateResponseIdentitySent},
+			{Name: eapol.EventResponseChallengeSent, Src: []string{eapol.StateResponseIdentitySent}, Dst: eapol.StateResponseChallengeSent},
+			{Name: eapol.EventResponseSuccessReceived, Src: []string{eapol.StateResponseChallengeSent}, Dst: eapol.StateResponseSuccessReceived},
+			{Name: eapol.EventAuthFailed, Src: []string{eapol.StateAuthStarted, eapol.StateStartSent, eapol.StateResponseIdentitySent, eapol.StateResponseChallengeSent}, Dst: eapol.StateAuthFailed},
 		},
 		fsm.Callbacks{
 			"enter_state": func(e *fsm.Event) {
 				service.logStateChange("EapolState", e.Src, e.Dst)
 			},
-			"before_start_auth": func(e *fsm.Event) {
+			fmt.Sprintf("before_%s", eapol.EventStartAuth): func(e *fsm.Event) {
 				msg := bbsimTypes.Message{
 					Type: bbsimTypes.StartEAPOL,
 				}
 				service.Channel <- msg
 			},
-			"enter_auth_started": func(e *fsm.Event) {
+			fmt.Sprintf("enter_%s", eapol.StateAuthStarted): func(e *fsm.Event) {
 				go func() {
 
 					for {
@@ -180,7 +181,7 @@
 							// if the OLT is disabled, then cancel
 							return
 						case <-time.After(eapolWaitTime):
-							if service.EapolState.Current() != "eap_response_success_received" {
+							if service.EapolState.Current() != eapol.StateResponseSuccessReceived {
 								serviceLogger.WithFields(log.Fields{
 									"OnuId":      service.UniPort.Onu.ID,
 									"IntfId":     service.UniPort.Onu.PonPortID,
@@ -191,9 +192,9 @@
 									"EapolState": service.EapolState.Current(),
 								}).Warn("EAPOL failed, resetting EAPOL State")
 
-								_ = service.EapolState.Event("auth_failed")
+								_ = service.EapolState.Event(eapol.EventAuthFailed)
 								if common.Config.BBSim.AuthRetry {
-									_ = service.EapolState.Event("start_auth")
+									_ = service.EapolState.Event(eapol.EventStartAuth)
 								}
 
 								return
@@ -325,7 +326,7 @@
 		return
 	}
 
-	if err := s.EapolState.Event("start_auth"); err != nil {
+	if err := s.EapolState.Event(eapol.EventStartAuth); err != nil {
 		serviceLogger.WithFields(log.Fields{
 			"OnuId":  s.UniPort.Onu.ID,
 			"IntfId": s.UniPort.Onu.PonPortID,
@@ -467,7 +468,7 @@
 					"Name":      s.Name,
 					"err":       err,
 				}).Error("Error while sending EapolStart packet")
-				_ = s.EapolState.Event("auth_failed")
+				_ = s.EapolState.Event(eapol.EventAuthFailed)
 			}
 		case bbsimTypes.StartDHCP:
 			if err := s.handleDHCPStart(s.Stream); err != nil {
diff --git a/internal/bbsim/responders/eapol/eapol.go b/internal/bbsim/responders/eapol/eapol.go
index e341cef..afaee68 100644
--- a/internal/bbsim/responders/eapol/eapol.go
+++ b/internal/bbsim/responders/eapol/eapol.go
@@ -36,6 +36,24 @@
 
 var eapolVersion uint8 = 1
 
+// constants for the EAPOL state machine states and events
+const (
+	StateCreated                 = "created"
+	StateAuthStarted             = "auth_started"
+	StateStartSent               = "eap_start_sent"
+	StateResponseIdentitySent    = "eap_response_identity_sent"
+	StateResponseChallengeSent   = "eap_response_challenge_sent"
+	StateResponseSuccessReceived = "eap_response_success_received"
+	StateAuthFailed              = "auth_failed"
+
+	EventStartAuth               = "start_auth"
+	EventStartSent               = "eap_start_sent"
+	EventResponseIdentitySent    = "eap_response_identity_sent"
+	EventResponseChallengeSent   = "eap_response_challenge_sent"
+	EventResponseSuccessReceived = "eap_response_success_received"
+	EventAuthFailed              = "auth_failed"
+)
+
 func sendEapolPktIn(msg bbsim.ByteMsg, portNo uint32, gemid uint32, stream bbsim.Stream) error {
 	// FIXME unify sendDHCPPktIn and sendEapolPktIn methods
 
@@ -181,7 +199,7 @@
 }
 
 func updateAuthFailed(onuId uint32, ponPortId uint32, serialNumber string, onuStateMachine *fsm.FSM) error {
-	if err := onuStateMachine.Event("auth_failed"); err != nil {
+	if err := onuStateMachine.Event(EventAuthFailed); err != nil {
 		eapolLogger.WithFields(log.Fields{
 			"OnuId":  onuId,
 			"IntfId": ponPortId,
@@ -253,7 +271,7 @@
 		"GemPortId": gemPort,
 	}).Debug("Sent EapStart packet")
 
-	if err := stateMachine.Event("eap_start_sent"); err != nil {
+	if err := stateMachine.Event(EventStartSent); err != nil {
 		eapolLogger.WithFields(log.Fields{
 			"OnuId":     onuId,
 			"IntfId":    ponPortId,
@@ -327,6 +345,21 @@
 		}).Infof("Sent EAPIdentityRequest packet")
 		return
 	} else if eap.Code == layers.EAPCodeRequest && eap.Type == layers.EAPTypeIdentity {
+		if state := stateMachine.Current(); state != StateStartSent {
+			log.WithFields(log.Fields{
+				"OnuId":  onuId,
+				"IntfId": ponPortId,
+				"OnuSn":  serialNumber,
+				"PortNo": portNo,
+				"UniId":  uniId,
+			}).Errorf("Received EAPIdentityRequest packet while in state %q, dropped", state)
+
+			if state := stateMachine.Current(); state != StateAuthFailed && state != StateResponseSuccessReceived {
+				_ = updateAuthFailed(onuId, ponPortId, serialNumber, stateMachine)
+			}
+			return
+		}
+
 		reseap := createEAPIdentityResponse(eap.Id)
 		pkt := createEAPOLPkt(reseap, serviceId, uniId, onuId, ponPortId, oltId)
 
@@ -337,7 +370,7 @@
 		}
 
 		if err := sendEapolPktIn(msg, portNo, gemPortId, stream); err != nil {
-			_ = stateMachine.Event("auth_failed")
+			_ = updateAuthFailed(onuId, ponPortId, serialNumber, stateMachine)
 			return
 		}
 		eapolLogger.WithFields(log.Fields{
@@ -347,7 +380,7 @@
 			"PortNo": portNo,
 			"UniId":  uniId,
 		}).Debugf("Sent EAPIdentityResponse packet")
-		if err := stateMachine.Event("eap_response_identity_sent"); err != nil {
+		if err := stateMachine.Event(EventResponseIdentitySent); err != nil {
 			eapolLogger.WithFields(log.Fields{
 				"OnuId":  onuId,
 				"IntfId": ponPortId,
@@ -381,6 +414,21 @@
 		}).Infof("Sent EAPChallengeRequest packet")
 		return
 	} else if eap.Code == layers.EAPCodeRequest && eap.Type == layers.EAPTypeOTP {
+		if state := stateMachine.Current(); state != StateResponseIdentitySent {
+			log.WithFields(log.Fields{
+				"OnuId":  onuId,
+				"IntfId": ponPortId,
+				"OnuSn":  serialNumber,
+				"PortNo": portNo,
+				"UniId":  uniId,
+			}).Errorf("Received EAPChallengeRequest packet while in state %q, dropped", state)
+
+			if state := stateMachine.Current(); state != StateAuthFailed && state != StateResponseSuccessReceived {
+				_ = updateAuthFailed(onuId, ponPortId, serialNumber, stateMachine)
+			}
+			return
+		}
+
 		senddata := getMD5Data(eap)
 		senddata = append([]byte{0x10}, senddata...)
 		sendeap := createEAPChallengeResponse(eap.Id, senddata)
@@ -393,7 +441,7 @@
 		}
 
 		if err := sendEapolPktIn(msg, portNo, gemPortId, stream); err != nil {
-			_ = stateMachine.Event("auth_failed")
+			_ = updateAuthFailed(onuId, ponPortId, serialNumber, stateMachine)
 			return
 		}
 		eapolLogger.WithFields(log.Fields{
@@ -403,7 +451,7 @@
 			"PortNo": portNo,
 			"UniId":  uniId,
 		}).Debugf("Sent EAPChallengeResponse packet")
-		if err := stateMachine.Event("eap_response_challenge_sent"); err != nil {
+		if err := stateMachine.Event(EventResponseChallengeSent); err != nil {
 			eapolLogger.WithFields(log.Fields{
 				"OnuId":  onuId,
 				"IntfId": ponPortId,
@@ -442,6 +490,21 @@
 			}).Errorf("Error while transitioning ONU State %v", err)
 		}
 	} else if eap.Code == layers.EAPCodeSuccess && eap.Type == layers.EAPTypeNone {
+		if state := stateMachine.Current(); state != StateResponseChallengeSent {
+			log.WithFields(log.Fields{
+				"OnuId":  onuId,
+				"IntfId": ponPortId,
+				"OnuSn":  serialNumber,
+				"PortNo": portNo,
+				"UniId":  uniId,
+			}).Errorf("Received EAP Success packet while in state %q, dropped", state)
+
+			if state := stateMachine.Current(); state != StateAuthFailed && state != StateResponseSuccessReceived {
+				_ = updateAuthFailed(onuId, ponPortId, serialNumber, stateMachine)
+			}
+			return
+		}
+
 		eapolLogger.WithFields(log.Fields{
 			"OnuId":  onuId,
 			"IntfId": ponPortId,
@@ -449,7 +512,7 @@
 			"PortNo": portNo,
 			"UniId":  uniId,
 		}).Debugf("Received EAPSuccess packet")
-		if err := stateMachine.Event("eap_response_success_received"); err != nil {
+		if err := stateMachine.Event(EventResponseSuccessReceived); err != nil {
 			eapolLogger.WithFields(log.Fields{
 				"OnuId":  onuId,
 				"IntfId": ponPortId,
diff --git a/internal/bbsim/responders/eapol/eapol_test.go b/internal/bbsim/responders/eapol/eapol_test.go
index 21ca86b..d2f861d 100644
--- a/internal/bbsim/responders/eapol/eapol_test.go
+++ b/internal/bbsim/responders/eapol/eapol_test.go
@@ -18,10 +18,14 @@
 
 import (
 	"errors"
+	"fmt"
 	"net"
 	"testing"
 
+	"github.com/google/gopacket"
+	"github.com/google/gopacket/layers"
 	"github.com/looplab/fsm"
+	"github.com/opencord/bbsim/internal/bbsim/types"
 	"github.com/opencord/voltha-protos/v5/go/openolt"
 	"google.golang.org/grpc"
 	"gotest.tools/assert"
@@ -30,13 +34,13 @@
 // MOCKS
 
 var eapolStateMachine = fsm.NewFSM(
-	"auth_started",
+	StateAuthStarted,
 	fsm.Events{
-		{Name: "eap_start_sent", Src: []string{"auth_started"}, Dst: "eap_start_sent"},
-		{Name: "eap_response_identity_sent", Src: []string{"eap_start_sent"}, Dst: "eap_response_identity_sent"},
-		{Name: "eap_response_challenge_sent", Src: []string{"eap_response_identity_sent"}, Dst: "eap_response_challenge_sent"},
-		{Name: "eap_response_success_received", Src: []string{"eap_response_challenge_sent"}, Dst: "eap_response_success_received"},
-		{Name: "auth_failed", Src: []string{"auth_started", "eap_start_sent", "eap_response_identity_sent", "eap_response_challenge_sent"}, Dst: "auth_failed"},
+		{Name: EventStartSent, Src: []string{StateAuthStarted}, Dst: StateStartSent},
+		{Name: EventResponseIdentitySent, Src: []string{StateStartSent}, Dst: StateResponseIdentitySent},
+		{Name: EventResponseChallengeSent, Src: []string{StateResponseIdentitySent}, Dst: StateResponseChallengeSent},
+		{Name: EventResponseSuccessReceived, Src: []string{StateResponseChallengeSent}, Dst: StateResponseSuccessReceived},
+		{Name: EventAuthFailed, Src: []string{StateAuthStarted, StateStartSent, StateResponseIdentitySent, StateResponseChallengeSent}, Dst: StateAuthFailed},
 	},
 	fsm.Callbacks{},
 )
@@ -49,6 +53,8 @@
 var serialNumber string = "BBSM00000001"
 var macAddress = net.HardwareAddr{0x01, 0x80, 0xC2, 0x00, 0x00, 0x03}
 var portNo uint32 = 16
+var serviceId uint32 = 0
+var oltId int = 0
 
 type mockStream struct {
 	grpc.ServerStream
@@ -69,7 +75,7 @@
 // TESTS
 
 func TestSendEapStartSuccess(t *testing.T) {
-	eapolStateMachine.SetState("auth_started")
+	eapolStateMachine.SetState(StateAuthStarted)
 
 	stream := &mockStream{
 		Calls: make(map[int]*openolt.PacketIndication),
@@ -87,13 +93,13 @@
 	assert.Equal(t, stream.Calls[1].IntfType, "pon")
 	assert.Equal(t, stream.Calls[1].GemportId, uint32(gemPortId))
 
-	assert.Equal(t, eapolStateMachine.Current(), "eap_start_sent")
+	assert.Equal(t, eapolStateMachine.Current(), StateStartSent)
 
 }
 
 func TestSendEapStartFailStreamError(t *testing.T) {
 
-	eapolStateMachine.SetState("auth_started")
+	eapolStateMachine.SetState(StateAuthStarted)
 
 	stream := &mockStream{
 		Calls: make(map[int]*openolt.PacketIndication),
@@ -108,7 +114,7 @@
 
 	assert.Equal(t, err.Error(), "fake-error")
 
-	assert.Equal(t, eapolStateMachine.Current(), "auth_failed")
+	assert.Equal(t, eapolStateMachine.Current(), StateAuthFailed)
 }
 
 // TODO test eapol.HandleNextPacket
@@ -119,28 +125,84 @@
 	var ponPortId uint32 = 0
 	var serialNumber string = "BBSM00000001"
 
-	eapolStateMachine.SetState("auth_started")
+	eapolStateMachine.SetState(StateAuthStarted)
 	_ = updateAuthFailed(onuId, ponPortId, serialNumber, eapolStateMachine)
 	assert.Equal(t, eapolStateMachine.Current(), "auth_failed")
 
-	eapolStateMachine.SetState("eap_start_sent")
+	eapolStateMachine.SetState(StateStartSent)
 	_ = updateAuthFailed(onuId, ponPortId, serialNumber, eapolStateMachine)
 	assert.Equal(t, eapolStateMachine.Current(), "auth_failed")
 
-	eapolStateMachine.SetState("eap_response_identity_sent")
+	eapolStateMachine.SetState(StateResponseIdentitySent)
 	_ = updateAuthFailed(onuId, ponPortId, serialNumber, eapolStateMachine)
 	assert.Equal(t, eapolStateMachine.Current(), "auth_failed")
 
-	eapolStateMachine.SetState("eap_response_challenge_sent")
+	eapolStateMachine.SetState(StateResponseChallengeSent)
 	_ = updateAuthFailed(onuId, ponPortId, serialNumber, eapolStateMachine)
 	assert.Equal(t, eapolStateMachine.Current(), "auth_failed")
 
-	eapolStateMachine.SetState("eap_response_success_received")
+	eapolStateMachine.SetState(StateResponseSuccessReceived)
 	err := updateAuthFailed(onuId, ponPortId, serialNumber, eapolStateMachine)
 	if err == nil {
 		t.Errorf("updateAuthFailed did not return an error")
 		t.Fail()
 	}
-	assert.Equal(t, err.Error(), "event auth_failed inappropriate in current state eap_response_success_received")
+	assert.Equal(t, err.Error(), fmt.Sprintf("event %s inappropriate in current state %s", EventAuthFailed, StateResponseSuccessReceived))
 
 }
+
+func createTestEAPOLPkt(eap *layers.EAP) gopacket.Packet {
+	bytes := createEAPOLPkt(eap, serviceId, uniId, onuId, ponPortId, oltId)
+	return gopacket.NewPacket(bytes, layers.LayerTypeEthernet, gopacket.Default)
+}
+
+func handleTestEAPOLPkt(pkt gopacket.Packet, stream types.Stream) {
+	HandleNextPacket(onuId, ponPortId, gemPortId, serialNumber, portNo, uniId, serviceId, oltId, eapolStateMachine, pkt, stream, nil)
+}
+
+func TestDropUnexpectedPackets(t *testing.T) {
+	stream := &mockStream{
+		Calls: make(map[int]*openolt.PacketIndication),
+	}
+
+	const eapId uint8 = 1
+
+	//Create test packets
+	identityRequest := createEAPIdentityRequest(eapId)
+	challangeRequest := createEAPChallengeRequest(eapId, []byte{0x10})
+	success := createEAPSuccess(eapId)
+
+	identityPkt := createTestEAPOLPkt(identityRequest)
+	challangePkt := createTestEAPOLPkt(challangeRequest)
+	successPkt := createTestEAPOLPkt(success)
+
+	testStates := map[string]struct {
+		packets          []gopacket.Packet
+		destinationState string
+	}{
+		//All packet should be dropped in state auth_started
+		StateAuthStarted: {[]gopacket.Packet{identityPkt, challangePkt, successPkt}, StateAuthFailed},
+		//Only the identity request packet should be handled in state eap_start_sent
+		StateStartSent: {[]gopacket.Packet{challangePkt, successPkt}, StateAuthFailed},
+		//Only the challange request packet should be handled in state eap_response_identity_sent
+		StateResponseIdentitySent: {[]gopacket.Packet{identityPkt, successPkt}, StateAuthFailed},
+		//Only the success packet should be handled in state eap_response_challenge_sent
+		StateResponseChallengeSent: {[]gopacket.Packet{identityPkt, challangePkt}, StateAuthFailed},
+		//All packet should be dropped in state eap_response_success_received
+		StateResponseSuccessReceived: {[]gopacket.Packet{identityPkt, challangePkt, successPkt}, StateResponseSuccessReceived},
+		//All packet should be dropped in state auth_failed
+		StateAuthFailed: {[]gopacket.Packet{identityPkt, challangePkt}, StateAuthFailed},
+	}
+
+	for s, info := range testStates {
+		for _, p := range info.packets {
+			eapolStateMachine.SetState(s)
+			handleTestEAPOLPkt(p, stream)
+
+			//No response should be sent
+			assert.Equal(t, stream.CallCount, 0)
+			//The state machine should transition to the failed state
+			assert.Equal(t, eapolStateMachine.Current(), info.destinationState)
+		}
+	}
+}