- listening for Flows and updating ONU state machine
- Sending the EAP_START packet
- Moving Eapol in an external responder

Change-Id: I94fbbbb391467f44c71be8f2181cd41df7bd92f5
diff --git a/README.md b/README.md
index 039b5d5..63e37cd 100644
--- a/README.md
+++ b/README.md
@@ -49,6 +49,15 @@
 enable
 ```
 
+#### VOLTHA 2.X
+
+_This assumes `voltctl` is installed an configured_
+
+```
+voltctl device create -t openolt -H $(kubectl get -n voltha service/bbsim -o go-template='{{.spec.clusterIP}}'):50060
+voltctl device enable $(voltctl device list --filter Type~openolt -q)
+```
+
 ## Control API
 
 BBSim comes with a gRPC interface to control the internal state.
@@ -79,6 +88,38 @@
     }
   ]
 }
+
+$ grpcurl -plaintext 127.0.0.1:50070 bbsim.BBSim/GetONUs
+{
+  "items": [
+    {
+      "ID": 1,
+      "SerialNumber": "vendor_id:\"BBSM\" vendor_specific:\"\\000\\000\\000\\001\" ",
+      "OperState": "up",
+      "InternalState": "auth_started"
+    },
+    {
+      "ID": 2,
+      "SerialNumber": "vendor_id:\"BBSM\" vendor_specific:\"\\000\\000\\000\\002\" ",
+      "OperState": "up",
+      "InternalState": "auth_started"
+    },
+    {
+      "ID": 1,
+      "SerialNumber": "vendor_id:\"BBSM\" vendor_specific:\"\\000\\000\\001\\001\" ",
+      "OperState": "up",
+      "InternalState": "auth_started",
+      "PonPortID": 1
+    },
+    {
+      "ID": 2,
+      "SerialNumber": "vendor_id:\"BBSM\" vendor_specific:\"\\000\\000\\001\\002\" ",
+      "OperState": "up",
+      "InternalState": "auth_started",
+      "PonPortID": 1
+    }
+  ]
+}
 ```
 
 ## Development
diff --git a/examples/sadis-minimal.json b/examples/sadis-minimal.json
index 10adc68..a37c3fe 100644
--- a/examples/sadis-minimal.json
+++ b/examples/sadis-minimal.json
@@ -11,7 +11,7 @@
       "entries": [
         {
           "id": "BBSM00000001",
-          "cTag": 83,
+          "cTag": 101,
           "sTag": 99,
           "nasPortId": "BBSM00000001",
           "technologyProfileId": 64,
@@ -19,6 +19,33 @@
           "downstreamBandwidthProfile": "User1-Specific"
         },
         {
+          "id": "BBSM00000002",
+          "cTag": 102,
+          "sTag": 99,
+          "nasPortId": "BBSM00000002",
+          "technologyProfileId": 64,
+          "upstreamBandwidthProfile": "High-Speed-Internet",
+          "downstreamBandwidthProfile": "User1-Specific"
+        },
+        {
+          "id": "BBSM00000101",
+          "cTag": 111,
+          "sTag": 99,
+          "nasPortId": "BBSM00000101",
+          "technologyProfileId": 64,
+          "upstreamBandwidthProfile": "High-Speed-Internet",
+          "downstreamBandwidthProfile": "User1-Specific"
+        },
+        {
+          "id": "BBSM00000102",
+          "cTag": 112,
+          "sTag": 99,
+          "nasPortId": "BBSM00000102",
+          "technologyProfileId": 64,
+          "upstreamBandwidthProfile": "High-Speed-Internet",
+          "downstreamBandwidthProfile": "User1-Specific"
+        },
+        {
           "id": "BBSIM_OLT_0",
           "hardwareIdentifier": "00:1b:22:00:b1:78",
           "ipAddress": "192.168.1.252",
@@ -38,27 +65,25 @@
       "entries": [
         {
           "id": "High-Speed-Internet",
-          "cir": 200000000,
-          "cbs": 348000,
-          "eir": 10000000,
-          "ebs": 348000,
-          "air": 10000000
-        },
-        {
+          "cir": 600,
+          "cbs": 2000,
+          "eir": 5000,
+          "ebs": 2000,
+          "air": 100000
+        }, {
           "id": "User1-Specific",
-          "cir": 300000000,
-          "cbs": 348000,
-          "eir": 20000000,
-          "ebs": 348000,
-          "air": 30000000
-        },
-        {
+          "cir": 600,
+          "cbs": 3000,
+          "eir": 3000,
+          "ebs": 4000,
+          "air": 100000
+        }, {
           "id": "Default",
-          "cir": 300000000,
-          "cbs": 348000,
-          "eir": 20000000,
-          "ebs": 348000,
-          "air": 30000000
+          "cir": 600,
+          "cbs": 30,
+          "eir": 400,
+          "ebs": 30,
+          "air": 100000
         }
       ]
     }
diff --git a/go.mod b/go.mod
index bfea739..ffee23a 100644
--- a/go.mod
+++ b/go.mod
@@ -4,6 +4,7 @@
 
 require (
 	github.com/golang/protobuf v1.3.2
+	github.com/google/gopacket v1.1.17
 	github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024 // indirect
 	github.com/looplab/fsm v0.1.0
 	github.com/opencord/omci-sim v0.0.0-20190826212842-203314beba7e
diff --git a/go.sum b/go.sum
index 25e3e31..0cfff06 100644
--- a/go.sum
+++ b/go.sum
@@ -14,6 +14,8 @@
 github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
 github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
 github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024 h1:rBMNdlhTLzJjJSDIjNEXX1Pz3Hmwmz91v+zycvx9PJc=
+github.com/google/gopacket v1.1.17 h1:rMrlX2ZY2UbvT+sdz3+6J+pp2z+msCq9MxTU6ymxbBY=
+github.com/google/gopacket v1.1.17/go.mod h1:UdDNZ1OO62aGYVnPhxT1U6aI7ukYtA/kB8vaU0diBUM=
 github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
 github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
 github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
@@ -44,9 +46,12 @@
 golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
 golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628=
 golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 h1:0GoQqolDA55aaLxZyTzK/Y2ePZzZTUrRacwib7cNsYQ=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190405154228-4b34438f7a67/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc=
 golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
diff --git a/internal/bbsim/bbsim.go b/internal/bbsim/bbsim.go
index deb7f40..268be8e 100644
--- a/internal/bbsim/bbsim.go
+++ b/internal/bbsim/bbsim.go
@@ -62,8 +62,8 @@
 }
 
 func init() {
-	//log.SetLevel(log.DebugLevel)
-	log.SetLevel(log.TraceLevel)
+	log.SetLevel(log.DebugLevel)
+	//log.SetLevel(log.TraceLevel)
 	//log.SetReportCaller(true)
 }
 
diff --git a/internal/bbsim/devices/olt.go b/internal/bbsim/devices/olt.go
index 7ace1c0..3b50584 100644
--- a/internal/bbsim/devices/olt.go
+++ b/internal/bbsim/devices/olt.go
@@ -92,7 +92,7 @@
 	olt.Nnis = append(olt.Nnis, nniPort)
 
 	// create PON ports
-	onuId := 1
+	//onuId := 1
 	for i := 0; i < pon; i++ {
 		p := PonPort{
 			NumOnu: olt.NumOnuPerPon,
@@ -107,9 +107,10 @@
 
 		// create ONU devices
 		for j := 0; j < onuPerPon; j++ {
-			o := CreateONU(olt, p, uint32(onuId))
+			//o := CreateONU(olt, p, uint32(onuId))
+			o := CreateONU(olt, p, uint32(j + 1))
 			p.Onus = append(p.Onus, o)
-			onuId = onuId + 1
+			//onuId = onuId + 1
 		}
 
 		olt.Pons = append(olt.Pons, p)
@@ -185,6 +186,7 @@
 
 		for _, onu := range pon.Onus {
 			go onu.processOnuMessages(stream)
+			go onu.processOmciMessages(stream)
 			msg := Message{
 				Type:      OnuDiscIndication,
 				Data: OnuDiscIndicationMessage{
@@ -381,9 +383,39 @@
 	return new(openolt.Empty) , nil
 }
 
-func (o OltDevice) FlowAdd(context.Context, *openolt.Flow) (*openolt.Empty, error)  {
-	oltLogger.Info("received FlowAdd")
-	// TODO store flows somewhere
+func (o OltDevice) FlowAdd(ctx context.Context, flow *openolt.Flow) (*openolt.Empty, error)  {
+	oltLogger.WithFields(log.Fields{
+		"IntfId": flow.AccessIntfId,
+		"OnuId": flow.OnuId,
+		"EthType": fmt.Sprintf("%x", flow.Classifier.EthType),
+		"InnerVlan": flow.Classifier.IVid,
+		"OuterVlan": flow.Classifier.OVid,
+		"FlowType": flow.FlowType,
+		"FlowId": flow.FlowId,
+		"UniID": flow.UniId,
+		"PortNo": flow.PortNo,
+	}).Infof("OLT receives Flow")
+	// TODO optionally store flows somewhere
+
+	if flow.AccessIntfId == -1 {
+		oltLogger.WithFields(log.Fields{
+			"FlowId": flow.FlowId,
+		}).Debugf("This is an OLT flow")
+	} else {
+		pon, _ := o.getPonById(uint32(flow.AccessIntfId))
+		onu, _ := pon.getOnuById(uint32(flow.OnuId))
+
+		msg := Message{
+			Type:      FlowUpdate,
+			Data:      OnuFlowUpdateMessage{
+				PonPortID:  pon.ID,
+				OnuID: 	onu.ID,
+				Flow: 	flow,
+			},
+		}
+		onu.channel <- msg
+	}
+
 	return new(openolt.Empty) , nil
 }
 
diff --git a/internal/bbsim/devices/onu.go b/internal/bbsim/devices/onu.go
index 172ead4..94e0705 100644
--- a/internal/bbsim/devices/onu.go
+++ b/internal/bbsim/devices/onu.go
@@ -17,10 +17,14 @@
 package devices
 
 import (
-	"github.com/opencord/voltha-protos/go/openolt"
+	"fmt"
+	"github.com/opencord/bbsim/internal/bbsim/responders"
+	"github.com/google/gopacket/layers"
 	"github.com/looplab/fsm"
 	omci "github.com/opencord/omci-sim"
+	"github.com/opencord/voltha-protos/go/openolt"
 	log "github.com/sirupsen/logrus"
+	bbsim "github.com/opencord/bbsim/internal/bbsim/types"
 )
 
 var onuLogger = log.WithFields(log.Fields{
@@ -32,7 +36,9 @@
 			ID: id,
 			PonPortID: pon.ID,
 			PonPort: pon,
+			// NOTE can we combine everything in a single channel?
 			channel: make(chan Message),
+			eapolPktOutCh: make(chan *bbsim.ByteMsg, 1024),
 		}
 		o.SerialNumber = o.NewSN(olt.ID, pon.ID, o.ID)
 
@@ -50,19 +56,68 @@
 			fsm.Events{
 				{Name: "discover", Src: []string{"created"}, Dst: "discovered"},
 				{Name: "enable", Src: []string{"discovered"}, Dst: "enabled"},
-				{Name: "start_omci", Src: []string{"enabled"}, Dst: "starting_openomci"},
+				{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"},
 			},
 			fsm.Callbacks{
 				"enter_state": func(e *fsm.Event) {
-					onuLogger.WithFields(log.Fields{
-						"ID": o.ID,
-					}).Debugf("Changing ONU InternalState from %s to %s", e.Src, e.Dst)
+					o.logStateChange(e.Src, e.Dst)
+				},
+				"enter_eapol_flow_received": func(e *fsm.Event) {
+					o.logStateChange(e.Src, e.Dst)
+					if e.Src == "enter_gem_port_added" {
+						if err := o.InternalState.Event("start_auth"); err != nil {
+							log.Infof("Transitioning to StartAuth")
+							onuLogger.WithFields(log.Fields{
+								"OnuId":  o.ID,
+								"IntfId": o.PonPortID,
+								"OnuSn":  o.SerialNumber,
+							}).Errorf("Error while transitioning ONU State")
+						}
+					}
+				},
+				"enter_gem_port_added": func(e *fsm.Event) {
+					o.logStateChange(e.Src, e.Dst)
+					if e.Src == "eapol_flow_received" {
+						log.Infof("Transitioning to StartAuth")
+						if err := o.InternalState.Event("start_auth"); err != nil {
+							onuLogger.WithFields(log.Fields{
+								"OnuId": o.ID,
+								"IntfId": o.PonPortID,
+								"OnuSn": o.SerialNumber,
+							}).Errorf("Error while transitioning ONU State")
+						}
+					}
+				},
+				"enter_auth_started": func(e *fsm.Event) {
+					o.logStateChange(e.Src, e.Dst)
+					msg := Message{
+						Type:      StartEAPOL,
+						Data: EapStartMessage{
+							PonPortID: o.PonPortID,
+							OnuID: o.ID,
+						},
+					}
+					go func(msg Message){
+						// you can only send a value on an unbuffered channel without blocking
+						o.channel <- msg
+					}(msg)
+
 				},
 			},
 		)
 		return o
 }
 
+func (o Onu) logStateChange(src string, dst string) {
+	onuLogger.WithFields(log.Fields{
+		"OnuId": o.ID,
+		"IntfId": o.PonPortID,
+		"OnuSn": o.SerialNumber,
+	}).Debugf("Changing ONU InternalState from %s to %s", src, dst)
+}
+
 func (o Onu) processOnuMessages(stream openolt.Openolt_EnableIndicationServer)  {
 	onuLogger.WithFields(log.Fields{
 		"onuID": o.ID,
@@ -74,7 +129,7 @@
 			"onuID": o.ID,
 			"onuSN": o.SerialNumber,
 			"messageType": message.Type,
-		}).Trace("Received message")
+		}).Tracef("Received message on ONU Channel")
 
 		switch message.Type {
 		case OnuDiscIndication:
@@ -85,14 +140,53 @@
 			o.sendOnuIndication(msg, stream)
 		case OMCI:
 			msg, _ := message.Data.(OmciMessage)
-			o.InternalState.Event("start_omci")
 			o.handleOmciMessage(msg, stream)
+		case FlowUpdate:
+			msg, _ := message.Data.(OnuFlowUpdateMessage)
+			o.handleFlowUpdate(msg, stream)
+		case StartEAPOL:
+			log.Infof("Receive StartEAPOL message on ONU channel")
+			go func() {
+
+				responders.StartWPASupplicant(o.ID, o.PonPortID, o.SerialNumber, stream, o.eapolPktOutCh)
+			}()
 		default:
 			onuLogger.Warnf("Received unknown message data %v for type %v in OLT channel", message.Data, message.Type)
 		}
 	}
 }
 
+func (o Onu) processOmciMessages(stream openolt.Openolt_EnableIndicationServer)  {
+	ch := omci.GetChannel()
+
+	onuLogger.WithFields(log.Fields{
+		"onuID": o.ID,
+		"onuSN": o.SerialNumber,
+	}).Debug("Started OMCI Indication Channel")
+
+	for message := range ch {
+		switch message.Type {
+		case omci.GemPortAdded:
+			log.WithFields(log.Fields{
+				"OnuId": message.Data.OnuId,
+				"IntfId": message.Data.IntfId,
+			}).Infof("GemPort Added")
+
+			// NOTE if we receive the GemPort but we don't have EAPOL flows
+			// go an intermediate state, otherwise start auth
+			if o.InternalState.Is("enabled") {
+				if err := o.InternalState.Event("add_gem_port"); err != nil {
+					log.Errorf("Can't go to gem_port_added: %v", err)
+				}
+			} else if  o.InternalState.Is("eapol_flow_received"){
+				if err := o.InternalState.Event("start_auth"); err != nil {
+					log.Errorf("Can't go to auth_started: %v", err)
+				}
+			}
+		}
+	}
+}
+
 func (o Onu) NewSN(oltid int, intfid uint32, onuid uint32) *openolt.SerialNumber {
 
 	sn := new(openolt.SerialNumber)
@@ -116,6 +210,7 @@
 	onuLogger.WithFields(log.Fields{
 		"IntfId": msg.Onu.PonPortID,
 		"SerialNumber": msg.Onu.SerialNumber,
+		"OnuId": o.ID,
 	}).Debug("Sent Indication_OnuDiscInd")
 }
 
@@ -175,6 +270,33 @@
 	}).Tracef("Sent OMCI message")
 }
 
+func (o Onu) handleFlowUpdate(msg OnuFlowUpdateMessage, stream openolt.Openolt_EnableIndicationServer) {
+	onuLogger.WithFields(log.Fields{
+		"IntfId": msg.Flow.AccessIntfId,
+		"OnuId": msg.Flow.OnuId,
+		"EthType": fmt.Sprintf("%x", msg.Flow.Classifier.EthType),
+		"InnerVlan": msg.Flow.Classifier.IVid,
+		"OuterVlan": msg.Flow.Classifier.OVid,
+		"FlowType": msg.Flow.FlowType,
+		"FlowId": msg.Flow.FlowId,
+		"UniID": msg.Flow.UniId,
+		"PortNo": msg.Flow.PortNo,
+	}).Infof("ONU receives Flow")
+	if msg.Flow.Classifier.EthType == uint32(layers.EthernetTypeEAPOL) && msg.Flow.Classifier.OVid == 4091 {
+		// NOTE if we receive the EAPOL flows but we don't have GemPorts
+		// go an intermediate state, otherwise start auth
+		if o.InternalState.Is("enabled") {
+			if err := o.InternalState.Event("receive_eapol_flow"); err != nil {
+				log.Errorf("Can't go to eapol_flow_received: %v", err)
+			}
+		} else if  o.InternalState.Is("gem_port_added"){
+			if err := o.InternalState.Event("start_auth"); err != nil {
+				log.Errorf("Can't go to auth_started: %v", err)
+			}
+		}
+	}
+}
+
 // HexDecode converts the hex encoding to binary
 func HexDecode(pkt []byte) []byte {
 	p := make([]byte, len(pkt)/2)
diff --git a/internal/bbsim/devices/types.go b/internal/bbsim/devices/types.go
index 068ad66..4c92849 100644
--- a/internal/bbsim/devices/types.go
+++ b/internal/bbsim/devices/types.go
@@ -22,8 +22,14 @@
 	"fmt"
 	"github.com/opencord/voltha-protos/go/openolt"
 	"github.com/looplab/fsm"
+	bbsim "github.com/opencord/bbsim/internal/bbsim/types"
 )
 
+// TODO get rid of this file
+// - move ONU and OLT struct in their respective file
+// - create files for PonPorts and NniPorts
+// - move messages in the `types` package
+
 // Devices
 type Onu struct {
 	ID uint32
@@ -35,6 +41,7 @@
 	SerialNumber *openolt.SerialNumber
 
 	channel chan Message
+	eapolPktOutCh chan *bbsim.ByteMsg
 }
 
 
@@ -96,6 +103,7 @@
 }
 
 // BBSim Internals
+
 type MessageType int
 
 const (
@@ -105,6 +113,8 @@
 	OnuDiscIndication MessageType = 3
 	OnuIndication     MessageType = 4
 	OMCI              MessageType = 5
+	FlowUpdate		  MessageType = 6
+	StartEAPOL		  MessageType = 7
 )
 
 func (m MessageType) String() string {
@@ -115,6 +125,8 @@
 		"OnuDiscIndication",
 		"OnuIndication",
 		"OMCI",
+		"FlowUpdate",
+		"StartEAPOL",
 	}
 	return names[m]
 }
@@ -156,6 +168,17 @@
 	omciMsg   *openolt.OmciMsg
 }
 
+type OnuFlowUpdateMessage struct {
+	PonPortID uint32
+	OnuID     uint32
+	Flow      *openolt.Flow
+}
+
+type EapStartMessage struct {
+	PonPortID uint32
+	OnuID     uint32
+}
+
 
 type OperState int
 
diff --git a/internal/bbsim/responders/eapol.go b/internal/bbsim/responders/eapol.go
new file mode 100644
index 0000000..4e7cd34
--- /dev/null
+++ b/internal/bbsim/responders/eapol.go
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+
+ * 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 responders
+
+import (
+	bbsim "github.com/opencord/bbsim/internal/bbsim/types"
+	"github.com/google/gopacket"
+	"github.com/google/gopacket/layers"
+	omci "github.com/opencord/omci-sim"
+	"github.com/opencord/voltha-protos/go/openolt"
+	log "github.com/sirupsen/logrus"
+	"net"
+)
+
+var eapolLogger = log.WithFields(log.Fields{
+	"module": "EAPOL",
+})
+
+func StartWPASupplicant(onuId uint32, ponPortId uint32, serialNumber *openolt.SerialNumber, stream openolt.Openolt_EnableIndicationServer, pktOutCh chan *bbsim.ByteMsg)  {
+	// NOTE pckOutCh is channel to listen on for packets received by VOLTHA
+	// the ONU device will publish messages on that channel
+
+	eapolLogger.WithFields(log.Fields{
+		"OnuId": onuId,
+		"IntfId": ponPortId,
+		"OnuSn": serialNumber,
+	}).Infof("EAPOL State Machine starting")
+
+	// send the packet (hacked together)
+	gemid, err := omci.GetGemPortId(ponPortId, onuId)
+	if err != nil {
+		eapolLogger.WithFields(log.Fields{
+			"OnuId": onuId,
+			"IntfId": ponPortId,
+			"OnuSn": serialNumber,
+		}).Errorf("Can't retrieve GemPortId: %s", err)
+		return
+	}
+
+	buffer := gopacket.NewSerializeBuffer()
+	options := gopacket.SerializeOptions{}
+
+	ethernetLayer := &layers.Ethernet{
+		SrcMAC:       net.HardwareAddr{0x2e, 0x60, 0x70, 0x13, 0x07, byte(onuId)},
+		DstMAC:       net.HardwareAddr{0x01, 0x80, 0xC2, 0x00, 0x00, 0x03},
+		EthernetType: layers.EthernetTypeEAPOL,
+	}
+
+	gopacket.SerializeLayers(buffer, options,
+		ethernetLayer,
+		&layers.EAPOL{Version: 1, Type: 1, Length: 0},
+	)
+
+	msg := buffer.Bytes()
+
+	data := &openolt.Indication_PktInd{
+		PktInd: &openolt.PacketIndication{
+			IntfType: "pon",
+			IntfId: ponPortId,
+			GemportId: uint32(gemid),
+			Pkt: msg,
+		},
+	}
+	// end of hacked (move in an EAPOL state machine)
+	if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
+		eapolLogger.Error("Fail to send EAPOL PktInd indication. %v", err)
+	}
+}
\ No newline at end of file
diff --git a/internal/bbsim/types.go b/internal/bbsim/types.go
index e429bf4..6a6ce76 100644
--- a/internal/bbsim/types.go
+++ b/internal/bbsim/types.go
@@ -23,6 +23,4 @@
 	NumNniPerOlt int
 	NumPonPerOlt int
 	NumOnuPerPon int
-}
-
-
+}
\ No newline at end of file
diff --git a/internal/bbsim/types/types.go b/internal/bbsim/types/types.go
new file mode 100644
index 0000000..3245add
--- /dev/null
+++ b/internal/bbsim/types/types.go
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+
+ * 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 types
+
+type ByteMsg struct {
+	IntfId uint32
+	OnuId  uint32
+	Byte   []byte
+}
\ No newline at end of file