blob: 688728caa64111082a335916d9284dfe833ed44b [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 Scandolo4f4ac792020-10-01 16:33:21 -070029 "github.com/opencord/voltha-protos/v4/go/openolt"
Matteo Scandolo47e69bb2019-08-28 15:41:12 -070030 log "github.com/sirupsen/logrus"
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 Scandolo47e69bb2019-08-28 15:41:12 -070038
Matteo Scandolo75ed5b92020-09-03 09:03:16 -070039func sendEapolPktIn(msg bbsim.ByteMsg, portNo uint32, gemid uint32, stream bbsim.Stream) error {
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -070040 // FIXME unify sendDHCPPktIn and sendEapolPktIn methods
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -070041
42 log.WithFields(log.Fields{
Shrey Baid688b4242020-07-10 20:40:10 +053043 "OnuId": msg.OnuId,
44 "IntfId": msg.IntfId,
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -070045 "GemPort": gemid,
Shrey Baid688b4242020-07-10 20:40:10 +053046 "Type": "EAPOL",
Matteo Scandoloeb6b5af2020-06-24 16:23:58 -070047 }).Trace("sending-pkt")
48
Matteo Scandolo47e69bb2019-08-28 15:41:12 -070049 data := &openolt.Indication_PktInd{PktInd: &openolt.PacketIndication{
Matteo Scandolo27428702019-10-11 16:21:16 -070050 IntfType: "pon",
51 IntfId: msg.IntfId,
52 GemportId: uint32(gemid),
53 Pkt: msg.Bytes,
54 PortNo: portNo,
Matteo Scandolo47e69bb2019-08-28 15:41:12 -070055 }}
56
57 if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
58 eapolLogger.Errorf("Fail to send EAPOL PktInd indication. %v", err)
Matteo Scandolo75ed5b92020-09-03 09:03:16 -070059 return err
Matteo Scandolo47e69bb2019-08-28 15:41:12 -070060 }
Matteo Scandolo75ed5b92020-09-03 09:03:16 -070061 return nil
Matteo Scandolo47e69bb2019-08-28 15:41:12 -070062}
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{
Matteo Scandolo4a036262020-08-17 15:56:13 -0700131 SrcMAC: net.HardwareAddr{0x2e, 0x60, byte(0), byte(intfId), byte(onuId), byte(0)},
132 DstMAC: net.HardwareAddr{0x2e, 0x60, byte(0), byte(intfId), byte(onuId), byte(0)},
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700133 EthernetType: layers.EthernetTypeEAPOL,
134 }
135
Shrey Baid688b4242020-07-10 20:40:10 +0530136 _ = gopacket.SerializeLayers(buffer, options,
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700137 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 Scandolo4a036262020-08-17 15:56:13 -0700191func 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 -0700192
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700193 // TODO use createEAPOLPkt
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700194 buffer := gopacket.NewSerializeBuffer()
195 options := gopacket.SerializeOptions{}
196
197 ethernetLayer := &layers.Ethernet{
Matteo Scandolo86e8ce62019-10-11 12:03:10 -0700198 SrcMAC: macAddress,
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700199 DstMAC: net.HardwareAddr{0x01, 0x80, 0xC2, 0x00, 0x00, 0x03},
200 EthernetType: layers.EthernetTypeEAPOL,
201 }
202
Shrey Baid688b4242020-07-10 20:40:10 +0530203 _ = gopacket.SerializeLayers(buffer, options,
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700204 ethernetLayer,
205 &layers.EAPOL{Version: eapolVersion, Type: 1, Length: 0},
206 )
207
208 msg := buffer.Bytes()
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700209 // TODO end createEAPOLPkt
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700210
211 data := &openolt.Indication_PktInd{
212 PktInd: &openolt.PacketIndication{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700213 IntfType: "pon",
214 IntfId: ponPortId,
Matteo Scandolo4a036262020-08-17 15:56:13 -0700215 GemportId: gemPort,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700216 Pkt: msg,
Matteo Scandolo27428702019-10-11 16:21:16 -0700217 PortNo: portNo,
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700218 },
219 }
Matteo Scandolo075b1892019-10-07 12:11:07 -0700220
Matteo Scandolo4a036262020-08-17 15:56:13 -0700221 err := stream.Send(&openolt.Indication{Data: data})
Matteo Scandolo075b1892019-10-07 12:11:07 -0700222 if err != nil {
223 eapolLogger.WithFields(log.Fields{
224 "OnuId": onuId,
225 "IntfId": ponPortId,
226 "OnuSn": serialNumber,
227 }).Errorf("Can't send EapStart Message: %s", err)
228
Matteo Scandolo4a036262020-08-17 15:56:13 -0700229 if err := updateAuthFailed(onuId, ponPortId, serialNumber, stateMachine); err != nil {
Matteo Scandolo075b1892019-10-07 12:11:07 -0700230 return err
231 }
232 return err
233 }
234
Matteo Scandolo27428702019-10-11 16:21:16 -0700235 eapolLogger.WithFields(log.Fields{
236 "OnuId": onuId,
237 "IntfId": ponPortId,
238 "OnuSn": serialNumber,
239 "PortNo": portNo,
240 }).Debugf("Sent EapStart packet")
Matteo Scandolo075b1892019-10-07 12:11:07 -0700241
Matteo Scandolo4a036262020-08-17 15:56:13 -0700242 if err := stateMachine.Event("eap_start_sent"); err != nil {
Matteo Scandolo075b1892019-10-07 12:11:07 -0700243 eapolLogger.WithFields(log.Fields{
244 "OnuId": onuId,
245 "IntfId": ponPortId,
246 "OnuSn": serialNumber,
247 }).Errorf("Error while transitioning ONU State %v", err)
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700248 return err
249 }
250 return nil
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700251}
Matteo Scandolo075b1892019-10-07 12:11:07 -0700252
Matteo Scandolo4a036262020-08-17 15:56:13 -0700253func 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 -0700254
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700255 eap, eapErr := extractEAP(pkt)
256
257 eapol, eapolErr := extractEAPOL(pkt)
258
259 if eapErr != nil && eapolErr != nil {
260 log.Fatalf("Failed to Extract EAP: %v - %v", eapErr, eapolErr)
261 return
Matteo Scandolo075b1892019-10-07 12:11:07 -0700262 }
263
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700264 fields := log.Fields{}
265 if eap != nil {
266 fields = log.Fields{
267 "Code": eap.Code,
268 "Type": eap.Type,
269 "OnuId": onuId,
270 "IntfId": ponPortId,
271 "OnuSn": serialNumber,
272 }
273 } else if eapol != nil {
274 fields = log.Fields{
275 "Type": eapol.Type,
276 "OnuId": onuId,
277 "IntfId": ponPortId,
278 "OnuSn": serialNumber,
279 }
280 }
Matteo Scandolo27428702019-10-11 16:21:16 -0700281
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700282 log.WithFields(fields).Tracef("Handle Next EAPOL Packet")
283
284 if eapol != nil && eapol.Type == layers.EAPOLTypeStart {
285 identityRequest := createEAPIdentityRequest(1)
286 pkt := createEAPOLPkt(identityRequest, onuId, ponPortId)
287
288 if err := sendEapolPktOut(client, ponPortId, onuId, pkt); err != nil {
289 log.WithFields(log.Fields{
290 "OnuId": onuId,
291 "IntfId": ponPortId,
292 "OnuSn": serialNumber,
293 "error": err,
294 }).Errorf("Error while sending EAPIdentityRequest packet")
295 return
296 }
297
298 log.WithFields(log.Fields{
299 "OnuId": onuId,
300 "IntfId": ponPortId,
301 "OnuSn": serialNumber,
302 }).Infof("Sent EAPIdentityRequest packet")
303 return
304 } else if eap.Code == layers.EAPCodeRequest && eap.Type == layers.EAPTypeIdentity {
Matteo Scandolo075b1892019-10-07 12:11:07 -0700305 reseap := createEAPIdentityResponse(eap.Id)
306 pkt := createEAPOLPkt(reseap, onuId, ponPortId)
307
308 msg := bbsim.ByteMsg{
309 IntfId: ponPortId,
310 OnuId: onuId,
311 Bytes: pkt,
312 }
313
Matteo Scandolo75ed5b92020-09-03 09:03:16 -0700314 if err := sendEapolPktIn(msg, portNo, gemPortId, stream); err != nil {
315 _ = stateMachine.Event("auth_failed")
316 return
317 }
Matteo Scandolo075b1892019-10-07 12:11:07 -0700318 eapolLogger.WithFields(log.Fields{
319 "OnuId": onuId,
320 "IntfId": ponPortId,
321 "OnuSn": serialNumber,
Matteo Scandolo27428702019-10-11 16:21:16 -0700322 "PortNo": portNo,
323 }).Debugf("Sent EAPIdentityResponse packet")
Matteo Scandolo4a036262020-08-17 15:56:13 -0700324 if err := stateMachine.Event("eap_response_identity_sent"); err != nil {
Matteo Scandolo075b1892019-10-07 12:11:07 -0700325 eapolLogger.WithFields(log.Fields{
326 "OnuId": onuId,
327 "IntfId": ponPortId,
328 "OnuSn": serialNumber,
329 }).Errorf("Error while transitioning ONU State %v", err)
330 }
331
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700332 } else if eap.Code == layers.EAPCodeResponse && eap.Type == layers.EAPTypeIdentity {
333 senddata := getMD5Data(eap)
334 senddata = append([]byte{0x10}, senddata...)
335 challengeRequest := createEAPChallengeRequest(eap.Id, senddata)
336 pkt := createEAPOLPkt(challengeRequest, onuId, ponPortId)
337
338 if err := sendEapolPktOut(client, ponPortId, onuId, pkt); err != nil {
339 log.WithFields(log.Fields{
340 "OnuId": onuId,
341 "IntfId": ponPortId,
342 "OnuSn": serialNumber,
343 "error": err,
344 }).Errorf("Error while sending EAPChallengeRequest packet")
345 return
346 }
347 log.WithFields(log.Fields{
348 "OnuId": onuId,
349 "IntfId": ponPortId,
350 "OnuSn": serialNumber,
351 }).Infof("Sent EAPChallengeRequest packet")
352 return
Matteo Scandolo075b1892019-10-07 12:11:07 -0700353 } else if eap.Code == layers.EAPCodeRequest && eap.Type == layers.EAPTypeOTP {
354 senddata := getMD5Data(eap)
355 senddata = append([]byte{0x10}, senddata...)
356 sendeap := createEAPChallengeResponse(eap.Id, senddata)
357 pkt := createEAPOLPkt(sendeap, onuId, ponPortId)
358
359 msg := bbsim.ByteMsg{
360 IntfId: ponPortId,
361 OnuId: onuId,
362 Bytes: pkt,
363 }
364
Matteo Scandolo75ed5b92020-09-03 09:03:16 -0700365 if err := sendEapolPktIn(msg, portNo, gemPortId, stream); err != nil {
366 _ = stateMachine.Event("auth_failed")
367 return
368 }
Matteo Scandolo075b1892019-10-07 12:11:07 -0700369 eapolLogger.WithFields(log.Fields{
370 "OnuId": onuId,
371 "IntfId": ponPortId,
372 "OnuSn": serialNumber,
Matteo Scandolo27428702019-10-11 16:21:16 -0700373 "PortNo": portNo,
374 }).Debugf("Sent EAPChallengeResponse packet")
Matteo Scandolo4a036262020-08-17 15:56:13 -0700375 if err := stateMachine.Event("eap_response_challenge_sent"); err != nil {
Matteo Scandolo075b1892019-10-07 12:11:07 -0700376 eapolLogger.WithFields(log.Fields{
377 "OnuId": onuId,
378 "IntfId": ponPortId,
379 "OnuSn": serialNumber,
380 }).Errorf("Error while transitioning ONU State %v", err)
381 }
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700382 } else if eap.Code == layers.EAPCodeResponse && eap.Type == layers.EAPTypeOTP {
383 eapSuccess := createEAPSuccess(eap.Id)
384 pkt := createEAPOLPkt(eapSuccess, onuId, ponPortId)
385
386 if err := sendEapolPktOut(client, ponPortId, onuId, pkt); err != nil {
387 log.WithFields(log.Fields{
388 "OnuId": onuId,
389 "IntfId": ponPortId,
390 "OnuSn": serialNumber,
391 "error": err,
392 }).Errorf("Error while sending EAPSuccess packet")
393 return
394 }
395
396 log.WithFields(log.Fields{
397 "OnuId": onuId,
398 "IntfId": ponPortId,
399 "OnuSn": serialNumber,
400 }).Infof("Sent EAP Success packet")
401
Matteo Scandolo4a036262020-08-17 15:56:13 -0700402 if err := stateMachine.Event("send_dhcp_flow"); err != nil {
Matteo Scandolo40e067f2019-10-16 16:59:41 -0700403 eapolLogger.WithFields(log.Fields{
404 "OnuId": onuId,
405 "IntfId": ponPortId,
406 "OnuSn": serialNumber,
407 }).Errorf("Error while transitioning ONU State %v", err)
408 }
Matteo Scandolo075b1892019-10-07 12:11:07 -0700409 } else if eap.Code == layers.EAPCodeSuccess && eap.Type == layers.EAPTypeNone {
410 eapolLogger.WithFields(log.Fields{
411 "OnuId": onuId,
412 "IntfId": ponPortId,
413 "OnuSn": serialNumber,
Matteo Scandolo27428702019-10-11 16:21:16 -0700414 "PortNo": portNo,
415 }).Debugf("Received EAPSuccess packet")
Matteo Scandolo4a036262020-08-17 15:56:13 -0700416 if err := stateMachine.Event("eap_response_success_received"); err != nil {
Matteo Scandolo075b1892019-10-07 12:11:07 -0700417 eapolLogger.WithFields(log.Fields{
418 "OnuId": onuId,
419 "IntfId": ponPortId,
420 "OnuSn": serialNumber,
421 }).Errorf("Error while transitioning ONU State %v", err)
422 }
423 eapolLogger.WithFields(log.Fields{
424 "OnuId": onuId,
425 "IntfId": ponPortId,
426 "OnuSn": serialNumber,
427 }).Infof("EAPOL State machine completed")
428 return
429 }
430}