blob: e40da4751506702ff87d4281587e4f577ebe448e [file] [log] [blame]
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +09001/*
2 * Copyright 2018-present Open Networking Foundation
3
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7
8 * http://www.apache.org/licenses/LICENSE-2.0
9
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package core
18
19import (
20 "context"
21 "gerrit.opencord.org/voltha-bbsim/common/logger"
22 "net"
23 "errors"
24 "encoding/hex"
25 "github.com/google/gopacket"
26 "github.com/google/gopacket/layers"
27 "crypto/md5"
28 "sync"
29)
30
31type eapState int
32const (
33 START eapState = iota //TODO: This state definition should support 802.1X
34 RESPID
35 RESPCHA
36 SUCCESS
37)
38
39
40
41type responder struct {
42 peers map [key] *peerInstance
43 eapolIn chan *EAPByte
44}
45
46type peerInstance struct{
47 key key
48 srcaddr *net.HardwareAddr
49 version uint8
50 curId uint8
51 curState eapState
52}
53
54type key struct {
55 intfid uint32
56 onuid uint32
57}
58
59var resp *responder
60var once sync.Once
61func getResponder () *responder {
62 once.Do(func(){
63 resp = &responder{peers: make(map[key] *peerInstance), eapolIn: nil}
64 })
65 return resp
66}
67
68func RunEapolResponder(ctx context.Context, eapolOut chan *EAPPkt, eapolIn chan *EAPByte, errch chan error) {
69 responder := getResponder()
70 responder.eapolIn = eapolIn
71 peers := responder.peers
72
73 go func() {
74 logger.Debug("EAPOL response process starts")
75 defer logger.Debug("EAPOL response process was done")
76 for {
77 select {
78 case msg := <- eapolOut:
79 logger.Debug("Received eapol from eapolOut")
80 intfid := msg.IntfId
81 onuid := msg.OnuId
82
83 if peer, ok := peers[key{intfid: intfid, onuid:onuid}]; ok {
84 logger.Debug("Key hit intfid:%d onuid: %d", intfid, onuid)
85 curstate := peer.curState
86 nextstate, err := peer.transitState(curstate, eapolIn, msg.Pkt)
87 if err != nil {
88 logger.Error("Failed to transitState: %s", err)
89 }
90 peer.curState = nextstate
91 } else {
92 logger.Error("Failed to find eapol peer instance intfid:%d onuid:%d", intfid, onuid)
93 }
94 case <-ctx.Done():
95 return
96 }
97 }
98 }()
99}
100
101func startPeer (intfid uint32, onuid uint32) error {
102 peer := peerInstance{key: key{intfid: intfid, onuid: onuid},
103 srcaddr: &net.HardwareAddr{0x2e, 0x60, 0x70, 0x13, 0x07, byte(onuid)},
104 version: 1,
105 curId: 0,
106 curState: START}
107
108 eap := peer.createEAPStart()
109 bytes := peer.createEAPOL(eap)
110 resp := getResponder()
111 eapolIn := resp.eapolIn
112 if err := peer.sendPkt(bytes, eapolIn); err != nil {
113 return errors.New("Failed to send EAPStart")
114 }
115 logger.Debug("Sending EAPStart")
116 logger.Debug(hex.Dump(bytes))
117 //peers[key{intfid: intfid, onuid: onuid}] = &peer
118 resp.peers[key{intfid: intfid, onuid: onuid}] = &peer
119 return nil
120}
121
122func (p *peerInstance)transitState(cur eapState, omciIn chan *EAPByte, recvpkt gopacket.Packet) (next eapState, err error) {
123 logger.Debug("currentState:%d", cur)
124 eap, err := extractEAP(recvpkt)
125 if err != nil {
126 return cur, nil
127 }
128 if eap.Code == layers.EAPCodeRequest && eap.Type == layers.EAPTypeIdentity {
129 logger.Debug("Received EAP-Request/Identity")
130 logger.Debug(recvpkt.Dump())
131 p.curId = eap.Id
132 if cur == START {
133 reseap := p.createEAPResID()
134 pkt := p.createEAPOL(reseap)
135 logger.Debug("Sending EAP-Response/Identity")
136 if err != p.sendPkt(pkt, omciIn) {
137 return cur, err
138 }
139 return RESPID, nil
140 }
141 } else if eap.Code == layers.EAPCodeRequest && eap.Type == layers.EAPTypeOTP {
142 logger.Debug("Received EAP-Request/Challenge")
143 logger.Debug(recvpkt.Dump())
144 if cur == RESPID {
145 p.curId = eap.Id
146 resdata := getMD5Res (p.curId, eap)
147 resdata = append([]byte{0x10}, resdata ...)
148 reseap := p.createEAPResCha(resdata)
149 pkt := p.createEAPOL(reseap)
150 logger.Debug("Sending EAP-Response/Challenge")
151 if err != p.sendPkt(pkt, omciIn) {
152 return cur, err
153 }
154 return RESPCHA, nil
155 }
156 } else if eap.Code == layers.EAPCodeSuccess && eap.Type == layers.EAPTypeNone {
157 logger.Debug("Received EAP-Success")
158 logger.Debug(recvpkt.Dump())
159 if cur == RESPCHA {
160 return SUCCESS, nil
161 }
162 } else {
163 logger.Debug("Received unsupported EAP")
164 return cur, nil
165 }
166 logger.Debug("State transition does not support..current state:%d", cur)
167 logger.Debug(recvpkt.Dump())
168 return cur, nil
169}
170
171func (p *peerInstance) createEAPOL (eap *layers.EAP) []byte {
172 buffer := gopacket.NewSerializeBuffer()
173 options := gopacket.SerializeOptions{}
174
175 ethernetLayer := &layers.Ethernet{
176 SrcMAC: *p.srcaddr,
177 DstMAC: net.HardwareAddr{0x01, 0x80, 0xC2, 0x00, 0x00, 0x03},
178 EthernetType: layers.EthernetTypeEAPOL,
179 }
180
181 if eap == nil { // EAP Start
182 gopacket.SerializeLayers(buffer, options,
183 ethernetLayer,
184 &layers.EAPOL{Version: p.version, Type:1, Length: 0},
185 )
186 } else {
187 gopacket.SerializeLayers(buffer, options,
188 ethernetLayer,
189 &layers.EAPOL{Version: p.version, Type:0, Length: eap.Length},
190 eap,
191 )
192 }
193 bytes := buffer.Bytes()
194 return bytes
195}
196
197func (p *peerInstance) createEAPStart () *layers.EAP {
198 return nil
199}
200
201func (p *peerInstance) createEAPResID () *layers.EAP {
202 eap := layers.EAP{Code: layers.EAPCodeResponse,
203 Id: p.curId,
204 Length: 9,
205 Type: layers.EAPTypeIdentity,
206 TypeData: []byte{0x75, 0x73, 0x65, 0x72 }}
207 return &eap
208}
209
210func (p *peerInstance) createEAPResCha (payload []byte) *layers.EAP {
211 eap := layers.EAP{Code: layers.EAPCodeResponse,
212 Id: p.curId, Length: 22,
213 Type: layers.EAPTypeOTP,
214 TypeData: payload}
215 return &eap
216}
217
218func (p *peerInstance) sendPkt (pkt []byte, omciIn chan *EAPByte) error {
219 // Send our packet
220 msg := EAPByte{IntfId: p.key.intfid,
221 OnuId: p.key.onuid,
222 Byte: pkt}
223 omciIn <- &msg
224 logger.Debug("sendPkt intfid:%d onuid:%d", p.key.intfid, p.key.onuid)
225 logger.Debug(hex.Dump(msg.Byte))
226 return nil
227}
228
229func getMD5Res (id uint8, eap *layers.EAP) []byte {
230 i := byte(id)
231 C := []byte(eap.BaseLayer.Contents)[6:]
232 P := []byte{i, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64} //"password"
233 data := md5.Sum(append(P, C ...))
234 ret := make([]byte, 16)
235 for j := 0; j < 16; j ++ {
236 ret[j] = data[j]
237 }
238 return ret
239}
240
241func extractEAPOL (pkt gopacket.Packet) (*layers.EAPOL, error) {
242 layerEAPOL := pkt.Layer(layers.LayerTypeEAPOL)
243 eapol, _ := layerEAPOL.(*layers.EAPOL)
244 if eapol == nil {
245 return nil, errors.New("Cannot extract EAPOL")
246 }
247 return eapol, nil
248}
249
250func extractEAP (pkt gopacket.Packet) (*layers.EAP, error) {
251 layerEAP := pkt.Layer(layers.LayerTypeEAP)
252 eap, _ := layerEAP.(*layers.EAP)
253 if eap == nil {
254 return nil, errors.New("Cannot extract EAP")
255 }
256 return eap, nil
257}