blob: cd0606ebfcbbeb5369162cafc79dfea5acc1f973 [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"
Shrey Baid688b4242020-07-10 20:40:10 +053023 "net"
24
Matteo Scandolo47e69bb2019-08-28 15:41:12 -070025 "github.com/google/gopacket"
26 "github.com/google/gopacket/layers"
27 "github.com/looplab/fsm"
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -070028 bbsim "github.com/opencord/bbsim/internal/bbsim/types"
Matteo Scandolo47e69bb2019-08-28 15:41:12 -070029 omci "github.com/opencord/omci-sim"
Matteo Scandolo3de9de02019-11-14 13:40:03 -080030 "github.com/opencord/voltha-protos/v2/go/openolt"
Matteo Scandolo47e69bb2019-08-28 15:41:12 -070031 log "github.com/sirupsen/logrus"
Matteo Scandolo47e69bb2019-08-28 15:41:12 -070032)
33
34var eapolLogger = log.WithFields(log.Fields{
35 "module": "EAPOL",
36})
37
38var eapolVersion uint8 = 1
Matteo Scandolo075b1892019-10-07 12:11:07 -070039var GetGemPortId = omci.GetGemPortId
Matteo Scandolo47e69bb2019-08-28 15:41:12 -070040
Matteo Scandolo27428702019-10-11 16:21:16 -070041func sendEapolPktIn(msg bbsim.ByteMsg, portNo uint32, stream openolt.Openolt_EnableIndicationServer) {
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -070042 // FIXME unify sendDHCPPktIn and sendEapolPktIn methods
Matteo Scandolo47e69bb2019-08-28 15:41:12 -070043 gemid, err := omci.GetGemPortId(msg.IntfId, msg.OnuId)
44 if err != nil {
45 eapolLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -070046 "OnuId": msg.OnuId,
Matteo Scandolo47e69bb2019-08-28 15:41:12 -070047 "IntfId": msg.IntfId,
48 }).Errorf("Can't retrieve GemPortId: %s", err)
49 return
50 }
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -070051
52 log.WithFields(log.Fields{
Shrey Baid688b4242020-07-10 20:40:10 +053053 "OnuId": msg.OnuId,
54 "IntfId": msg.IntfId,
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -070055 "GemPort": gemid,
Shrey Baid688b4242020-07-10 20:40:10 +053056 "Type": "EAPOL",
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -070057 }).Trace("sending-pkt")
58
Matteo Scandolo47e69bb2019-08-28 15:41:12 -070059 data := &openolt.Indication_PktInd{PktInd: &openolt.PacketIndication{
Matteo Scandolo27428702019-10-11 16:21:16 -070060 IntfType: "pon",
61 IntfId: msg.IntfId,
62 GemportId: uint32(gemid),
63 Pkt: msg.Bytes,
64 PortNo: portNo,
Matteo Scandolo47e69bb2019-08-28 15:41:12 -070065 }}
66
67 if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
68 eapolLogger.Errorf("Fail to send EAPOL PktInd indication. %v", err)
69 return
70 }
71}
72
73func getMD5Data(eap *layers.EAP) []byte {
74 i := byte(eap.Id)
75 C := []byte(eap.BaseLayer.Contents)[6:]
76 P := []byte{i, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64} // "password"
77 data := md5.Sum(append(P, C...))
78 ret := make([]byte, 16)
79 for j := 0; j < 16; j++ {
80 ret[j] = data[j]
81 }
82 return ret
83}
84
Matteo Scandolo40e067f2019-10-16 16:59:41 -070085func createEAPChallengeRequest(eapId uint8, payload []byte) *layers.EAP {
86 eap := layers.EAP{
87 Code: layers.EAPCodeRequest,
88 Id: eapId,
89 Length: 22,
90 Type: layers.EAPTypeOTP,
91 TypeData: payload,
92 }
93 return &eap
94}
95
Matteo Scandolo47e69bb2019-08-28 15:41:12 -070096func createEAPChallengeResponse(eapId uint8, payload []byte) *layers.EAP {
97 eap := layers.EAP{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -070098 Code: layers.EAPCodeResponse,
99 Id: eapId,
100 Length: 22,
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700101 Type: layers.EAPTypeOTP,
102 TypeData: payload,
103 }
104 return &eap
105}
106
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700107func createEAPIdentityRequest(eapId uint8) *layers.EAP {
108 eap := layers.EAP{Code: layers.EAPCodeRequest,
109 Id: eapId,
110 Length: 9,
111 Type: layers.EAPTypeIdentity,
112 TypeData: []byte{0x75, 0x73, 0x65, 0x72}}
113 return &eap
114}
115
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700116func createEAPIdentityResponse(eapId uint8) *layers.EAP {
117 eap := layers.EAP{Code: layers.EAPCodeResponse,
118 Id: eapId,
119 Length: 9,
120 Type: layers.EAPTypeIdentity,
121 TypeData: []byte{0x75, 0x73, 0x65, 0x72}}
122 return &eap
123}
124
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700125func createEAPSuccess(eapId uint8) *layers.EAP {
126 eap := layers.EAP{
127 Code: layers.EAPCodeSuccess,
128 Id: eapId,
129 Length: 9,
130 Type: layers.EAPTypeNone,
131 TypeData: []byte{0x75, 0x73, 0x65, 0x72}}
132 return &eap
133}
134
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700135func createEAPOLPkt(eap *layers.EAP, onuId uint32, intfId uint32) []byte {
136 buffer := gopacket.NewSerializeBuffer()
137 options := gopacket.SerializeOptions{}
138
139 ethernetLayer := &layers.Ethernet{
140 SrcMAC: net.HardwareAddr{0x2e, 0x60, 0x70, 0x13, byte(intfId), byte(onuId)},
141 DstMAC: net.HardwareAddr{0x01, 0x80, 0xC2, 0x00, 0x00, 0x03},
142 EthernetType: layers.EthernetTypeEAPOL,
143 }
144
Shrey Baid688b4242020-07-10 20:40:10 +0530145 _ = gopacket.SerializeLayers(buffer, options,
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700146 ethernetLayer,
147 &layers.EAPOL{Version: eapolVersion, Type: 0, Length: eap.Length},
148 eap,
149 )
150
151 bytes := buffer.Bytes()
152 return bytes
153}
154
155func extractEAP(pkt gopacket.Packet) (*layers.EAP, error) {
156 layerEAP := pkt.Layer(layers.LayerTypeEAP)
157 eap, _ := layerEAP.(*layers.EAP)
158 if eap == nil {
159 return nil, errors.New("Cannot extract EAP")
160 }
161 return eap, nil
162}
163
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700164func extractEAPOL(pkt gopacket.Packet) (*layers.EAPOL, error) {
165 layerEAPOL := pkt.Layer(layers.LayerTypeEAPOL)
166 eap, _ := layerEAPOL.(*layers.EAPOL)
167 if eap == nil {
168 return nil, errors.New("Cannot extract EAPOL")
169 }
170 return eap, nil
171}
172
173func sendEapolPktOut(client openolt.OpenoltClient, intfId uint32, onuId uint32, pkt []byte) error {
174 onuPacket := openolt.OnuPacket{
175 IntfId: intfId,
176 OnuId: onuId,
177 PortNo: onuId,
178 GemportId: 1,
179 Pkt: pkt,
180 }
181
182 if _, err := client.OnuPacketOut(context.Background(), &onuPacket); err != nil {
183 return err
184 }
185 return nil
186}
187
Matteo Scandolo075b1892019-10-07 12:11:07 -0700188func updateAuthFailed(onuId uint32, ponPortId uint32, serialNumber string, onuStateMachine *fsm.FSM) error {
189 if err := onuStateMachine.Event("auth_failed"); err != nil {
190 eapolLogger.WithFields(log.Fields{
191 "OnuId": onuId,
192 "IntfId": ponPortId,
193 "OnuSn": serialNumber,
194 }).Errorf("Error while transitioning ONU State %v", err)
195 return err
196 }
197 return nil
198}
199
Matteo Scandolo27428702019-10-11 16:21:16 -0700200func 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 -0700201
202 // send the packet (hacked together)
Matteo Scandolo075b1892019-10-07 12:11:07 -0700203 gemId, err := GetGemPortId(ponPortId, onuId)
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700204 if err != nil {
Matteo Scandolo075b1892019-10-07 12:11:07 -0700205 eapolLogger.WithFields(log.Fields{
206 "OnuId": onuId,
207 "IntfId": ponPortId,
208 "OnuSn": serialNumber,
209 }).Errorf("Can't retrieve GemPortId: %s", err)
210
211 if err := updateAuthFailed(onuId, ponPortId, serialNumber, onuStateMachine); err != nil {
212 return err
213 }
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700214 return err
215 }
216
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700217 // TODO use createEAPOLPkt
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700218 buffer := gopacket.NewSerializeBuffer()
219 options := gopacket.SerializeOptions{}
220
221 ethernetLayer := &layers.Ethernet{
Matteo Scandolo86e8ce62019-10-11 12:03:10 -0700222 SrcMAC: macAddress,
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700223 DstMAC: net.HardwareAddr{0x01, 0x80, 0xC2, 0x00, 0x00, 0x03},
224 EthernetType: layers.EthernetTypeEAPOL,
225 }
226
Shrey Baid688b4242020-07-10 20:40:10 +0530227 _ = gopacket.SerializeLayers(buffer, options,
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700228 ethernetLayer,
229 &layers.EAPOL{Version: eapolVersion, Type: 1, Length: 0},
230 )
231
232 msg := buffer.Bytes()
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700233 // TODO end createEAPOLPkt
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700234
235 data := &openolt.Indication_PktInd{
236 PktInd: &openolt.PacketIndication{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700237 IntfType: "pon",
238 IntfId: ponPortId,
Matteo Scandolo075b1892019-10-07 12:11:07 -0700239 GemportId: uint32(gemId),
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700240 Pkt: msg,
Matteo Scandolo27428702019-10-11 16:21:16 -0700241 PortNo: portNo,
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700242 },
243 }
Matteo Scandolo075b1892019-10-07 12:11:07 -0700244
245 err = stream.Send(&openolt.Indication{Data: data})
246 if err != nil {
247 eapolLogger.WithFields(log.Fields{
248 "OnuId": onuId,
249 "IntfId": ponPortId,
250 "OnuSn": serialNumber,
251 }).Errorf("Can't send EapStart Message: %s", err)
252
253 if err := updateAuthFailed(onuId, ponPortId, serialNumber, onuStateMachine); err != nil {
254 return err
255 }
256 return err
257 }
258
Matteo Scandolo27428702019-10-11 16:21:16 -0700259 eapolLogger.WithFields(log.Fields{
260 "OnuId": onuId,
261 "IntfId": ponPortId,
262 "OnuSn": serialNumber,
263 "PortNo": portNo,
264 }).Debugf("Sent EapStart packet")
Matteo Scandolo075b1892019-10-07 12:11:07 -0700265
266 if err := onuStateMachine.Event("eap_start_sent"); err != nil {
267 eapolLogger.WithFields(log.Fields{
268 "OnuId": onuId,
269 "IntfId": ponPortId,
270 "OnuSn": serialNumber,
271 }).Errorf("Error while transitioning ONU State %v", err)
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700272 return err
273 }
274 return nil
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700275}
Matteo Scandolo075b1892019-10-07 12:11:07 -0700276
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700277func 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 -0700278
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700279 eap, eapErr := extractEAP(pkt)
280
281 eapol, eapolErr := extractEAPOL(pkt)
282
283 if eapErr != nil && eapolErr != nil {
284 log.Fatalf("Failed to Extract EAP: %v - %v", eapErr, eapolErr)
285 return
Matteo Scandolo075b1892019-10-07 12:11:07 -0700286 }
287
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700288 fields := log.Fields{}
289 if eap != nil {
290 fields = log.Fields{
291 "Code": eap.Code,
292 "Type": eap.Type,
293 "OnuId": onuId,
294 "IntfId": ponPortId,
295 "OnuSn": serialNumber,
296 }
297 } else if eapol != nil {
298 fields = log.Fields{
299 "Type": eapol.Type,
300 "OnuId": onuId,
301 "IntfId": ponPortId,
302 "OnuSn": serialNumber,
303 }
304 }
Matteo Scandolo27428702019-10-11 16:21:16 -0700305
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700306 log.WithFields(fields).Tracef("Handle Next EAPOL Packet")
307
308 if eapol != nil && eapol.Type == layers.EAPOLTypeStart {
309 identityRequest := createEAPIdentityRequest(1)
310 pkt := createEAPOLPkt(identityRequest, onuId, ponPortId)
311
312 if err := sendEapolPktOut(client, ponPortId, onuId, pkt); err != nil {
313 log.WithFields(log.Fields{
314 "OnuId": onuId,
315 "IntfId": ponPortId,
316 "OnuSn": serialNumber,
317 "error": err,
318 }).Errorf("Error while sending EAPIdentityRequest packet")
319 return
320 }
321
322 log.WithFields(log.Fields{
323 "OnuId": onuId,
324 "IntfId": ponPortId,
325 "OnuSn": serialNumber,
326 }).Infof("Sent EAPIdentityRequest packet")
327 return
328 } else if eap.Code == layers.EAPCodeRequest && eap.Type == layers.EAPTypeIdentity {
Matteo Scandolo075b1892019-10-07 12:11:07 -0700329 reseap := createEAPIdentityResponse(eap.Id)
330 pkt := createEAPOLPkt(reseap, onuId, ponPortId)
331
332 msg := bbsim.ByteMsg{
333 IntfId: ponPortId,
334 OnuId: onuId,
335 Bytes: pkt,
336 }
337
Matteo Scandolo27428702019-10-11 16:21:16 -0700338 sendEapolPktIn(msg, portNo, stream)
Matteo Scandolo075b1892019-10-07 12:11:07 -0700339 eapolLogger.WithFields(log.Fields{
340 "OnuId": onuId,
341 "IntfId": ponPortId,
342 "OnuSn": serialNumber,
Matteo Scandolo27428702019-10-11 16:21:16 -0700343 "PortNo": portNo,
344 }).Debugf("Sent EAPIdentityResponse packet")
Matteo Scandolo075b1892019-10-07 12:11:07 -0700345 if err := onuStateMachine.Event("eap_response_identity_sent"); err != nil {
346 eapolLogger.WithFields(log.Fields{
347 "OnuId": onuId,
348 "IntfId": ponPortId,
349 "OnuSn": serialNumber,
350 }).Errorf("Error while transitioning ONU State %v", err)
351 }
352
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700353 } else if eap.Code == layers.EAPCodeResponse && eap.Type == layers.EAPTypeIdentity {
354 senddata := getMD5Data(eap)
355 senddata = append([]byte{0x10}, senddata...)
356 challengeRequest := createEAPChallengeRequest(eap.Id, senddata)
357 pkt := createEAPOLPkt(challengeRequest, onuId, ponPortId)
358
359 if err := sendEapolPktOut(client, ponPortId, onuId, pkt); err != nil {
360 log.WithFields(log.Fields{
361 "OnuId": onuId,
362 "IntfId": ponPortId,
363 "OnuSn": serialNumber,
364 "error": err,
365 }).Errorf("Error while sending EAPChallengeRequest packet")
366 return
367 }
368 log.WithFields(log.Fields{
369 "OnuId": onuId,
370 "IntfId": ponPortId,
371 "OnuSn": serialNumber,
372 }).Infof("Sent EAPChallengeRequest packet")
373 return
Matteo Scandolo075b1892019-10-07 12:11:07 -0700374 } else if eap.Code == layers.EAPCodeRequest && eap.Type == layers.EAPTypeOTP {
375 senddata := getMD5Data(eap)
376 senddata = append([]byte{0x10}, senddata...)
377 sendeap := createEAPChallengeResponse(eap.Id, senddata)
378 pkt := createEAPOLPkt(sendeap, onuId, ponPortId)
379
380 msg := bbsim.ByteMsg{
381 IntfId: ponPortId,
382 OnuId: onuId,
383 Bytes: pkt,
384 }
385
Matteo Scandolo27428702019-10-11 16:21:16 -0700386 sendEapolPktIn(msg, portNo, stream)
Matteo Scandolo075b1892019-10-07 12:11:07 -0700387 eapolLogger.WithFields(log.Fields{
388 "OnuId": onuId,
389 "IntfId": ponPortId,
390 "OnuSn": serialNumber,
Matteo Scandolo27428702019-10-11 16:21:16 -0700391 "PortNo": portNo,
392 }).Debugf("Sent EAPChallengeResponse packet")
Matteo Scandolo075b1892019-10-07 12:11:07 -0700393 if err := onuStateMachine.Event("eap_response_challenge_sent"); err != nil {
394 eapolLogger.WithFields(log.Fields{
395 "OnuId": onuId,
396 "IntfId": ponPortId,
397 "OnuSn": serialNumber,
398 }).Errorf("Error while transitioning ONU State %v", err)
399 }
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700400 } else if eap.Code == layers.EAPCodeResponse && eap.Type == layers.EAPTypeOTP {
401 eapSuccess := createEAPSuccess(eap.Id)
402 pkt := createEAPOLPkt(eapSuccess, onuId, ponPortId)
403
404 if err := sendEapolPktOut(client, ponPortId, onuId, pkt); err != nil {
405 log.WithFields(log.Fields{
406 "OnuId": onuId,
407 "IntfId": ponPortId,
408 "OnuSn": serialNumber,
409 "error": err,
410 }).Errorf("Error while sending EAPSuccess packet")
411 return
412 }
413
414 log.WithFields(log.Fields{
415 "OnuId": onuId,
416 "IntfId": ponPortId,
417 "OnuSn": serialNumber,
418 }).Infof("Sent EAP Success packet")
419
420 if err := onuStateMachine.Event("send_dhcp_flow"); err != nil {
421 eapolLogger.WithFields(log.Fields{
422 "OnuId": onuId,
423 "IntfId": ponPortId,
424 "OnuSn": serialNumber,
425 }).Errorf("Error while transitioning ONU State %v", err)
426 }
Matteo Scandolo075b1892019-10-07 12:11:07 -0700427 } else if eap.Code == layers.EAPCodeSuccess && eap.Type == layers.EAPTypeNone {
428 eapolLogger.WithFields(log.Fields{
429 "OnuId": onuId,
430 "IntfId": ponPortId,
431 "OnuSn": serialNumber,
Matteo Scandolo27428702019-10-11 16:21:16 -0700432 "PortNo": portNo,
433 }).Debugf("Received EAPSuccess packet")
Matteo Scandolo075b1892019-10-07 12:11:07 -0700434 if err := onuStateMachine.Event("eap_response_success_received"); err != nil {
435 eapolLogger.WithFields(log.Fields{
436 "OnuId": onuId,
437 "IntfId": ponPortId,
438 "OnuSn": serialNumber,
439 }).Errorf("Error while transitioning ONU State %v", err)
440 }
441 eapolLogger.WithFields(log.Fields{
442 "OnuId": onuId,
443 "IntfId": ponPortId,
444 "OnuSn": serialNumber,
445 }).Infof("EAPOL State machine completed")
446 return
447 }
448}