blob: c13aa695106bd98e0707f797d8fd0c5c0e5d2b0a [file] [log] [blame]
Matteo Scandolo47e69bb2019-08-28 15:41:12 -07001/*
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 eapol
18
19import (
Matteo Scandolo40e067f2019-10-16 16:59:41 -070020 "context"
Matteo Scandolo47e69bb2019-08-28 15:41:12 -070021 "crypto/md5"
22 "errors"
Matteo Scandolo47e69bb2019-08-28 15:41:12 -070023 "github.com/google/gopacket"
24 "github.com/google/gopacket/layers"
25 "github.com/looplab/fsm"
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -070026 bbsim "github.com/opencord/bbsim/internal/bbsim/types"
Matteo Scandolo47e69bb2019-08-28 15:41:12 -070027 omci "github.com/opencord/omci-sim"
28 "github.com/opencord/voltha-protos/go/openolt"
29 log "github.com/sirupsen/logrus"
30 "net"
Matteo Scandolo47e69bb2019-08-28 15:41:12 -070031)
32
33var eapolLogger = log.WithFields(log.Fields{
34 "module": "EAPOL",
35})
36
37var eapolVersion uint8 = 1
Matteo Scandolo075b1892019-10-07 12:11:07 -070038var GetGemPortId = omci.GetGemPortId
Matteo Scandolo47e69bb2019-08-28 15:41:12 -070039
Matteo Scandolo27428702019-10-11 16:21:16 -070040func sendEapolPktIn(msg bbsim.ByteMsg, portNo uint32, stream openolt.Openolt_EnableIndicationServer) {
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -070041 // FIXME unify sendDHCPPktIn and sendEapolPktIn methods
Matteo Scandolo47e69bb2019-08-28 15:41:12 -070042 gemid, err := omci.GetGemPortId(msg.IntfId, msg.OnuId)
43 if err != nil {
44 eapolLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -070045 "OnuId": msg.OnuId,
Matteo Scandolo47e69bb2019-08-28 15:41:12 -070046 "IntfId": msg.IntfId,
47 }).Errorf("Can't retrieve GemPortId: %s", err)
48 return
49 }
50 data := &openolt.Indication_PktInd{PktInd: &openolt.PacketIndication{
Matteo Scandolo27428702019-10-11 16:21:16 -070051 IntfType: "pon",
52 IntfId: msg.IntfId,
53 GemportId: uint32(gemid),
54 Pkt: msg.Bytes,
55 PortNo: portNo,
Matteo Scandolo47e69bb2019-08-28 15:41:12 -070056 }}
57
58 if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
59 eapolLogger.Errorf("Fail to send EAPOL PktInd indication. %v", err)
60 return
61 }
62}
63
64func getMD5Data(eap *layers.EAP) []byte {
65 i := byte(eap.Id)
66 C := []byte(eap.BaseLayer.Contents)[6:]
67 P := []byte{i, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64} // "password"
68 data := md5.Sum(append(P, C...))
69 ret := make([]byte, 16)
70 for j := 0; j < 16; j++ {
71 ret[j] = data[j]
72 }
73 return ret
74}
75
Matteo Scandolo40e067f2019-10-16 16:59:41 -070076func createEAPChallengeRequest(eapId uint8, payload []byte) *layers.EAP {
77 eap := layers.EAP{
78 Code: layers.EAPCodeRequest,
79 Id: eapId,
80 Length: 22,
81 Type: layers.EAPTypeOTP,
82 TypeData: payload,
83 }
84 return &eap
85}
86
Matteo Scandolo47e69bb2019-08-28 15:41:12 -070087func createEAPChallengeResponse(eapId uint8, payload []byte) *layers.EAP {
88 eap := layers.EAP{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -070089 Code: layers.EAPCodeResponse,
90 Id: eapId,
91 Length: 22,
Matteo Scandolo47e69bb2019-08-28 15:41:12 -070092 Type: layers.EAPTypeOTP,
93 TypeData: payload,
94 }
95 return &eap
96}
97
Matteo Scandolo40e067f2019-10-16 16:59:41 -070098func createEAPIdentityRequest(eapId uint8) *layers.EAP {
99 eap := layers.EAP{Code: layers.EAPCodeRequest,
100 Id: eapId,
101 Length: 9,
102 Type: layers.EAPTypeIdentity,
103 TypeData: []byte{0x75, 0x73, 0x65, 0x72}}
104 return &eap
105}
106
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700107func createEAPIdentityResponse(eapId uint8) *layers.EAP {
108 eap := layers.EAP{Code: layers.EAPCodeResponse,
109 Id: eapId,
110 Length: 9,
111 Type: layers.EAPTypeIdentity,
112 TypeData: []byte{0x75, 0x73, 0x65, 0x72}}
113 return &eap
114}
115
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700116func createEAPSuccess(eapId uint8) *layers.EAP {
117 eap := layers.EAP{
118 Code: layers.EAPCodeSuccess,
119 Id: eapId,
120 Length: 9,
121 Type: layers.EAPTypeNone,
122 TypeData: []byte{0x75, 0x73, 0x65, 0x72}}
123 return &eap
124}
125
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700126func createEAPOLPkt(eap *layers.EAP, onuId uint32, intfId uint32) []byte {
127 buffer := gopacket.NewSerializeBuffer()
128 options := gopacket.SerializeOptions{}
129
130 ethernetLayer := &layers.Ethernet{
131 SrcMAC: net.HardwareAddr{0x2e, 0x60, 0x70, 0x13, byte(intfId), byte(onuId)},
132 DstMAC: net.HardwareAddr{0x01, 0x80, 0xC2, 0x00, 0x00, 0x03},
133 EthernetType: layers.EthernetTypeEAPOL,
134 }
135
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700136 gopacket.SerializeLayers(buffer, options,
137 ethernetLayer,
138 &layers.EAPOL{Version: eapolVersion, Type: 0, Length: eap.Length},
139 eap,
140 )
141
142 bytes := buffer.Bytes()
143 return bytes
144}
145
146func extractEAP(pkt gopacket.Packet) (*layers.EAP, error) {
147 layerEAP := pkt.Layer(layers.LayerTypeEAP)
148 eap, _ := layerEAP.(*layers.EAP)
149 if eap == nil {
150 return nil, errors.New("Cannot extract EAP")
151 }
152 return eap, nil
153}
154
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700155func extractEAPOL(pkt gopacket.Packet) (*layers.EAPOL, error) {
156 layerEAPOL := pkt.Layer(layers.LayerTypeEAPOL)
157 eap, _ := layerEAPOL.(*layers.EAPOL)
158 if eap == nil {
159 return nil, errors.New("Cannot extract EAPOL")
160 }
161 return eap, nil
162}
163
164func sendEapolPktOut(client openolt.OpenoltClient, intfId uint32, onuId uint32, pkt []byte) error {
165 onuPacket := openolt.OnuPacket{
166 IntfId: intfId,
167 OnuId: onuId,
168 PortNo: onuId,
169 GemportId: 1,
170 Pkt: pkt,
171 }
172
173 if _, err := client.OnuPacketOut(context.Background(), &onuPacket); err != nil {
174 return err
175 }
176 return nil
177}
178
Matteo Scandolo075b1892019-10-07 12:11:07 -0700179func updateAuthFailed(onuId uint32, ponPortId uint32, serialNumber string, onuStateMachine *fsm.FSM) error {
180 if err := onuStateMachine.Event("auth_failed"); err != nil {
181 eapolLogger.WithFields(log.Fields{
182 "OnuId": onuId,
183 "IntfId": ponPortId,
184 "OnuSn": serialNumber,
185 }).Errorf("Error while transitioning ONU State %v", err)
186 return err
187 }
188 return nil
189}
190
Matteo Scandolo27428702019-10-11 16:21:16 -0700191func SendEapStart(onuId uint32, ponPortId uint32, serialNumber string, portNo uint32, macAddress net.HardwareAddr, onuStateMachine *fsm.FSM, stream bbsim.Stream) error {
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700192
193 // send the packet (hacked together)
Matteo Scandolo075b1892019-10-07 12:11:07 -0700194 gemId, err := GetGemPortId(ponPortId, onuId)
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700195 if err != nil {
Matteo Scandolo075b1892019-10-07 12:11:07 -0700196 eapolLogger.WithFields(log.Fields{
197 "OnuId": onuId,
198 "IntfId": ponPortId,
199 "OnuSn": serialNumber,
200 }).Errorf("Can't retrieve GemPortId: %s", err)
201
202 if err := updateAuthFailed(onuId, ponPortId, serialNumber, onuStateMachine); err != nil {
203 return err
204 }
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700205 return err
206 }
207
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700208 // TODO use createEAPOLPkt
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700209 buffer := gopacket.NewSerializeBuffer()
210 options := gopacket.SerializeOptions{}
211
212 ethernetLayer := &layers.Ethernet{
Matteo Scandolo86e8ce62019-10-11 12:03:10 -0700213 SrcMAC: macAddress,
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700214 DstMAC: net.HardwareAddr{0x01, 0x80, 0xC2, 0x00, 0x00, 0x03},
215 EthernetType: layers.EthernetTypeEAPOL,
216 }
217
218 gopacket.SerializeLayers(buffer, options,
219 ethernetLayer,
220 &layers.EAPOL{Version: eapolVersion, Type: 1, Length: 0},
221 )
222
223 msg := buffer.Bytes()
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700224 // TODO end createEAPOLPkt
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700225
226 data := &openolt.Indication_PktInd{
227 PktInd: &openolt.PacketIndication{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700228 IntfType: "pon",
229 IntfId: ponPortId,
Matteo Scandolo075b1892019-10-07 12:11:07 -0700230 GemportId: uint32(gemId),
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700231 Pkt: msg,
Matteo Scandolo27428702019-10-11 16:21:16 -0700232 PortNo: portNo,
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700233 },
234 }
Matteo Scandolo075b1892019-10-07 12:11:07 -0700235
236 err = stream.Send(&openolt.Indication{Data: data})
237 if err != nil {
238 eapolLogger.WithFields(log.Fields{
239 "OnuId": onuId,
240 "IntfId": ponPortId,
241 "OnuSn": serialNumber,
242 }).Errorf("Can't send EapStart Message: %s", err)
243
244 if err := updateAuthFailed(onuId, ponPortId, serialNumber, onuStateMachine); err != nil {
245 return err
246 }
247 return err
248 }
249
Matteo Scandolo27428702019-10-11 16:21:16 -0700250 eapolLogger.WithFields(log.Fields{
251 "OnuId": onuId,
252 "IntfId": ponPortId,
253 "OnuSn": serialNumber,
254 "PortNo": portNo,
255 }).Debugf("Sent EapStart packet")
Matteo Scandolo075b1892019-10-07 12:11:07 -0700256
257 if err := onuStateMachine.Event("eap_start_sent"); err != nil {
258 eapolLogger.WithFields(log.Fields{
259 "OnuId": onuId,
260 "IntfId": ponPortId,
261 "OnuSn": serialNumber,
262 }).Errorf("Error while transitioning ONU State %v", err)
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700263 return err
264 }
265 return nil
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700266}
Matteo Scandolo075b1892019-10-07 12:11:07 -0700267
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700268func HandleNextPacket(onuId uint32, ponPortId uint32, serialNumber string, portNo uint32, onuStateMachine *fsm.FSM, pkt gopacket.Packet, stream openolt.Openolt_EnableIndicationServer, client openolt.OpenoltClient) {
Matteo Scandolo27428702019-10-11 16:21:16 -0700269
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700270 eap, eapErr := extractEAP(pkt)
271
272 eapol, eapolErr := extractEAPOL(pkt)
273
274 if eapErr != nil && eapolErr != nil {
275 log.Fatalf("Failed to Extract EAP: %v - %v", eapErr, eapolErr)
276 return
Matteo Scandolo075b1892019-10-07 12:11:07 -0700277 }
278
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700279 fields := log.Fields{}
280 if eap != nil {
281 fields = log.Fields{
282 "Code": eap.Code,
283 "Type": eap.Type,
284 "OnuId": onuId,
285 "IntfId": ponPortId,
286 "OnuSn": serialNumber,
287 }
288 } else if eapol != nil {
289 fields = log.Fields{
290 "Type": eapol.Type,
291 "OnuId": onuId,
292 "IntfId": ponPortId,
293 "OnuSn": serialNumber,
294 }
295 }
Matteo Scandolo27428702019-10-11 16:21:16 -0700296
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700297 log.WithFields(fields).Tracef("Handle Next EAPOL Packet")
298
299 if eapol != nil && eapol.Type == layers.EAPOLTypeStart {
300 identityRequest := createEAPIdentityRequest(1)
301 pkt := createEAPOLPkt(identityRequest, onuId, ponPortId)
302
303 if err := sendEapolPktOut(client, ponPortId, onuId, pkt); err != nil {
304 log.WithFields(log.Fields{
305 "OnuId": onuId,
306 "IntfId": ponPortId,
307 "OnuSn": serialNumber,
308 "error": err,
309 }).Errorf("Error while sending EAPIdentityRequest packet")
310 return
311 }
312
313 log.WithFields(log.Fields{
314 "OnuId": onuId,
315 "IntfId": ponPortId,
316 "OnuSn": serialNumber,
317 }).Infof("Sent EAPIdentityRequest packet")
318 return
319 } else if eap.Code == layers.EAPCodeRequest && eap.Type == layers.EAPTypeIdentity {
Matteo Scandolo075b1892019-10-07 12:11:07 -0700320 reseap := createEAPIdentityResponse(eap.Id)
321 pkt := createEAPOLPkt(reseap, onuId, ponPortId)
322
323 msg := bbsim.ByteMsg{
324 IntfId: ponPortId,
325 OnuId: onuId,
326 Bytes: pkt,
327 }
328
Matteo Scandolo27428702019-10-11 16:21:16 -0700329 sendEapolPktIn(msg, portNo, stream)
Matteo Scandolo075b1892019-10-07 12:11:07 -0700330 eapolLogger.WithFields(log.Fields{
331 "OnuId": onuId,
332 "IntfId": ponPortId,
333 "OnuSn": serialNumber,
Matteo Scandolo27428702019-10-11 16:21:16 -0700334 "PortNo": portNo,
335 }).Debugf("Sent EAPIdentityResponse packet")
Matteo Scandolo075b1892019-10-07 12:11:07 -0700336 if err := onuStateMachine.Event("eap_response_identity_sent"); err != nil {
337 eapolLogger.WithFields(log.Fields{
338 "OnuId": onuId,
339 "IntfId": ponPortId,
340 "OnuSn": serialNumber,
341 }).Errorf("Error while transitioning ONU State %v", err)
342 }
343
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700344 } else if eap.Code == layers.EAPCodeResponse && eap.Type == layers.EAPTypeIdentity {
345 senddata := getMD5Data(eap)
346 senddata = append([]byte{0x10}, senddata...)
347 challengeRequest := createEAPChallengeRequest(eap.Id, senddata)
348 pkt := createEAPOLPkt(challengeRequest, onuId, ponPortId)
349
350 if err := sendEapolPktOut(client, ponPortId, onuId, pkt); err != nil {
351 log.WithFields(log.Fields{
352 "OnuId": onuId,
353 "IntfId": ponPortId,
354 "OnuSn": serialNumber,
355 "error": err,
356 }).Errorf("Error while sending EAPChallengeRequest packet")
357 return
358 }
359 log.WithFields(log.Fields{
360 "OnuId": onuId,
361 "IntfId": ponPortId,
362 "OnuSn": serialNumber,
363 }).Infof("Sent EAPChallengeRequest packet")
364 return
Matteo Scandolo075b1892019-10-07 12:11:07 -0700365 } else if eap.Code == layers.EAPCodeRequest && eap.Type == layers.EAPTypeOTP {
366 senddata := getMD5Data(eap)
367 senddata = append([]byte{0x10}, senddata...)
368 sendeap := createEAPChallengeResponse(eap.Id, senddata)
369 pkt := createEAPOLPkt(sendeap, onuId, ponPortId)
370
371 msg := bbsim.ByteMsg{
372 IntfId: ponPortId,
373 OnuId: onuId,
374 Bytes: pkt,
375 }
376
Matteo Scandolo27428702019-10-11 16:21:16 -0700377 sendEapolPktIn(msg, portNo, stream)
Matteo Scandolo075b1892019-10-07 12:11:07 -0700378 eapolLogger.WithFields(log.Fields{
379 "OnuId": onuId,
380 "IntfId": ponPortId,
381 "OnuSn": serialNumber,
Matteo Scandolo27428702019-10-11 16:21:16 -0700382 "PortNo": portNo,
383 }).Debugf("Sent EAPChallengeResponse packet")
Matteo Scandolo075b1892019-10-07 12:11:07 -0700384 if err := onuStateMachine.Event("eap_response_challenge_sent"); err != nil {
385 eapolLogger.WithFields(log.Fields{
386 "OnuId": onuId,
387 "IntfId": ponPortId,
388 "OnuSn": serialNumber,
389 }).Errorf("Error while transitioning ONU State %v", err)
390 }
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700391 } else if eap.Code == layers.EAPCodeResponse && eap.Type == layers.EAPTypeOTP {
392 eapSuccess := createEAPSuccess(eap.Id)
393 pkt := createEAPOLPkt(eapSuccess, onuId, ponPortId)
394
395 if err := sendEapolPktOut(client, ponPortId, onuId, pkt); err != nil {
396 log.WithFields(log.Fields{
397 "OnuId": onuId,
398 "IntfId": ponPortId,
399 "OnuSn": serialNumber,
400 "error": err,
401 }).Errorf("Error while sending EAPSuccess packet")
402 return
403 }
404
405 log.WithFields(log.Fields{
406 "OnuId": onuId,
407 "IntfId": ponPortId,
408 "OnuSn": serialNumber,
409 }).Infof("Sent EAP Success packet")
410
411 if err := onuStateMachine.Event("send_dhcp_flow"); err != nil {
412 eapolLogger.WithFields(log.Fields{
413 "OnuId": onuId,
414 "IntfId": ponPortId,
415 "OnuSn": serialNumber,
416 }).Errorf("Error while transitioning ONU State %v", err)
417 }
Matteo Scandolo075b1892019-10-07 12:11:07 -0700418 } else if eap.Code == layers.EAPCodeSuccess && eap.Type == layers.EAPTypeNone {
419 eapolLogger.WithFields(log.Fields{
420 "OnuId": onuId,
421 "IntfId": ponPortId,
422 "OnuSn": serialNumber,
Matteo Scandolo27428702019-10-11 16:21:16 -0700423 "PortNo": portNo,
424 }).Debugf("Received EAPSuccess packet")
Matteo Scandolo075b1892019-10-07 12:11:07 -0700425 if err := onuStateMachine.Event("eap_response_success_received"); err != nil {
426 eapolLogger.WithFields(log.Fields{
427 "OnuId": onuId,
428 "IntfId": ponPortId,
429 "OnuSn": serialNumber,
430 }).Errorf("Error while transitioning ONU State %v", err)
431 }
432 eapolLogger.WithFields(log.Fields{
433 "OnuId": onuId,
434 "IntfId": ponPortId,
435 "OnuSn": serialNumber,
436 }).Infof("EAPOL State machine completed")
437 return
438 }
439}