[VOL-3583] Reject unexpected EAPOL packets

Change-Id: I7c164fb2815e2ab573ab3f466a373cb75c61ac86
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)
+		}
+	}
+}