[VOL-3210] Added Retry feature in BBSim for EAPOL and DHCP

Change-Id: If0586c804f906998ebc09b7770fd6a749a3a2762
diff --git a/internal/bbsim/devices/onu.go b/internal/bbsim/devices/onu.go
index 6b879cc..78569f5 100644
--- a/internal/bbsim/devices/onu.go
+++ b/internal/bbsim/devices/onu.go
@@ -26,6 +26,7 @@
 
 	"github.com/cboling/omci"
 	"github.com/google/gopacket/layers"
+	backoff "github.com/jpillora/backoff"
 	"github.com/looplab/fsm"
 	"github.com/opencord/bbsim/internal/bbsim/packetHandlers"
 	"github.com/opencord/bbsim/internal/bbsim/responders/dhcp"
@@ -60,7 +61,7 @@
 	InternalState       *fsm.FSM
 	DiscoveryRetryDelay time.Duration // this is the time between subsequent Discovery Indication
 	DiscoveryDelay      time.Duration // this is the time to send the first Discovery Indication
-
+	Backoff             *backoff.Backoff
 	// ONU State
 	// PortNo comes with flows and it's used when sending packetIndications,
 	// There is one PortNo per UNI Port, for now we're only storing the first one
@@ -98,6 +99,13 @@
 }
 
 func CreateONU(olt *OltDevice, pon PonPort, id uint32, sTag int, cTag int, auth bool, dhcp bool, delay time.Duration, isMock bool) *Onu {
+	b := &backoff.Backoff{
+		//These are the defaults
+		Min:    1 * time.Second,
+		Max:    35 * time.Second,
+		Factor: 1.5,
+		Jitter: false,
+	}
 
 	o := Onu{
 		ID:                  0,
@@ -119,9 +127,9 @@
 		DiscoveryRetryDelay: 60 * time.Second, // this is used to send OnuDiscoveryIndications until an activate call is received
 		Flows:               []FlowKey{},
 		DiscoveryDelay:      delay,
+		Backoff:             b,
 	}
 	o.SerialNumber = o.NewSN(olt.ID, pon.ID, id)
-
 	// NOTE this state machine is used to track the operational
 	// state as requested by VOLTHA
 	o.OperState = getOperStateFSM(func(e *fsm.Event) {
@@ -397,12 +405,9 @@
 				msg, _ := message.Data.(OnuFlowUpdateMessage)
 				o.handleFlowUpdate(msg)
 			case StartEAPOL:
-				log.Infof("Receive StartEAPOL message on ONU Channel")
-				eapol.SendEapStart(o.ID, o.PonPortID, o.Sn(), o.PortNo, o.HwAddress, o.InternalState, stream)
+				o.handleEAPOLStart(stream)
 			case StartDHCP:
-				log.Infof("Receive StartDHCP message on ONU Channel")
-				// FIXME use id, ponId as SendEapStart
-				dhcp.SendDHCPDiscovery(o.PonPort.Olt.ID, o.PonPortID, o.ID, o.Sn(), o.PortNo, o.InternalState, o.HwAddress, o.CTag, stream)
+				o.handleDHCPStart(stream)
 			case OnuPacketOut:
 
 				msg, _ := message.Data.(OnuPacketMessage)
@@ -518,6 +523,38 @@
 	}
 }
 
+func (o *Onu) handleEAPOLStart(stream openolt.Openolt_EnableIndicationServer) {
+	log.Infof("Receive StartEAPOL message on ONU Channel")
+	eapol.SendEapStart(o.ID, o.PonPortID, o.Sn(), o.PortNo, o.HwAddress, o.InternalState, stream)
+	go func(delay time.Duration) {
+		time.Sleep(delay)
+		if (o.InternalState.Current() == "eap_start_sent" ||
+			o.InternalState.Current() == "eap_response_identity_sent" ||
+			o.InternalState.Current() == "eap_response_challenge_sent" ||
+			o.InternalState.Current() == "auth_failed") && common.Options.BBSim.AuthRetry {
+			o.InternalState.Event("start_auth")
+		} else if o.InternalState.Current() == "eap_response_success_received" {
+			o.Backoff.Reset()
+		}
+	}(o.Backoff.Duration())
+}
+
+func (o *Onu) handleDHCPStart(stream openolt.Openolt_EnableIndicationServer) {
+	log.Infof("Receive StartDHCP message on ONU Channel")
+	// FIXME use id, ponId as SendEapStart
+	dhcp.SendDHCPDiscovery(o.PonPort.Olt.ID, o.PonPortID, o.ID, o.Sn(), o.PortNo, o.InternalState, o.HwAddress, o.CTag, stream)
+	go func(delay time.Duration) {
+		time.Sleep(delay)
+		if (o.InternalState.Current() == "dhcp_discovery_sent" ||
+			o.InternalState.Current() == "dhcp_request_sent" ||
+			o.InternalState.Current() == "dhcp_failed") && common.Options.BBSim.DhcpRetry {
+			o.InternalState.Event("start_dhcp")
+		} else if o.InternalState.Current() == "dhcp_ack_received" {
+			o.Backoff.Reset()
+		}
+	}(o.Backoff.Duration())
+}
+
 func (o Onu) NewSN(oltid int, intfid uint32, onuid uint32) *openolt.SerialNumber {
 
 	sn := new(openolt.SerialNumber)