Completed the EAPOL State machine
Stopping BBSim in the proper way when OLT-Reboot is received

Change-Id: I142eaa70e329121a5331f1a5706ed864fcf5d993
diff --git a/internal/bbsim/devices/helpers_test.go b/internal/bbsim/devices/helpers_test.go
index 2d01c1a..7b3bf71 100644
--- a/internal/bbsim/devices/helpers_test.go
+++ b/internal/bbsim/devices/helpers_test.go
@@ -19,6 +19,7 @@
 import (
 	"github.com/looplab/fsm"
 	"gotest.tools/assert"
+	"os"
 	"testing"
 )
 
@@ -26,7 +27,7 @@
 	originalNewFSM func(initial string, events []fsm.EventDesc, callbacks map[string]fsm.Callback) *fsm.FSM
 )
 
-func setUp(t *testing.T)  {
+func setUp()  {
 	originalNewFSM = newFSM
 }
 
@@ -35,6 +36,13 @@
 	newFSM = originalNewFSM
 }
 
+func TestMain(m *testing.M) {
+	setUp()
+	code := m.Run()
+	tearDown()
+	os.Exit(code)
+}
+
 func Test_Helpers(t *testing.T) {
 
 	// feedback values for the mock
diff --git a/internal/bbsim/devices/olt.go b/internal/bbsim/devices/olt.go
index 3b50584..66abe14 100644
--- a/internal/bbsim/devices/olt.go
+++ b/internal/bbsim/devices/olt.go
@@ -20,13 +20,15 @@
 	"context"
 	"errors"
 	"fmt"
-	"github.com/opencord/voltha-protos/go/openolt"
+	bbsim "github.com/opencord/bbsim/internal/bbsim/types"
+	"github.com/google/gopacket"
+	"github.com/google/gopacket/layers"
 	"github.com/looplab/fsm"
+	"github.com/opencord/voltha-protos/go/openolt"
 	"github.com/opencord/voltha-protos/go/tech_profile"
 	log "github.com/sirupsen/logrus"
 	"google.golang.org/grpc"
 	"net"
-	"os"
 	"sync"
 )
 
@@ -45,7 +47,7 @@
 	return olt
 }
 
-func CreateOLT(seq int, nni int, pon int, onuPerPon int) OltDevice {
+func CreateOLT(seq int, nni int, pon int, onuPerPon int, oltDoneChannel *chan bool, apiDoneChannel *chan bool, group *sync.WaitGroup) OltDevice {
 	oltLogger.WithFields(log.Fields{
 		"ID": seq,
 		"NumNni":nni,
@@ -64,6 +66,8 @@
 		Pons: []PonPort{},
 		Nnis: []NniPort{},
 		channel: make(chan Message),
+		oltDoneChannel: oltDoneChannel,
+		apiDoneChannel: apiDoneChannel,
 	}
 
 	// OLT State machine
@@ -116,11 +120,9 @@
 		olt.Pons = append(olt.Pons, p)
 	}
 
-	wg := sync.WaitGroup{}
+	newOltServer(olt)
 
-	wg.Add(1)
-	go newOltServer(olt)
-	wg.Wait()
+	group.Done()
 	return olt
 }
 
@@ -134,9 +136,25 @@
 	grpcServer := grpc.NewServer()
 	openolt.RegisterOpenoltServer(grpcServer, o)
 
+	wg := sync.WaitGroup{}
+	wg.Add(1)
+
 	go grpcServer.Serve(lis)
 	oltLogger.Debugf("OLT Listening on: %v", address)
 
+	for {
+		_, ok := <- *o.oltDoneChannel
+		if !ok {
+			// if the olt channel is closed, stop the gRPC server
+			log.Warnf("Stopping OLT gRPC server")
+			grpcServer.Stop()
+			wg.Done()
+			break
+		}
+	}
+
+	wg.Wait()
+
 	return nil
 }
 
@@ -471,14 +489,26 @@
 	return new(openolt.Empty) , nil
 }
 
-func (o OltDevice) OnuPacketOut(context.Context, *openolt.OnuPacket) (*openolt.Empty, error)  {
-	oltLogger.Error("OnuPacketOut not implemented")
+func (o OltDevice) OnuPacketOut(ctx context.Context, onuPkt *openolt.OnuPacket) (*openolt.Empty, error)  {
+	pon, _ := o.getPonById(onuPkt.IntfId)
+	onu, _ := pon.getOnuById(onuPkt.OnuId)
+
+	rawpkt := gopacket.NewPacket(onuPkt.Pkt, layers.LayerTypeEthernet, gopacket.Default)
+
+	// NOTE is this the best way to the to the ethertype?
+	etherType := rawpkt.Layer(layers.LayerTypeEthernet).(*layers.Ethernet).EthernetType
+
+	if etherType == layers.EthernetTypeEAPOL {
+		eapolPkt := bbsim.ByteMsg{IntfId: onuPkt.IntfId, OnuId: onuPkt.OnuId, Bytes: rawpkt.Data()}
+		onu.eapolPktOutCh <- &eapolPkt
+	}
 	return new(openolt.Empty) , nil
 }
 
 func (o OltDevice) Reboot(context.Context, *openolt.Empty) (*openolt.Empty, error)  {
-	oltLogger.Info("Shutting Down, hope you're running in K8s...")
-	os.Exit(0)
+	oltLogger.Info("Shutting Down")
+	close(*o.oltDoneChannel)
+	close(*o.apiDoneChannel)
 	return new(openolt.Empty) , nil
 }
 
diff --git a/internal/bbsim/devices/onu.go b/internal/bbsim/devices/onu.go
index 94e0705..fac7ce1 100644
--- a/internal/bbsim/devices/onu.go
+++ b/internal/bbsim/devices/onu.go
@@ -18,7 +18,7 @@
 
 import (
 	"fmt"
-	"github.com/opencord/bbsim/internal/bbsim/responders"
+	"github.com/opencord/bbsim/internal/bbsim/responders/eapol"
 	"github.com/google/gopacket/layers"
 	"github.com/looplab/fsm"
 	omci "github.com/opencord/omci-sim"
@@ -59,6 +59,11 @@
 				{Name: "receive_eapol_flow", Src: []string{"enabled", "gem_port_added"}, Dst: "eapol_flow_received"},
 				{Name: "add_gem_port", Src: []string{"enabled", "eapol_flow_received"}, Dst: "gem_port_added"},
 				{Name: "start_auth", Src: []string{"eapol_flow_received", "gem_port_added"}, Dst: "auth_started"},
+				{Name: "eap_start_sent", Src: []string{"auth_started"}, Dst: "eap_start_sent"},
+				{Name: "eap_resonse_identity_sent", Src: []string{"eap_start_sent"}, Dst: "eap_resonse_identity_sent"},
+				{Name: "eap_resonse_challenge_sent", Src: []string{"eap_resonse_identity_sent"}, Dst: "eap_resonse_challenge_sent"},
+				{Name: "eap_resonse_success_received", Src: []string{"eap_resonse_challenge_sent"}, Dst: "eap_resonse_success_received"},
+				{Name: "auth_failed", Src: []string{"auth_started", "eap_start_sent", "eap_resonse_identity_sent", "eap_resonse_challenge_sent"}, Dst: "auth_failed"},
 			},
 			fsm.Callbacks{
 				"enter_state": func(e *fsm.Event) {
@@ -105,6 +110,14 @@
 					}(msg)
 
 				},
+				"enter_eap_resonse_success_received": func(e *fsm.Event) {
+					o.logStateChange(e.Src, e.Dst)
+					onuLogger.WithFields(log.Fields{
+						"OnuId": o.ID,
+						"IntfId": o.PonPortID,
+						"OnuSn": o.SerialNumber,
+					}).Warnf("TODO start DHCP request")
+				},
 			},
 		)
 		return o
@@ -147,8 +160,8 @@
 		case StartEAPOL:
 			log.Infof("Receive StartEAPOL message on ONU channel")
 			go func() {
-
-				responders.StartWPASupplicant(o.ID, o.PonPortID, o.SerialNumber, stream, o.eapolPktOutCh)
+				// TODO kill this thread
+				eapol.CreateWPASupplicant(o.ID, o.PonPortID, o.SerialNumber, o.InternalState, stream, o.eapolPktOutCh)
 			}()
 		default:
 			onuLogger.Warnf("Received unknown message data %v for type %v in OLT channel", message.Data, message.Type)
@@ -191,7 +204,7 @@
 
 	sn := new(openolt.SerialNumber)
 
-	sn = new(openolt.SerialNumber)
+	//sn = new(openolt.SerialNumber)
 	sn.VendorId = []byte("BBSM")
 	sn.VendorSpecific = []byte{0, byte(oltid % 256), byte(intfid), byte(onuid)}
 
diff --git a/internal/bbsim/devices/types.go b/internal/bbsim/devices/types.go
index 4c92849..e3439f5 100644
--- a/internal/bbsim/devices/types.go
+++ b/internal/bbsim/devices/types.go
@@ -94,6 +94,8 @@
 	NumOnuPerPon int
 	InternalState *fsm.FSM
 	channel chan Message
+	oltDoneChannel *chan bool
+	apiDoneChannel *chan bool
 
 	Pons []PonPort
 	Nnis []NniPort