VOL-1430, SEBA-436 Add EAPOL responder
Change-Id: I9b01271373099a843ada51fdf0a8639abaf8667e
diff --git a/core/core_server.go b/core/core_server.go
index 3e2a075..f6d0dbb 100644
--- a/core/core_server.go
+++ b/core/core_server.go
@@ -63,6 +63,8 @@
stateRepCh chan stateReport
omciIn chan openolt.OmciIndication
omciOut chan openolt.OmciMsg
+ eapolIn chan *EAPByte
+ eapolOut chan *EAPPkt
}
type Packet struct {
@@ -70,6 +72,18 @@
Pkt gopacket.Packet
}
+type EAPByte struct {
+ IntfId uint32
+ OnuId uint32
+ Byte []byte
+}
+
+type EAPPkt struct {
+ IntfId uint32
+ OnuId uint32
+ Pkt gopacket.Packet
+}
+
type stateReport struct {
device device.Device
current device.DeviceState
@@ -94,6 +108,8 @@
stateRepCh: make(chan stateReport, 8),
omciIn: make(chan openolt.OmciIndication, 1024),
omciOut: make(chan openolt.OmciMsg, 1024),
+ eapolIn: make(chan *EAPByte, 1024),
+ eapolOut: make(chan *EAPPkt, 1024),
}
nnni := s.Olt.NumNniIntf
@@ -338,16 +354,19 @@
logger.Debug("runPacketPktLoops Start")
defer logger.Debug("runPacketLoops Done")
- errch := make(chan error)
- RunOmciResponder(ctx, s.omciOut, s.omciIn, s.Onumap, errch)
+ errchOmci := make(chan error)
+ RunOmciResponder(ctx, s.omciOut, s.omciIn, errchOmci)
eg, child := errgroup.WithContext(ctx)
child, cancel := context.WithCancel(child)
+ errchEapol := make(chan error)
+ RunEapolResponder(ctx, s.eapolOut, s.eapolIn, errchEapol)
+
eg.Go(func() error {
logger.Debug("runOMCIResponder Start")
defer logger.Debug("runOMCIResponder Done")
select {
- case v, ok := <-errch: // Wait for OmciInitialization
+ case v, ok := <-errchOmci: // Wait for OmciInitialization
if ok { //Error
logger.Error("Error happend in Omci:%s", v)
return v
@@ -361,6 +380,21 @@
})
eg.Go(func() error {
+ logger.Debug("runEapolResponder Start")
+ defer logger.Debug("runEapolResponder Done")
+ select {
+ case v, ok := <-errchEapol:
+ if ok { //Error
+ logger.Error("Error happend in Eapol:%s", v)
+ return v
+ }
+ case <-child.Done():
+ return nil
+ }
+ return nil
+ })
+
+ eg.Go(func() error {
err := s.runMainPktLoop(child, stream)
return err
})
@@ -412,6 +446,22 @@
logger.Error("send omci indication failed.", err)
continue
}
+ case msg := <- s.eapolIn:
+ intfid := msg.IntfId
+ onuid := msg.OnuId
+ gemid, err := getGemPortID(intfid, onuid)
+ if err != nil {
+ logger.Error("Failed to getGemPortID intfid:%d onuid:%d", intfid, onuid)
+ continue
+ }
+
+ logger.Debug("OLT %d send eapol packet out (upstream), IF %v (ONU-ID: %v) pkt:%x.", s.Olt.ID, intfid, onuid)
+
+ data = &openolt.Indication_PktInd{PktInd: &openolt.PacketIndication{IntfType: "pon", IntfId: intfid, GemportId: gemid, Pkt: msg.Byte}}
+ if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
+ logger.Error("Fail to send EAPOL PktInd indication.", err)
+ return err
+ }
case unipkt := <-unichannel:
onuid := unipkt.Info.onuid
onu, _ := s.GetOnuByID(onuid)
@@ -506,6 +556,9 @@
ethtype := pkt.EthernetType
if ethtype == layers.EthernetTypeEAPOL {
utils.LoggerWithOnu(onu).Info("Received downstream packet is EAPOL.")
+ eapolPkt := EAPPkt{IntfId:intfid, OnuId:onuid, Pkt: rawpkt}
+ s.eapolOut <- &eapolPkt
+ return nil
} else if layerDHCP := rawpkt.Layer(layers.LayerTypeDHCPv4); layerDHCP != nil {
utils.LoggerWithOnu(onu).WithFields(log.Fields{
"payload": layerDHCP.LayerPayload(),
diff --git a/core/eapol.go b/core/eapol.go
new file mode 100644
index 0000000..e40da47
--- /dev/null
+++ b/core/eapol.go
@@ -0,0 +1,257 @@
+/*
+ * 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 core
+
+import (
+ "context"
+ "gerrit.opencord.org/voltha-bbsim/common/logger"
+ "net"
+ "errors"
+ "encoding/hex"
+ "github.com/google/gopacket"
+ "github.com/google/gopacket/layers"
+ "crypto/md5"
+ "sync"
+)
+
+type eapState int
+const (
+ START eapState = iota //TODO: This state definition should support 802.1X
+ RESPID
+ RESPCHA
+ SUCCESS
+)
+
+
+
+type responder struct {
+ peers map [key] *peerInstance
+ eapolIn chan *EAPByte
+}
+
+type peerInstance struct{
+ key key
+ srcaddr *net.HardwareAddr
+ version uint8
+ curId uint8
+ curState eapState
+}
+
+type key struct {
+ intfid uint32
+ onuid uint32
+}
+
+var resp *responder
+var once sync.Once
+func getResponder () *responder {
+ once.Do(func(){
+ resp = &responder{peers: make(map[key] *peerInstance), eapolIn: nil}
+ })
+ return resp
+}
+
+func RunEapolResponder(ctx context.Context, eapolOut chan *EAPPkt, eapolIn chan *EAPByte, errch chan error) {
+ responder := getResponder()
+ responder.eapolIn = eapolIn
+ peers := responder.peers
+
+ go func() {
+ logger.Debug("EAPOL response process starts")
+ defer logger.Debug("EAPOL response process was done")
+ for {
+ select {
+ case msg := <- eapolOut:
+ logger.Debug("Received eapol from eapolOut")
+ intfid := msg.IntfId
+ onuid := msg.OnuId
+
+ if peer, ok := peers[key{intfid: intfid, onuid:onuid}]; ok {
+ logger.Debug("Key hit intfid:%d onuid: %d", intfid, onuid)
+ curstate := peer.curState
+ nextstate, err := peer.transitState(curstate, eapolIn, msg.Pkt)
+ if err != nil {
+ logger.Error("Failed to transitState: %s", err)
+ }
+ peer.curState = nextstate
+ } else {
+ logger.Error("Failed to find eapol peer instance intfid:%d onuid:%d", intfid, onuid)
+ }
+ case <-ctx.Done():
+ return
+ }
+ }
+ }()
+}
+
+func startPeer (intfid uint32, onuid uint32) error {
+ peer := peerInstance{key: key{intfid: intfid, onuid: onuid},
+ srcaddr: &net.HardwareAddr{0x2e, 0x60, 0x70, 0x13, 0x07, byte(onuid)},
+ version: 1,
+ curId: 0,
+ curState: START}
+
+ eap := peer.createEAPStart()
+ bytes := peer.createEAPOL(eap)
+ resp := getResponder()
+ eapolIn := resp.eapolIn
+ if err := peer.sendPkt(bytes, eapolIn); err != nil {
+ return errors.New("Failed to send EAPStart")
+ }
+ logger.Debug("Sending EAPStart")
+ logger.Debug(hex.Dump(bytes))
+ //peers[key{intfid: intfid, onuid: onuid}] = &peer
+ resp.peers[key{intfid: intfid, onuid: onuid}] = &peer
+ return nil
+}
+
+func (p *peerInstance)transitState(cur eapState, omciIn chan *EAPByte, recvpkt gopacket.Packet) (next eapState, err error) {
+ logger.Debug("currentState:%d", cur)
+ eap, err := extractEAP(recvpkt)
+ if err != nil {
+ return cur, nil
+ }
+ if eap.Code == layers.EAPCodeRequest && eap.Type == layers.EAPTypeIdentity {
+ logger.Debug("Received EAP-Request/Identity")
+ logger.Debug(recvpkt.Dump())
+ p.curId = eap.Id
+ if cur == START {
+ reseap := p.createEAPResID()
+ pkt := p.createEAPOL(reseap)
+ logger.Debug("Sending EAP-Response/Identity")
+ if err != p.sendPkt(pkt, omciIn) {
+ return cur, err
+ }
+ return RESPID, nil
+ }
+ } else if eap.Code == layers.EAPCodeRequest && eap.Type == layers.EAPTypeOTP {
+ logger.Debug("Received EAP-Request/Challenge")
+ logger.Debug(recvpkt.Dump())
+ if cur == RESPID {
+ p.curId = eap.Id
+ resdata := getMD5Res (p.curId, eap)
+ resdata = append([]byte{0x10}, resdata ...)
+ reseap := p.createEAPResCha(resdata)
+ pkt := p.createEAPOL(reseap)
+ logger.Debug("Sending EAP-Response/Challenge")
+ if err != p.sendPkt(pkt, omciIn) {
+ return cur, err
+ }
+ return RESPCHA, nil
+ }
+ } else if eap.Code == layers.EAPCodeSuccess && eap.Type == layers.EAPTypeNone {
+ logger.Debug("Received EAP-Success")
+ logger.Debug(recvpkt.Dump())
+ if cur == RESPCHA {
+ return SUCCESS, nil
+ }
+ } else {
+ logger.Debug("Received unsupported EAP")
+ return cur, nil
+ }
+ logger.Debug("State transition does not support..current state:%d", cur)
+ logger.Debug(recvpkt.Dump())
+ return cur, nil
+}
+
+func (p *peerInstance) createEAPOL (eap *layers.EAP) []byte {
+ buffer := gopacket.NewSerializeBuffer()
+ options := gopacket.SerializeOptions{}
+
+ ethernetLayer := &layers.Ethernet{
+ SrcMAC: *p.srcaddr,
+ DstMAC: net.HardwareAddr{0x01, 0x80, 0xC2, 0x00, 0x00, 0x03},
+ EthernetType: layers.EthernetTypeEAPOL,
+ }
+
+ if eap == nil { // EAP Start
+ gopacket.SerializeLayers(buffer, options,
+ ethernetLayer,
+ &layers.EAPOL{Version: p.version, Type:1, Length: 0},
+ )
+ } else {
+ gopacket.SerializeLayers(buffer, options,
+ ethernetLayer,
+ &layers.EAPOL{Version: p.version, Type:0, Length: eap.Length},
+ eap,
+ )
+ }
+ bytes := buffer.Bytes()
+ return bytes
+}
+
+func (p *peerInstance) createEAPStart () *layers.EAP {
+ return nil
+}
+
+func (p *peerInstance) createEAPResID () *layers.EAP {
+ eap := layers.EAP{Code: layers.EAPCodeResponse,
+ Id: p.curId,
+ Length: 9,
+ Type: layers.EAPTypeIdentity,
+ TypeData: []byte{0x75, 0x73, 0x65, 0x72 }}
+ return &eap
+}
+
+func (p *peerInstance) createEAPResCha (payload []byte) *layers.EAP {
+ eap := layers.EAP{Code: layers.EAPCodeResponse,
+ Id: p.curId, Length: 22,
+ Type: layers.EAPTypeOTP,
+ TypeData: payload}
+ return &eap
+}
+
+func (p *peerInstance) sendPkt (pkt []byte, omciIn chan *EAPByte) error {
+ // Send our packet
+ msg := EAPByte{IntfId: p.key.intfid,
+ OnuId: p.key.onuid,
+ Byte: pkt}
+ omciIn <- &msg
+ logger.Debug("sendPkt intfid:%d onuid:%d", p.key.intfid, p.key.onuid)
+ logger.Debug(hex.Dump(msg.Byte))
+ return nil
+}
+
+func getMD5Res (id uint8, eap *layers.EAP) []byte {
+ i := byte(id)
+ C := []byte(eap.BaseLayer.Contents)[6:]
+ P := []byte{i, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64} //"password"
+ data := md5.Sum(append(P, C ...))
+ ret := make([]byte, 16)
+ for j := 0; j < 16; j ++ {
+ ret[j] = data[j]
+ }
+ return ret
+}
+
+func extractEAPOL (pkt gopacket.Packet) (*layers.EAPOL, error) {
+ layerEAPOL := pkt.Layer(layers.LayerTypeEAPOL)
+ eapol, _ := layerEAPOL.(*layers.EAPOL)
+ if eapol == nil {
+ return nil, errors.New("Cannot extract EAPOL")
+ }
+ return eapol, nil
+}
+
+func extractEAP (pkt gopacket.Packet) (*layers.EAP, error) {
+ layerEAP := pkt.Layer(layers.LayerTypeEAP)
+ eap, _ := layerEAP.(*layers.EAP)
+ if eap == nil {
+ return nil, errors.New("Cannot extract EAP")
+ }
+ return eap, nil
+}
\ No newline at end of file
diff --git a/core/omci.go b/core/omci.go
index 1d1a78c..433cb57 100644
--- a/core/omci.go
+++ b/core/omci.go
@@ -20,12 +20,11 @@
"context"
"gerrit.opencord.org/voltha-bbsim/common/logger"
- "gerrit.opencord.org/voltha-bbsim/device"
"gerrit.opencord.org/voltha-bbsim/protos"
omci "github.com/opencord/omci-sim"
)
-func RunOmciResponder(ctx context.Context, omciOut chan openolt.OmciMsg, omciIn chan openolt.OmciIndication, onumap map[uint32][]*device.Onu, errch chan error) {
+func RunOmciResponder(ctx context.Context, omciOut chan openolt.OmciMsg, omciIn chan openolt.OmciIndication, errch chan error) {
go func() {
defer logger.Debug("Omci response process was done")
diff --git a/core/tester.go b/core/tester.go
index 4f9ccaf..6e9f0bf 100644
--- a/core/tester.go
+++ b/core/tester.go
@@ -290,10 +290,15 @@
}
func activateWPASupplicant(univeth UniVeth, s *Server) (err error) {
+ /*
cmd := "/sbin/wpa_supplicant"
conf := "/etc/wpa_supplicant/wpa_supplicant.conf"
err = exec.Command(cmd, "-D", "wired", "-i", univeth.Veth, "-c", conf).Start()
+ */
onu, _ := s.GetOnuByID(univeth.OnuId)
+ if err = startPeer(onu.IntfID, onu.OnuID); err != nil {
+ logger.Error("%s", err)
+ }
if err != nil {
utils.LoggerWithOnu(onu).WithFields(log.Fields{
"err": err,
@@ -307,12 +312,12 @@
func activateDHCPClient(univeth UniVeth, s *Server) (err error) {
onu, _ := s.GetOnuByID(univeth.OnuId)
-
cmd := exec.Command("/usr/local/bin/dhclient", univeth.Veth)
if err := cmd.Start(); err != nil {
logger.Error("Fail to activateDHCPClient() for: %s", univeth.Veth)
logger.Panic("activateDHCPClient %s", err)
}
+
utils.LoggerWithOnu(onu).WithFields(log.Fields{
"veth": univeth.Veth,
}).Infof("activateDHCPClient() start for: %s", univeth.Veth)