blob: 7ee36fc0e5eea09f82a7bf0815ea7fde7b759347 [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"
Matteo Scandolo3de9de02019-11-14 13:40:03 -080028 "github.com/opencord/voltha-protos/v2/go/openolt"
Matteo Scandolo47e69bb2019-08-28 15:41:12 -070029 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 }
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -070050
51 log.WithFields(log.Fields{
52 "OnuId": msg.OnuId,
53 "IntfId": msg.IntfId,
54 "GemPort": gemid,
55 "Type": "EAPOL",
56 }).Trace("sending-pkt")
57
Matteo Scandolo47e69bb2019-08-28 15:41:12 -070058 data := &openolt.Indication_PktInd{PktInd: &openolt.PacketIndication{
Matteo Scandolo27428702019-10-11 16:21:16 -070059 IntfType: "pon",
60 IntfId: msg.IntfId,
61 GemportId: uint32(gemid),
62 Pkt: msg.Bytes,
63 PortNo: portNo,
Matteo Scandolo47e69bb2019-08-28 15:41:12 -070064 }}
65
66 if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
67 eapolLogger.Errorf("Fail to send EAPOL PktInd indication. %v", err)
68 return
69 }
70}
71
72func getMD5Data(eap *layers.EAP) []byte {
73 i := byte(eap.Id)
74 C := []byte(eap.BaseLayer.Contents)[6:]
75 P := []byte{i, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64} // "password"
76 data := md5.Sum(append(P, C...))
77 ret := make([]byte, 16)
78 for j := 0; j < 16; j++ {
79 ret[j] = data[j]
80 }
81 return ret
82}
83
Matteo Scandolo40e067f2019-10-16 16:59:41 -070084func createEAPChallengeRequest(eapId uint8, payload []byte) *layers.EAP {
85 eap := layers.EAP{
86 Code: layers.EAPCodeRequest,
87 Id: eapId,
88 Length: 22,
89 Type: layers.EAPTypeOTP,
90 TypeData: payload,
91 }
92 return &eap
93}
94
Matteo Scandolo47e69bb2019-08-28 15:41:12 -070095func createEAPChallengeResponse(eapId uint8, payload []byte) *layers.EAP {
96 eap := layers.EAP{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -070097 Code: layers.EAPCodeResponse,
98 Id: eapId,
99 Length: 22,
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700100 Type: layers.EAPTypeOTP,
101 TypeData: payload,
102 }
103 return &eap
104}
105
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700106func createEAPIdentityRequest(eapId uint8) *layers.EAP {
107 eap := layers.EAP{Code: layers.EAPCodeRequest,
108 Id: eapId,
109 Length: 9,
110 Type: layers.EAPTypeIdentity,
111 TypeData: []byte{0x75, 0x73, 0x65, 0x72}}
112 return &eap
113}
114
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700115func createEAPIdentityResponse(eapId uint8) *layers.EAP {
116 eap := layers.EAP{Code: layers.EAPCodeResponse,
117 Id: eapId,
118 Length: 9,
119 Type: layers.EAPTypeIdentity,
120 TypeData: []byte{0x75, 0x73, 0x65, 0x72}}
121 return &eap
122}
123
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700124func createEAPSuccess(eapId uint8) *layers.EAP {
125 eap := layers.EAP{
126 Code: layers.EAPCodeSuccess,
127 Id: eapId,
128 Length: 9,
129 Type: layers.EAPTypeNone,
130 TypeData: []byte{0x75, 0x73, 0x65, 0x72}}
131 return &eap
132}
133
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700134func createEAPOLPkt(eap *layers.EAP, onuId uint32, intfId uint32) []byte {
135 buffer := gopacket.NewSerializeBuffer()
136 options := gopacket.SerializeOptions{}
137
138 ethernetLayer := &layers.Ethernet{
139 SrcMAC: net.HardwareAddr{0x2e, 0x60, 0x70, 0x13, byte(intfId), byte(onuId)},
140 DstMAC: net.HardwareAddr{0x01, 0x80, 0xC2, 0x00, 0x00, 0x03},
141 EthernetType: layers.EthernetTypeEAPOL,
142 }
143
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700144 gopacket.SerializeLayers(buffer, options,
145 ethernetLayer,
146 &layers.EAPOL{Version: eapolVersion, Type: 0, Length: eap.Length},
147 eap,
148 )
149
150 bytes := buffer.Bytes()
151 return bytes
152}
153
154func extractEAP(pkt gopacket.Packet) (*layers.EAP, error) {
155 layerEAP := pkt.Layer(layers.LayerTypeEAP)
156 eap, _ := layerEAP.(*layers.EAP)
157 if eap == nil {
158 return nil, errors.New("Cannot extract EAP")
159 }
160 return eap, nil
161}
162
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700163func extractEAPOL(pkt gopacket.Packet) (*layers.EAPOL, error) {
164 layerEAPOL := pkt.Layer(layers.LayerTypeEAPOL)
165 eap, _ := layerEAPOL.(*layers.EAPOL)
166 if eap == nil {
167 return nil, errors.New("Cannot extract EAPOL")
168 }
169 return eap, nil
170}
171
172func sendEapolPktOut(client openolt.OpenoltClient, intfId uint32, onuId uint32, pkt []byte) error {
173 onuPacket := openolt.OnuPacket{
174 IntfId: intfId,
175 OnuId: onuId,
176 PortNo: onuId,
177 GemportId: 1,
178 Pkt: pkt,
179 }
180
181 if _, err := client.OnuPacketOut(context.Background(), &onuPacket); err != nil {
182 return err
183 }
184 return nil
185}
186
Matteo Scandolo075b1892019-10-07 12:11:07 -0700187func updateAuthFailed(onuId uint32, ponPortId uint32, serialNumber string, onuStateMachine *fsm.FSM) error {
188 if err := onuStateMachine.Event("auth_failed"); err != nil {
189 eapolLogger.WithFields(log.Fields{
190 "OnuId": onuId,
191 "IntfId": ponPortId,
192 "OnuSn": serialNumber,
193 }).Errorf("Error while transitioning ONU State %v", err)
194 return err
195 }
196 return nil
197}
198
Matteo Scandolo27428702019-10-11 16:21:16 -0700199func 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 -0700200
201 // send the packet (hacked together)
Matteo Scandolo075b1892019-10-07 12:11:07 -0700202 gemId, err := GetGemPortId(ponPortId, onuId)
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700203 if err != nil {
Matteo Scandolo075b1892019-10-07 12:11:07 -0700204 eapolLogger.WithFields(log.Fields{
205 "OnuId": onuId,
206 "IntfId": ponPortId,
207 "OnuSn": serialNumber,
208 }).Errorf("Can't retrieve GemPortId: %s", err)
209
210 if err := updateAuthFailed(onuId, ponPortId, serialNumber, onuStateMachine); err != nil {
211 return err
212 }
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700213 return err
214 }
215
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700216 // TODO use createEAPOLPkt
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700217 buffer := gopacket.NewSerializeBuffer()
218 options := gopacket.SerializeOptions{}
219
220 ethernetLayer := &layers.Ethernet{
Matteo Scandolo86e8ce62019-10-11 12:03:10 -0700221 SrcMAC: macAddress,
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700222 DstMAC: net.HardwareAddr{0x01, 0x80, 0xC2, 0x00, 0x00, 0x03},
223 EthernetType: layers.EthernetTypeEAPOL,
224 }
225
226 gopacket.SerializeLayers(buffer, options,
227 ethernetLayer,
228 &layers.EAPOL{Version: eapolVersion, Type: 1, Length: 0},
229 )
230
231 msg := buffer.Bytes()
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700232 // TODO end createEAPOLPkt
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700233
234 data := &openolt.Indication_PktInd{
235 PktInd: &openolt.PacketIndication{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700236 IntfType: "pon",
237 IntfId: ponPortId,
Matteo Scandolo075b1892019-10-07 12:11:07 -0700238 GemportId: uint32(gemId),
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700239 Pkt: msg,
Matteo Scandolo27428702019-10-11 16:21:16 -0700240 PortNo: portNo,
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700241 },
242 }
Matteo Scandolo075b1892019-10-07 12:11:07 -0700243
244 err = stream.Send(&openolt.Indication{Data: data})
245 if err != nil {
246 eapolLogger.WithFields(log.Fields{
247 "OnuId": onuId,
248 "IntfId": ponPortId,
249 "OnuSn": serialNumber,
250 }).Errorf("Can't send EapStart Message: %s", err)
251
252 if err := updateAuthFailed(onuId, ponPortId, serialNumber, onuStateMachine); err != nil {
253 return err
254 }
255 return err
256 }
257
Matteo Scandolo27428702019-10-11 16:21:16 -0700258 eapolLogger.WithFields(log.Fields{
259 "OnuId": onuId,
260 "IntfId": ponPortId,
261 "OnuSn": serialNumber,
262 "PortNo": portNo,
263 }).Debugf("Sent EapStart packet")
Matteo Scandolo075b1892019-10-07 12:11:07 -0700264
265 if err := onuStateMachine.Event("eap_start_sent"); err != nil {
266 eapolLogger.WithFields(log.Fields{
267 "OnuId": onuId,
268 "IntfId": ponPortId,
269 "OnuSn": serialNumber,
270 }).Errorf("Error while transitioning ONU State %v", err)
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700271 return err
272 }
273 return nil
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700274}
Matteo Scandolo075b1892019-10-07 12:11:07 -0700275
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700276func 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 -0700277
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700278 eap, eapErr := extractEAP(pkt)
279
280 eapol, eapolErr := extractEAPOL(pkt)
281
282 if eapErr != nil && eapolErr != nil {
283 log.Fatalf("Failed to Extract EAP: %v - %v", eapErr, eapolErr)
284 return
Matteo Scandolo075b1892019-10-07 12:11:07 -0700285 }
286
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700287 fields := log.Fields{}
288 if eap != nil {
289 fields = log.Fields{
290 "Code": eap.Code,
291 "Type": eap.Type,
292 "OnuId": onuId,
293 "IntfId": ponPortId,
294 "OnuSn": serialNumber,
295 }
296 } else if eapol != nil {
297 fields = log.Fields{
298 "Type": eapol.Type,
299 "OnuId": onuId,
300 "IntfId": ponPortId,
301 "OnuSn": serialNumber,
302 }
303 }
Matteo Scandolo27428702019-10-11 16:21:16 -0700304
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700305 log.WithFields(fields).Tracef("Handle Next EAPOL Packet")
306
307 if eapol != nil && eapol.Type == layers.EAPOLTypeStart {
308 identityRequest := createEAPIdentityRequest(1)
309 pkt := createEAPOLPkt(identityRequest, onuId, ponPortId)
310
311 if err := sendEapolPktOut(client, ponPortId, onuId, pkt); err != nil {
312 log.WithFields(log.Fields{
313 "OnuId": onuId,
314 "IntfId": ponPortId,
315 "OnuSn": serialNumber,
316 "error": err,
317 }).Errorf("Error while sending EAPIdentityRequest packet")
318 return
319 }
320
321 log.WithFields(log.Fields{
322 "OnuId": onuId,
323 "IntfId": ponPortId,
324 "OnuSn": serialNumber,
325 }).Infof("Sent EAPIdentityRequest packet")
326 return
327 } else if eap.Code == layers.EAPCodeRequest && eap.Type == layers.EAPTypeIdentity {
Matteo Scandolo075b1892019-10-07 12:11:07 -0700328 reseap := createEAPIdentityResponse(eap.Id)
329 pkt := createEAPOLPkt(reseap, onuId, ponPortId)
330
331 msg := bbsim.ByteMsg{
332 IntfId: ponPortId,
333 OnuId: onuId,
334 Bytes: pkt,
335 }
336
Matteo Scandolo27428702019-10-11 16:21:16 -0700337 sendEapolPktIn(msg, portNo, stream)
Matteo Scandolo075b1892019-10-07 12:11:07 -0700338 eapolLogger.WithFields(log.Fields{
339 "OnuId": onuId,
340 "IntfId": ponPortId,
341 "OnuSn": serialNumber,
Matteo Scandolo27428702019-10-11 16:21:16 -0700342 "PortNo": portNo,
343 }).Debugf("Sent EAPIdentityResponse packet")
Matteo Scandolo075b1892019-10-07 12:11:07 -0700344 if err := onuStateMachine.Event("eap_response_identity_sent"); err != nil {
345 eapolLogger.WithFields(log.Fields{
346 "OnuId": onuId,
347 "IntfId": ponPortId,
348 "OnuSn": serialNumber,
349 }).Errorf("Error while transitioning ONU State %v", err)
350 }
351
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700352 } else if eap.Code == layers.EAPCodeResponse && eap.Type == layers.EAPTypeIdentity {
353 senddata := getMD5Data(eap)
354 senddata = append([]byte{0x10}, senddata...)
355 challengeRequest := createEAPChallengeRequest(eap.Id, senddata)
356 pkt := createEAPOLPkt(challengeRequest, onuId, ponPortId)
357
358 if err := sendEapolPktOut(client, ponPortId, onuId, pkt); err != nil {
359 log.WithFields(log.Fields{
360 "OnuId": onuId,
361 "IntfId": ponPortId,
362 "OnuSn": serialNumber,
363 "error": err,
364 }).Errorf("Error while sending EAPChallengeRequest packet")
365 return
366 }
367 log.WithFields(log.Fields{
368 "OnuId": onuId,
369 "IntfId": ponPortId,
370 "OnuSn": serialNumber,
371 }).Infof("Sent EAPChallengeRequest packet")
372 return
Matteo Scandolo075b1892019-10-07 12:11:07 -0700373 } else if eap.Code == layers.EAPCodeRequest && eap.Type == layers.EAPTypeOTP {
374 senddata := getMD5Data(eap)
375 senddata = append([]byte{0x10}, senddata...)
376 sendeap := createEAPChallengeResponse(eap.Id, senddata)
377 pkt := createEAPOLPkt(sendeap, onuId, ponPortId)
378
379 msg := bbsim.ByteMsg{
380 IntfId: ponPortId,
381 OnuId: onuId,
382 Bytes: pkt,
383 }
384
Matteo Scandolo27428702019-10-11 16:21:16 -0700385 sendEapolPktIn(msg, portNo, stream)
Matteo Scandolo075b1892019-10-07 12:11:07 -0700386 eapolLogger.WithFields(log.Fields{
387 "OnuId": onuId,
388 "IntfId": ponPortId,
389 "OnuSn": serialNumber,
Matteo Scandolo27428702019-10-11 16:21:16 -0700390 "PortNo": portNo,
391 }).Debugf("Sent EAPChallengeResponse packet")
Matteo Scandolo075b1892019-10-07 12:11:07 -0700392 if err := onuStateMachine.Event("eap_response_challenge_sent"); err != nil {
393 eapolLogger.WithFields(log.Fields{
394 "OnuId": onuId,
395 "IntfId": ponPortId,
396 "OnuSn": serialNumber,
397 }).Errorf("Error while transitioning ONU State %v", err)
398 }
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700399 } else if eap.Code == layers.EAPCodeResponse && eap.Type == layers.EAPTypeOTP {
400 eapSuccess := createEAPSuccess(eap.Id)
401 pkt := createEAPOLPkt(eapSuccess, onuId, ponPortId)
402
403 if err := sendEapolPktOut(client, ponPortId, onuId, pkt); err != nil {
404 log.WithFields(log.Fields{
405 "OnuId": onuId,
406 "IntfId": ponPortId,
407 "OnuSn": serialNumber,
408 "error": err,
409 }).Errorf("Error while sending EAPSuccess packet")
410 return
411 }
412
413 log.WithFields(log.Fields{
414 "OnuId": onuId,
415 "IntfId": ponPortId,
416 "OnuSn": serialNumber,
417 }).Infof("Sent EAP Success packet")
418
419 if err := onuStateMachine.Event("send_dhcp_flow"); err != nil {
420 eapolLogger.WithFields(log.Fields{
421 "OnuId": onuId,
422 "IntfId": ponPortId,
423 "OnuSn": serialNumber,
424 }).Errorf("Error while transitioning ONU State %v", err)
425 }
Matteo Scandolo075b1892019-10-07 12:11:07 -0700426 } else if eap.Code == layers.EAPCodeSuccess && eap.Type == layers.EAPTypeNone {
427 eapolLogger.WithFields(log.Fields{
428 "OnuId": onuId,
429 "IntfId": ponPortId,
430 "OnuSn": serialNumber,
Matteo Scandolo27428702019-10-11 16:21:16 -0700431 "PortNo": portNo,
432 }).Debugf("Received EAPSuccess packet")
Matteo Scandolo075b1892019-10-07 12:11:07 -0700433 if err := onuStateMachine.Event("eap_response_success_received"); err != nil {
434 eapolLogger.WithFields(log.Fields{
435 "OnuId": onuId,
436 "IntfId": ponPortId,
437 "OnuSn": serialNumber,
438 }).Errorf("Error while transitioning ONU State %v", err)
439 }
440 eapolLogger.WithFields(log.Fields{
441 "OnuId": onuId,
442 "IntfId": ponPortId,
443 "OnuSn": serialNumber,
444 }).Infof("EAPOL State machine completed")
445 return
446 }
447}