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/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
 }