blob: 5595d5b0dbf3098518fb3e76ee0c48257aa26ae5 [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 Scandolo4a036262020-08-17 15:56:13 -070041func sendEapolPktIn(msg bbsim.ByteMsg, portNo uint32, gemid uint32, stream bbsim.Stream) {
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -070042 // FIXME unify sendDHCPPktIn and sendEapolPktIn methods
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -070043
44 log.WithFields(log.Fields{
Shrey Baid688b4242020-07-10 20:40:10 +053045 "OnuId": msg.OnuId,
46 "IntfId": msg.IntfId,
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -070047 "GemPort": gemid,
Shrey Baid688b4242020-07-10 20:40:10 +053048 "Type": "EAPOL",
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -070049 }).Trace("sending-pkt")
50
Matteo Scandolo47e69bb2019-08-28 15:41:12 -070051 data := &openolt.Indication_PktInd{PktInd: &openolt.PacketIndication{
Matteo Scandolo27428702019-10-11 16:21:16 -070052 IntfType: "pon",
53 IntfId: msg.IntfId,
54 GemportId: uint32(gemid),
55 Pkt: msg.Bytes,
56 PortNo: portNo,
Matteo Scandolo47e69bb2019-08-28 15:41:12 -070057 }}
58
59 if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
60 eapolLogger.Errorf("Fail to send EAPOL PktInd indication. %v", err)
61 return
62 }
63}
64
65func getMD5Data(eap *layers.EAP) []byte {
66 i := byte(eap.Id)
67 C := []byte(eap.BaseLayer.Contents)[6:]
68 P := []byte{i, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64} // "password"
69 data := md5.Sum(append(P, C...))
70 ret := make([]byte, 16)
71 for j := 0; j < 16; j++ {
72 ret[j] = data[j]
73 }
74 return ret
75}
76
Matteo Scandolo40e067f2019-10-16 16:59:41 -070077func createEAPChallengeRequest(eapId uint8, payload []byte) *layers.EAP {
78 eap := layers.EAP{
79 Code: layers.EAPCodeRequest,
80 Id: eapId,
81 Length: 22,
82 Type: layers.EAPTypeOTP,
83 TypeData: payload,
84 }
85 return &eap
86}
87
Matteo Scandolo47e69bb2019-08-28 15:41:12 -070088func createEAPChallengeResponse(eapId uint8, payload []byte) *layers.EAP {
89 eap := layers.EAP{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -070090 Code: layers.EAPCodeResponse,
91 Id: eapId,
92 Length: 22,
Matteo Scandolo47e69bb2019-08-28 15:41:12 -070093 Type: layers.EAPTypeOTP,
94 TypeData: payload,
95 }
96 return &eap
97}
98
Matteo Scandolo40e067f2019-10-16 16:59:41 -070099func createEAPIdentityRequest(eapId uint8) *layers.EAP {
100 eap := layers.EAP{Code: layers.EAPCodeRequest,
101 Id: eapId,
102 Length: 9,
103 Type: layers.EAPTypeIdentity,
104 TypeData: []byte{0x75, 0x73, 0x65, 0x72}}
105 return &eap
106}
107
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700108func createEAPIdentityResponse(eapId uint8) *layers.EAP {
109 eap := layers.EAP{Code: layers.EAPCodeResponse,
110 Id: eapId,
111 Length: 9,
112 Type: layers.EAPTypeIdentity,
113 TypeData: []byte{0x75, 0x73, 0x65, 0x72}}
114 return &eap
115}
116
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700117func createEAPSuccess(eapId uint8) *layers.EAP {
118 eap := layers.EAP{
119 Code: layers.EAPCodeSuccess,
120 Id: eapId,
121 Length: 9,
122 Type: layers.EAPTypeNone,
123 TypeData: []byte{0x75, 0x73, 0x65, 0x72}}
124 return &eap
125}
126
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700127func createEAPOLPkt(eap *layers.EAP, onuId uint32, intfId uint32) []byte {
128 buffer := gopacket.NewSerializeBuffer()
129 options := gopacket.SerializeOptions{}
130
131 ethernetLayer := &layers.Ethernet{
Matteo Scandolo4a036262020-08-17 15:56:13 -0700132 SrcMAC: net.HardwareAddr{0x2e, 0x60, byte(0), byte(intfId), byte(onuId), byte(0)},
133 DstMAC: net.HardwareAddr{0x2e, 0x60, byte(0), byte(intfId), byte(onuId), byte(0)},
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700134 EthernetType: layers.EthernetTypeEAPOL,
135 }
136
Shrey Baid688b4242020-07-10 20:40:10 +0530137 _ = gopacket.SerializeLayers(buffer, options,
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700138 ethernetLayer,
139 &layers.EAPOL{Version: eapolVersion, Type: 0, Length: eap.Length},
140 eap,
141 )
142
143 bytes := buffer.Bytes()
144 return bytes
145}
146
147func extractEAP(pkt gopacket.Packet) (*layers.EAP, error) {
148 layerEAP := pkt.Layer(layers.LayerTypeEAP)
149 eap, _ := layerEAP.(*layers.EAP)
150 if eap == nil {
151 return nil, errors.New("Cannot extract EAP")
152 }
153 return eap, nil
154}
155
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700156func extractEAPOL(pkt gopacket.Packet) (*layers.EAPOL, error) {
157 layerEAPOL := pkt.Layer(layers.LayerTypeEAPOL)
158 eap, _ := layerEAPOL.(*layers.EAPOL)
159 if eap == nil {
160 return nil, errors.New("Cannot extract EAPOL")
161 }
162 return eap, nil
163}
164
165func sendEapolPktOut(client openolt.OpenoltClient, intfId uint32, onuId uint32, pkt []byte) error {
166 onuPacket := openolt.OnuPacket{
167 IntfId: intfId,
168 OnuId: onuId,
169 PortNo: onuId,
170 GemportId: 1,
171 Pkt: pkt,
172 }
173
174 if _, err := client.OnuPacketOut(context.Background(), &onuPacket); err != nil {
175 return err
176 }
177 return nil
178}
179
Matteo Scandolo075b1892019-10-07 12:11:07 -0700180func updateAuthFailed(onuId uint32, ponPortId uint32, serialNumber string, onuStateMachine *fsm.FSM) error {
181 if err := onuStateMachine.Event("auth_failed"); err != nil {
182 eapolLogger.WithFields(log.Fields{
183 "OnuId": onuId,
184 "IntfId": ponPortId,
185 "OnuSn": serialNumber,
186 }).Errorf("Error while transitioning ONU State %v", err)
187 return err
188 }
189 return nil
190}
191
Matteo Scandolo4a036262020-08-17 15:56:13 -0700192func SendEapStart(onuId uint32, ponPortId uint32, serialNumber string, portNo uint32, macAddress net.HardwareAddr, gemPort uint32, stateMachine *fsm.FSM, stream bbsim.Stream) error {
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700193
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700194 // TODO use createEAPOLPkt
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700195 buffer := gopacket.NewSerializeBuffer()
196 options := gopacket.SerializeOptions{}
197
198 ethernetLayer := &layers.Ethernet{
Matteo Scandolo86e8ce62019-10-11 12:03:10 -0700199 SrcMAC: macAddress,
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700200 DstMAC: net.HardwareAddr{0x01, 0x80, 0xC2, 0x00, 0x00, 0x03},
201 EthernetType: layers.EthernetTypeEAPOL,
202 }
203
Shrey Baid688b4242020-07-10 20:40:10 +0530204 _ = gopacket.SerializeLayers(buffer, options,
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700205 ethernetLayer,
206 &layers.EAPOL{Version: eapolVersion, Type: 1, Length: 0},
207 )
208
209 msg := buffer.Bytes()
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700210 // TODO end createEAPOLPkt
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700211
212 data := &openolt.Indication_PktInd{
213 PktInd: &openolt.PacketIndication{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700214 IntfType: "pon",
215 IntfId: ponPortId,
Matteo Scandolo4a036262020-08-17 15:56:13 -0700216 GemportId: gemPort,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700217 Pkt: msg,
Matteo Scandolo27428702019-10-11 16:21:16 -0700218 PortNo: portNo,
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700219 },
220 }
Matteo Scandolo075b1892019-10-07 12:11:07 -0700221
Matteo Scandolo4a036262020-08-17 15:56:13 -0700222 err := stream.Send(&openolt.Indication{Data: data})
Matteo Scandolo075b1892019-10-07 12:11:07 -0700223 if err != nil {
224 eapolLogger.WithFields(log.Fields{
225 "OnuId": onuId,
226 "IntfId": ponPortId,
227 "OnuSn": serialNumber,
228 }).Errorf("Can't send EapStart Message: %s", err)
229
Matteo Scandolo4a036262020-08-17 15:56:13 -0700230 if err := updateAuthFailed(onuId, ponPortId, serialNumber, stateMachine); err != nil {
Matteo Scandolo075b1892019-10-07 12:11:07 -0700231 return err
232 }
233 return err
234 }
235
Matteo Scandolo27428702019-10-11 16:21:16 -0700236 eapolLogger.WithFields(log.Fields{
237 "OnuId": onuId,
238 "IntfId": ponPortId,
239 "OnuSn": serialNumber,
240 "PortNo": portNo,
241 }).Debugf("Sent EapStart packet")
Matteo Scandolo075b1892019-10-07 12:11:07 -0700242
Matteo Scandolo4a036262020-08-17 15:56:13 -0700243 if err := stateMachine.Event("eap_start_sent"); err != nil {
Matteo Scandolo075b1892019-10-07 12:11:07 -0700244 eapolLogger.WithFields(log.Fields{
245 "OnuId": onuId,
246 "IntfId": ponPortId,
247 "OnuSn": serialNumber,
248 }).Errorf("Error while transitioning ONU State %v", err)
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700249 return err
250 }
251 return nil
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700252}
Matteo Scandolo075b1892019-10-07 12:11:07 -0700253
Matteo Scandolo4a036262020-08-17 15:56:13 -0700254func HandleNextPacket(onuId uint32, ponPortId uint32, gemPortId uint32, serialNumber string, portNo uint32, stateMachine *fsm.FSM, pkt gopacket.Packet, stream bbsim.Stream, client openolt.OpenoltClient) {
Matteo Scandolo27428702019-10-11 16:21:16 -0700255
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700256 eap, eapErr := extractEAP(pkt)
257
258 eapol, eapolErr := extractEAPOL(pkt)
259
260 if eapErr != nil && eapolErr != nil {
261 log.Fatalf("Failed to Extract EAP: %v - %v", eapErr, eapolErr)
262 return
Matteo Scandolo075b1892019-10-07 12:11:07 -0700263 }
264
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700265 fields := log.Fields{}
266 if eap != nil {
267 fields = log.Fields{
268 "Code": eap.Code,
269 "Type": eap.Type,
270 "OnuId": onuId,
271 "IntfId": ponPortId,
272 "OnuSn": serialNumber,
273 }
274 } else if eapol != nil {
275 fields = log.Fields{
276 "Type": eapol.Type,
277 "OnuId": onuId,
278 "IntfId": ponPortId,
279 "OnuSn": serialNumber,
280 }
281 }
Matteo Scandolo27428702019-10-11 16:21:16 -0700282
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700283 log.WithFields(fields).Tracef("Handle Next EAPOL Packet")
284
285 if eapol != nil && eapol.Type == layers.EAPOLTypeStart {
286 identityRequest := createEAPIdentityRequest(1)
287 pkt := createEAPOLPkt(identityRequest, onuId, ponPortId)
288
289 if err := sendEapolPktOut(client, ponPortId, onuId, pkt); err != nil {
290 log.WithFields(log.Fields{
291 "OnuId": onuId,
292 "IntfId": ponPortId,
293 "OnuSn": serialNumber,
294 "error": err,
295 }).Errorf("Error while sending EAPIdentityRequest packet")
296 return
297 }
298
299 log.WithFields(log.Fields{
300 "OnuId": onuId,
301 "IntfId": ponPortId,
302 "OnuSn": serialNumber,
303 }).Infof("Sent EAPIdentityRequest packet")
304 return
305 } else if eap.Code == layers.EAPCodeRequest && eap.Type == layers.EAPTypeIdentity {
Matteo Scandolo075b1892019-10-07 12:11:07 -0700306 reseap := createEAPIdentityResponse(eap.Id)
307 pkt := createEAPOLPkt(reseap, onuId, ponPortId)
308
309 msg := bbsim.ByteMsg{
310 IntfId: ponPortId,
311 OnuId: onuId,
312 Bytes: pkt,
313 }
314
Matteo Scandolo4a036262020-08-17 15:56:13 -0700315 sendEapolPktIn(msg, portNo, gemPortId, stream)
Matteo Scandolo075b1892019-10-07 12:11:07 -0700316 eapolLogger.WithFields(log.Fields{
317 "OnuId": onuId,
318 "IntfId": ponPortId,
319 "OnuSn": serialNumber,
Matteo Scandolo27428702019-10-11 16:21:16 -0700320 "PortNo": portNo,
321 }).Debugf("Sent EAPIdentityResponse packet")
Matteo Scandolo4a036262020-08-17 15:56:13 -0700322 if err := stateMachine.Event("eap_response_identity_sent"); err != nil {
Matteo Scandolo075b1892019-10-07 12:11:07 -0700323 eapolLogger.WithFields(log.Fields{
324 "OnuId": onuId,
325 "IntfId": ponPortId,
326 "OnuSn": serialNumber,
327 }).Errorf("Error while transitioning ONU State %v", err)
328 }
329
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700330 } else if eap.Code == layers.EAPCodeResponse && eap.Type == layers.EAPTypeIdentity {
331 senddata := getMD5Data(eap)
332 senddata = append([]byte{0x10}, senddata...)
333 challengeRequest := createEAPChallengeRequest(eap.Id, senddata)
334 pkt := createEAPOLPkt(challengeRequest, onuId, ponPortId)
335
336 if err := sendEapolPktOut(client, ponPortId, onuId, pkt); err != nil {
337 log.WithFields(log.Fields{
338 "OnuId": onuId,
339 "IntfId": ponPortId,
340 "OnuSn": serialNumber,
341 "error": err,
342 }).Errorf("Error while sending EAPChallengeRequest packet")
343 return
344 }
345 log.WithFields(log.Fields{
346 "OnuId": onuId,
347 "IntfId": ponPortId,
348 "OnuSn": serialNumber,
349 }).Infof("Sent EAPChallengeRequest packet")
350 return
Matteo Scandolo075b1892019-10-07 12:11:07 -0700351 } else if eap.Code == layers.EAPCodeRequest && eap.Type == layers.EAPTypeOTP {
352 senddata := getMD5Data(eap)
353 senddata = append([]byte{0x10}, senddata...)
354 sendeap := createEAPChallengeResponse(eap.Id, senddata)
355 pkt := createEAPOLPkt(sendeap, onuId, ponPortId)
356
357 msg := bbsim.ByteMsg{
358 IntfId: ponPortId,
359 OnuId: onuId,
360 Bytes: pkt,
361 }
362
Matteo Scandolo4a036262020-08-17 15:56:13 -0700363 sendEapolPktIn(msg, portNo, gemPortId, stream)
Matteo Scandolo075b1892019-10-07 12:11:07 -0700364 eapolLogger.WithFields(log.Fields{
365 "OnuId": onuId,
366 "IntfId": ponPortId,
367 "OnuSn": serialNumber,
Matteo Scandolo27428702019-10-11 16:21:16 -0700368 "PortNo": portNo,
369 }).Debugf("Sent EAPChallengeResponse packet")
Matteo Scandolo4a036262020-08-17 15:56:13 -0700370 if err := stateMachine.Event("eap_response_challenge_sent"); err != nil {
Matteo Scandolo075b1892019-10-07 12:11:07 -0700371 eapolLogger.WithFields(log.Fields{
372 "OnuId": onuId,
373 "IntfId": ponPortId,
374 "OnuSn": serialNumber,
375 }).Errorf("Error while transitioning ONU State %v", err)
376 }
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700377 } else if eap.Code == layers.EAPCodeResponse && eap.Type == layers.EAPTypeOTP {
378 eapSuccess := createEAPSuccess(eap.Id)
379 pkt := createEAPOLPkt(eapSuccess, onuId, ponPortId)
380
381 if err := sendEapolPktOut(client, ponPortId, onuId, pkt); err != nil {
382 log.WithFields(log.Fields{
383 "OnuId": onuId,
384 "IntfId": ponPortId,
385 "OnuSn": serialNumber,
386 "error": err,
387 }).Errorf("Error while sending EAPSuccess packet")
388 return
389 }
390
391 log.WithFields(log.Fields{
392 "OnuId": onuId,
393 "IntfId": ponPortId,
394 "OnuSn": serialNumber,
395 }).Infof("Sent EAP Success packet")
396
Matteo Scandolo4a036262020-08-17 15:56:13 -0700397 if err := stateMachine.Event("send_dhcp_flow"); err != nil {
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700398 eapolLogger.WithFields(log.Fields{
399 "OnuId": onuId,
400 "IntfId": ponPortId,
401 "OnuSn": serialNumber,
402 }).Errorf("Error while transitioning ONU State %v", err)
403 }
Matteo Scandolo075b1892019-10-07 12:11:07 -0700404 } else if eap.Code == layers.EAPCodeSuccess && eap.Type == layers.EAPTypeNone {
405 eapolLogger.WithFields(log.Fields{
406 "OnuId": onuId,
407 "IntfId": ponPortId,
408 "OnuSn": serialNumber,
Matteo Scandolo27428702019-10-11 16:21:16 -0700409 "PortNo": portNo,
410 }).Debugf("Received EAPSuccess packet")
Matteo Scandolo4a036262020-08-17 15:56:13 -0700411 if err := stateMachine.Event("eap_response_success_received"); err != nil {
Matteo Scandolo075b1892019-10-07 12:11:07 -0700412 eapolLogger.WithFields(log.Fields{
413 "OnuId": onuId,
414 "IntfId": ponPortId,
415 "OnuSn": serialNumber,
416 }).Errorf("Error while transitioning ONU State %v", err)
417 }
418 eapolLogger.WithFields(log.Fields{
419 "OnuId": onuId,
420 "IntfId": ponPortId,
421 "OnuSn": serialNumber,
422 }).Infof("EAPOL State machine completed")
423 return
424 }
425}