blob: d26f3e9f8a5f2ed8d908366c84752a149bf0a979 [file] [log] [blame]
/*
* Copyright 2018-2024 Open Networking Foundation (ONF) and the ONF Contributors
* 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 eapol
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"
)
// MOCKS
var eapolStateMachine = fsm.NewFSM(
StateAuthStarted,
fsm.Events{
{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{},
)
// params for the function under test
var onuId uint32 = 1
var gemPortId uint32 = 1
var ponPortId uint32 = 0
var uniId uint32 = 0
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
CallCount int
Calls map[int]*openolt.PacketIndication
fail bool
}
func (s *mockStream) Send(ind *openolt.Indication) error {
s.CallCount++
if s.fail {
return errors.New("fake-error")
}
s.Calls[s.CallCount] = ind.GetPktInd()
return nil
}
// TESTS
func TestSendEapStartSuccess(t *testing.T) {
eapolStateMachine.SetState(StateAuthStarted)
stream := &mockStream{
Calls: make(map[int]*openolt.PacketIndication),
fail: false,
}
if err := SendEapStart(onuId, ponPortId, serialNumber, portNo, macAddress, gemPortId, uniId, eapolStateMachine, stream); err != nil {
t.Errorf("SendEapStart returned an error: %v", err)
t.Fail()
}
assert.Equal(t, stream.CallCount, 1)
assert.Equal(t, stream.Calls[1].PortNo, portNo)
assert.Equal(t, stream.Calls[1].IntfId, ponPortId)
assert.Equal(t, stream.Calls[1].IntfType, "pon")
assert.Equal(t, stream.Calls[1].GemportId, uint32(gemPortId))
assert.Equal(t, eapolStateMachine.Current(), StateStartSent)
}
func TestSendEapStartFailStreamError(t *testing.T) {
eapolStateMachine.SetState(StateAuthStarted)
stream := &mockStream{
Calls: make(map[int]*openolt.PacketIndication),
fail: true,
}
err := SendEapStart(onuId, ponPortId, serialNumber, portNo, macAddress, gemPortId, uniId, eapolStateMachine, stream)
if err == nil {
t.Errorf("SendEapStart did not return an error")
t.Fail()
}
assert.Equal(t, err.Error(), "fake-error")
assert.Equal(t, eapolStateMachine.Current(), StateAuthFailed)
}
// TODO test eapol.HandleNextPacket
func TestUpdateAuthFailed(t *testing.T) {
var onuId uint32 = 1
var ponPortId uint32 = 0
var serialNumber string = "BBSM00000001"
eapolStateMachine.SetState(StateAuthStarted)
_ = updateAuthFailed(onuId, ponPortId, serialNumber, eapolStateMachine)
assert.Equal(t, eapolStateMachine.Current(), "auth_failed")
eapolStateMachine.SetState(StateStartSent)
_ = updateAuthFailed(onuId, ponPortId, serialNumber, eapolStateMachine)
assert.Equal(t, eapolStateMachine.Current(), "auth_failed")
eapolStateMachine.SetState(StateResponseIdentitySent)
_ = updateAuthFailed(onuId, ponPortId, serialNumber, eapolStateMachine)
assert.Equal(t, eapolStateMachine.Current(), "auth_failed")
eapolStateMachine.SetState(StateResponseChallengeSent)
_ = updateAuthFailed(onuId, ponPortId, serialNumber, eapolStateMachine)
assert.Equal(t, eapolStateMachine.Current(), "auth_failed")
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(), 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)
}
}
}