blob: 3477a62616d1a27b257f4f4350d187b0475ba36e [file] [log] [blame]
Matteo Scandolo11006992019-08-28 11:29:46 -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
Matteo Scandolo4747d292019-08-05 11:50:18 -070017package devices
18
19import (
Matteo Scandolo3bc73742019-08-20 14:04:04 -070020 "fmt"
Matteo Scandolo3bc73742019-08-20 14:04:04 -070021 "github.com/google/gopacket/layers"
Matteo Scandolo4747d292019-08-05 11:50:18 -070022 "github.com/looplab/fsm"
Matteo Scandolo075b1892019-10-07 12:11:07 -070023 "github.com/opencord/bbsim/internal/bbsim/packetHandlers"
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -070024 "github.com/opencord/bbsim/internal/bbsim/responders/dhcp"
25 "github.com/opencord/bbsim/internal/bbsim/responders/eapol"
26 bbsim "github.com/opencord/bbsim/internal/bbsim/types"
Matteo Scandoloc559ef12019-08-20 13:24:21 -070027 omci "github.com/opencord/omci-sim"
Matteo Scandolo3bc73742019-08-20 14:04:04 -070028 "github.com/opencord/voltha-protos/go/openolt"
Matteo Scandolo4747d292019-08-05 11:50:18 -070029 log "github.com/sirupsen/logrus"
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -070030 "net"
Matteo Scandolo4747d292019-08-05 11:50:18 -070031)
32
Matteo Scandolo9a3518c2019-08-13 14:36:01 -070033var onuLogger = log.WithFields(log.Fields{
34 "module": "ONU",
35})
36
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -070037func CreateONU(olt OltDevice, pon PonPort, id uint32, sTag int, cTag int) Onu {
Matteo Scandolo4747d292019-08-05 11:50:18 -070038
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -070039 o := Onu{
40 ID: id,
41 PonPortID: pon.ID,
42 PonPort: pon,
43 STag: sTag,
44 CTag: cTag,
45 HwAddress: net.HardwareAddr{0x2e, 0x60, 0x70, 0x13, byte(pon.ID), byte(id)},
Matteo Scandolo10f965c2019-09-24 10:40:46 -070046 // NOTE can we combine everything in a single Channel?
47 Channel: make(chan Message, 2048),
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -070048 eapolPktOutCh: make(chan *bbsim.ByteMsg, 1024),
49 dhcpPktOutCh: make(chan *bbsim.ByteMsg, 1024),
50 }
51 o.SerialNumber = o.NewSN(olt.ID, pon.ID, o.ID)
Matteo Scandolo9a3518c2019-08-13 14:36:01 -070052
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -070053 // NOTE this state machine is used to track the operational
54 // state as requested by VOLTHA
55 o.OperState = getOperStateFSM(func(e *fsm.Event) {
56 onuLogger.WithFields(log.Fields{
57 "ID": o.ID,
58 }).Debugf("Changing ONU OperState from %s to %s", e.Src, e.Dst)
59 })
60
61 // NOTE this state machine is used to activate the OMCI, EAPOL and DHCP clients
62 o.InternalState = fsm.NewFSM(
63 "created",
64 fsm.Events{
Matteo Scandolo10f965c2019-09-24 10:40:46 -070065 // DEVICE Lifecycle
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -070066 {Name: "discover", Src: []string{"created"}, Dst: "discovered"},
Matteo Scandolo10f965c2019-09-24 10:40:46 -070067 {Name: "enable", Src: []string{"discovered", "disabled"}, Dst: "enabled"},
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -070068 {Name: "receive_eapol_flow", Src: []string{"enabled", "gem_port_added"}, Dst: "eapol_flow_received"},
69 {Name: "add_gem_port", Src: []string{"enabled", "eapol_flow_received"}, Dst: "gem_port_added"},
Matteo Scandolo10f965c2019-09-24 10:40:46 -070070 // NOTE should disabled state be diffente for oper_disabled (emulating an error) and admin_disabled (received a disabled call via VOLTHA)?
71 {Name: "disable", Src: []string{"eap_response_success_received", "auth_failed", "dhcp_ack_received", "dhcp_failed"}, Dst: "disabled"},
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -070072 // EAPOL
73 {Name: "start_auth", Src: []string{"eapol_flow_received", "gem_port_added"}, Dst: "auth_started"},
74 {Name: "eap_start_sent", Src: []string{"auth_started"}, Dst: "eap_start_sent"},
75 {Name: "eap_response_identity_sent", Src: []string{"eap_start_sent"}, Dst: "eap_response_identity_sent"},
76 {Name: "eap_response_challenge_sent", Src: []string{"eap_response_identity_sent"}, Dst: "eap_response_challenge_sent"},
77 {Name: "eap_response_success_received", Src: []string{"eap_response_challenge_sent"}, Dst: "eap_response_success_received"},
78 {Name: "auth_failed", Src: []string{"auth_started", "eap_start_sent", "eap_response_identity_sent", "eap_response_challenge_sent"}, Dst: "auth_failed"},
79 // DHCP
80 {Name: "start_dhcp", Src: []string{"eap_response_success_received"}, Dst: "dhcp_started"},
81 {Name: "dhcp_discovery_sent", Src: []string{"dhcp_started"}, Dst: "dhcp_discovery_sent"},
82 {Name: "dhcp_request_sent", Src: []string{"dhcp_discovery_sent"}, Dst: "dhcp_request_sent"},
83 {Name: "dhcp_ack_received", Src: []string{"dhcp_request_sent"}, Dst: "dhcp_ack_received"},
84 {Name: "dhcp_failed", Src: []string{"dhcp_started", "dhcp_discovery_sent", "dhcp_request_sent"}, Dst: "dhcp_failed"},
85 },
86 fsm.Callbacks{
87 "enter_state": func(e *fsm.Event) {
88 o.logStateChange(e.Src, e.Dst)
Matteo Scandolo4747d292019-08-05 11:50:18 -070089 },
Matteo Scandolo10f965c2019-09-24 10:40:46 -070090 "enter_enabled": func(event *fsm.Event) {
91 msg := Message{
92 Type: OnuIndication,
93 Data: OnuIndicationMessage{
94 OnuSN: o.SerialNumber,
95 PonPortID: o.PonPortID,
96 OperState: UP,
97 },
98 }
99 o.Channel <- msg
100 },
101 "enter_disabled": func(event *fsm.Event) {
102 msg := Message{
103 Type: OnuIndication,
104 Data: OnuIndicationMessage{
105 OnuSN: o.SerialNumber,
106 PonPortID: o.PonPortID,
107 OperState: DOWN,
108 },
109 }
110 o.Channel <- msg
111 },
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700112 "enter_auth_started": func(e *fsm.Event) {
113 o.logStateChange(e.Src, e.Dst)
114 msg := Message{
115 Type: StartEAPOL,
116 Data: PacketMessage{
117 PonPortID: o.PonPortID,
118 OnuID: o.ID,
119 },
120 }
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700121 o.Channel <- msg
Matteo Scandolo4747d292019-08-05 11:50:18 -0700122 },
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700123 "enter_auth_failed": func(e *fsm.Event) {
124 onuLogger.WithFields(log.Fields{
125 "OnuId": o.ID,
126 "IntfId": o.PonPortID,
127 "OnuSn": o.Sn(),
128 }).Errorf("ONU failed to authenticate!")
129 },
130 "enter_dhcp_started": func(e *fsm.Event) {
131 msg := Message{
132 Type: StartDHCP,
133 Data: PacketMessage{
134 PonPortID: o.PonPortID,
135 OnuID: o.ID,
136 },
137 }
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700138 o.Channel <- msg
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700139 },
140 "enter_dhcp_failed": func(e *fsm.Event) {
141 onuLogger.WithFields(log.Fields{
142 "OnuId": o.ID,
143 "IntfId": o.PonPortID,
144 "OnuSn": o.Sn(),
145 }).Errorf("ONU failed to DHCP!")
146 },
147 },
148 )
149 return o
Matteo Scandolo4747d292019-08-05 11:50:18 -0700150}
151
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700152func (o Onu) logStateChange(src string, dst string) {
153 onuLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700154 "OnuId": o.ID,
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700155 "IntfId": o.PonPortID,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700156 "OnuSn": o.Sn(),
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700157 }).Debugf("Changing ONU InternalState from %s to %s", src, dst)
158}
159
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700160func (o Onu) processOnuMessages(stream openolt.Openolt_EnableIndicationServer) {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700161 onuLogger.WithFields(log.Fields{
Matteo Scandolo4747d292019-08-05 11:50:18 -0700162 "onuID": o.ID,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700163 "onuSN": o.Sn(),
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700164 }).Debug("Started ONU Indication Channel")
165
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700166 for message := range o.Channel {
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700167 onuLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700168 "onuID": o.ID,
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700169 "onuSN": o.Sn(),
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700170 "messageType": message.Type,
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700171 }).Tracef("Received message on ONU Channel")
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700172
173 switch message.Type {
174 case OnuDiscIndication:
175 msg, _ := message.Data.(OnuDiscIndicationMessage)
176 o.sendOnuDiscIndication(msg, stream)
177 case OnuIndication:
178 msg, _ := message.Data.(OnuIndicationMessage)
179 o.sendOnuIndication(msg, stream)
180 case OMCI:
Matteo Scandoloc559ef12019-08-20 13:24:21 -0700181 msg, _ := message.Data.(OmciMessage)
Matteo Scandoloc559ef12019-08-20 13:24:21 -0700182 o.handleOmciMessage(msg, stream)
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700183 case FlowUpdate:
184 msg, _ := message.Data.(OnuFlowUpdateMessage)
185 o.handleFlowUpdate(msg, stream)
186 case StartEAPOL:
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700187 log.Infof("Receive StartEAPOL message on ONU Channel")
Matteo Scandolo075b1892019-10-07 12:11:07 -0700188 eapol.SendEapStart(o.ID, o.PonPortID, o.Sn(), o.InternalState, stream)
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700189 case StartDHCP:
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700190 log.Infof("Receive StartDHCP message on ONU Channel")
Matteo Scandolo075b1892019-10-07 12:11:07 -0700191 dhcp.SendDHCPDiscovery(o.PonPortID, o.ID, o.Sn(), o.InternalState, o.HwAddress, o.CTag, stream)
192 case OnuPacketOut:
193 msg, _ := message.Data.(OnuPacketOutMessage)
194 pkt := msg.Packet
195 etherType := pkt.Layer(layers.LayerTypeEthernet).(*layers.Ethernet).EthernetType
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700196
Matteo Scandolo075b1892019-10-07 12:11:07 -0700197 if etherType == layers.EthernetTypeEAPOL {
198 eapol.HandleNextPacket(msg.OnuId, msg.IntfId, o.Sn(), o.InternalState, msg.Packet, stream)
199 } else if packetHandlers.IsDhcpPacket(pkt) {
200 // NOTE here we receive packets going from the DHCP Server to the ONU
201 // for now we expect them to be double-tagged, but ideally the should be single tagged
202 dhcp.HandleNextPacket(o.ID, o.PonPortID, o.Sn(), o.HwAddress, o.CTag, o.InternalState, msg.Packet, stream)
203 }
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700204 case DyingGaspIndication:
205 msg, _ := message.Data.(DyingGaspIndicationMessage)
206 o.sendDyingGaspInd(msg, stream)
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700207 default:
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700208 onuLogger.Warnf("Received unknown message data %v for type %v in OLT Channel", message.Data, message.Type)
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700209 }
210 }
Matteo Scandolo4747d292019-08-05 11:50:18 -0700211}
212
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700213func (o Onu) processOmciMessages(stream openolt.Openolt_EnableIndicationServer) {
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700214 ch := omci.GetChannel()
215
216 onuLogger.WithFields(log.Fields{
217 "onuID": o.ID,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700218 "onuSN": o.Sn(),
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700219 }).Debug("Started OMCI Indication Channel")
220
221 for message := range ch {
222 switch message.Type {
223 case omci.GemPortAdded:
224 log.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700225 "OnuId": message.Data.OnuId,
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700226 "IntfId": message.Data.IntfId,
227 }).Infof("GemPort Added")
228
229 // NOTE if we receive the GemPort but we don't have EAPOL flows
230 // go an intermediate state, otherwise start auth
231 if o.InternalState.Is("enabled") {
232 if err := o.InternalState.Event("add_gem_port"); err != nil {
233 log.Errorf("Can't go to gem_port_added: %v", err)
234 }
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700235 } else if o.InternalState.Is("eapol_flow_received") {
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700236 if err := o.InternalState.Event("start_auth"); err != nil {
237 log.Errorf("Can't go to auth_started: %v", err)
238 }
239 }
240 }
241 }
242}
243
Matteo Scandolo4747d292019-08-05 11:50:18 -0700244func (o Onu) NewSN(oltid int, intfid uint32, onuid uint32) *openolt.SerialNumber {
245
246 sn := new(openolt.SerialNumber)
247
Matteo Scandolo47e69bb2019-08-28 15:41:12 -0700248 //sn = new(openolt.SerialNumber)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700249 sn.VendorId = []byte("BBSM")
250 sn.VendorSpecific = []byte{0, byte(oltid % 256), byte(intfid), byte(onuid)}
251
252 return sn
253}
254
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700255// NOTE handle_/process methods can change the ONU internal state as they are receiving messages
256// send method should not change the ONU state
257
258func (o Onu) sendDyingGaspInd(msg DyingGaspIndicationMessage, stream openolt.Openolt_EnableIndicationServer) error {
259 alarmData := &openolt.AlarmIndication_DyingGaspInd{
260 DyingGaspInd: &openolt.DyingGaspIndication{
261 IntfId: msg.PonPortID,
262 OnuId: msg.OnuID,
263 Status: "on",
264 },
265 }
266 data := &openolt.Indication_AlarmInd{AlarmInd: &openolt.AlarmIndication{Data: alarmData}}
267
268 if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
269 onuLogger.Errorf("Failed to send DyingGaspInd : %v", err)
270 return err
271 }
272 onuLogger.WithFields(log.Fields{
273 "IntfId": msg.PonPortID,
274 "OnuSn": o.Sn(),
275 "OnuId": msg.OnuID,
276 }).Info("sendDyingGaspInd")
277 return nil
278}
279
Matteo Scandolo4747d292019-08-05 11:50:18 -0700280func (o Onu) sendOnuDiscIndication(msg OnuDiscIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
281 discoverData := &openolt.Indication_OnuDiscInd{OnuDiscInd: &openolt.OnuDiscIndication{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700282 IntfId: msg.Onu.PonPortID,
Matteo Scandolo4747d292019-08-05 11:50:18 -0700283 SerialNumber: msg.Onu.SerialNumber,
284 }}
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700285
Matteo Scandolo4747d292019-08-05 11:50:18 -0700286 if err := stream.Send(&openolt.Indication{Data: discoverData}); err != nil {
Matteo Scandolo11006992019-08-28 11:29:46 -0700287 log.Errorf("Failed to send Indication_OnuDiscInd: %v", err)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700288 }
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700289
290 if err := o.InternalState.Event("discover"); err != nil {
291 oltLogger.WithFields(log.Fields{
292 "IntfId": o.PonPortID,
293 "OnuSn": o.Sn(),
294 "OnuId": o.ID,
295 }).Infof("Failed to transition ONU to discovered state: %s", err.Error())
296 }
297
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700298 onuLogger.WithFields(log.Fields{
Matteo Scandolo4747d292019-08-05 11:50:18 -0700299 "IntfId": msg.Onu.PonPortID,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700300 "OnuSn": msg.Onu.Sn(),
301 "OnuId": o.ID,
Matteo Scandolo4747d292019-08-05 11:50:18 -0700302 }).Debug("Sent Indication_OnuDiscInd")
303}
304
305func (o Onu) sendOnuIndication(msg OnuIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
306 // NOTE voltha returns an ID, but if we use that ID then it complains:
307 // expected_onu_id: 1, received_onu_id: 1024, event: ONU-id-mismatch, can happen if both voltha and the olt rebooted
308 // so we're using the internal ID that is 1
309 // o.ID = msg.OnuID
Matteo Scandolo4747d292019-08-05 11:50:18 -0700310
311 indData := &openolt.Indication_OnuInd{OnuInd: &openolt.OnuIndication{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700312 IntfId: o.PonPortID,
313 OnuId: o.ID,
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700314 OperState: msg.OperState.String(),
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700315 AdminState: o.OperState.Current(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700316 SerialNumber: o.SerialNumber,
317 }}
318 if err := stream.Send(&openolt.Indication{Data: indData}); err != nil {
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700319 // TODO do we need to transition to a broken state?
Matteo Scandolo11006992019-08-28 11:29:46 -0700320 log.Errorf("Failed to send Indication_OnuInd: %v", err)
Matteo Scandolo4747d292019-08-05 11:50:18 -0700321 }
Matteo Scandolo9a3518c2019-08-13 14:36:01 -0700322 onuLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700323 "IntfId": o.PonPortID,
324 "OnuId": o.ID,
325 "OperState": msg.OperState.String(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700326 "AdminState": msg.OperState.String(),
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700327 "OnuSn": o.Sn(),
Matteo Scandolo4747d292019-08-05 11:50:18 -0700328 }).Debug("Sent Indication_OnuInd")
Matteo Scandolo10f965c2019-09-24 10:40:46 -0700329
Matteo Scandoloc559ef12019-08-20 13:24:21 -0700330}
331
332func (o Onu) handleOmciMessage(msg OmciMessage, stream openolt.Openolt_EnableIndicationServer) {
333
334 onuLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700335 "IntfId": o.PonPortID,
Matteo Scandoloc559ef12019-08-20 13:24:21 -0700336 "SerialNumber": o.SerialNumber,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700337 "omciPacket": msg.omciMsg.Pkt,
Matteo Scandoloc559ef12019-08-20 13:24:21 -0700338 }).Tracef("Received OMCI message")
339
340 var omciInd openolt.OmciIndication
341 respPkt, err := omci.OmciSim(o.PonPortID, o.ID, HexDecode(msg.omciMsg.Pkt))
342 if err != nil {
343 onuLogger.Errorf("Error handling OMCI message %v", msg)
344 }
345
346 omciInd.IntfId = o.PonPortID
347 omciInd.OnuId = o.ID
348 omciInd.Pkt = respPkt
349
350 omci := &openolt.Indication_OmciInd{OmciInd: &omciInd}
351 if err := stream.Send(&openolt.Indication{Data: omci}); err != nil {
Matteo Scandolo11006992019-08-28 11:29:46 -0700352 onuLogger.Errorf("send omci indication failed: %v", err)
Matteo Scandoloc559ef12019-08-20 13:24:21 -0700353 }
354 onuLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700355 "IntfId": o.PonPortID,
Matteo Scandoloc559ef12019-08-20 13:24:21 -0700356 "SerialNumber": o.SerialNumber,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700357 "omciPacket": omciInd.Pkt,
Matteo Scandoloc559ef12019-08-20 13:24:21 -0700358 }).Tracef("Sent OMCI message")
359}
360
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700361func (o Onu) handleFlowUpdate(msg OnuFlowUpdateMessage, stream openolt.Openolt_EnableIndicationServer) {
362 onuLogger.WithFields(log.Fields{
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700363 "DstPort": msg.Flow.Classifier.DstPort,
364 "EthType": fmt.Sprintf("%x", msg.Flow.Classifier.EthType),
365 "FlowId": msg.Flow.FlowId,
366 "FlowType": msg.Flow.FlowType,
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700367 "InnerVlan": msg.Flow.Classifier.IVid,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700368 "IntfId": msg.Flow.AccessIntfId,
369 "IpProto": msg.Flow.Classifier.IpProto,
370 "OnuId": msg.Flow.OnuId,
371 "OnuSn": o.Sn(),
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700372 "OuterVlan": msg.Flow.Classifier.OVid,
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700373 "PortNo": msg.Flow.PortNo,
374 "SrcPort": msg.Flow.Classifier.SrcPort,
375 "UniID": msg.Flow.UniId,
376 }).Debug("ONU receives Flow")
377
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700378 if msg.Flow.Classifier.EthType == uint32(layers.EthernetTypeEAPOL) && msg.Flow.Classifier.OVid == 4091 {
379 // NOTE if we receive the EAPOL flows but we don't have GemPorts
380 // go an intermediate state, otherwise start auth
381 if o.InternalState.Is("enabled") {
382 if err := o.InternalState.Event("receive_eapol_flow"); err != nil {
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700383 log.Warnf("Can't go to eapol_flow_received: %v", err)
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700384 }
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700385 } else if o.InternalState.Is("gem_port_added") {
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700386 if err := o.InternalState.Event("start_auth"); err != nil {
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700387 log.Warnf("Can't go to auth_started: %v", err)
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700388 }
389 }
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700390 } else if msg.Flow.Classifier.EthType == uint32(layers.EthernetTypeIPv4) &&
391 msg.Flow.Classifier.SrcPort == uint32(68) &&
392 msg.Flow.Classifier.DstPort == uint32(67) {
393 // NOTE we are receiving mulitple DHCP flows but we shouldn't call the transition multiple times
394 if err := o.InternalState.Event("start_dhcp"); err != nil {
395 log.Warnf("Can't go to dhcp_started: %v", err)
396 }
Matteo Scandolo3bc73742019-08-20 14:04:04 -0700397 }
398}
399
Matteo Scandoloc559ef12019-08-20 13:24:21 -0700400// HexDecode converts the hex encoding to binary
401func HexDecode(pkt []byte) []byte {
402 p := make([]byte, len(pkt)/2)
403 for i, j := 0, 0; i < len(pkt); i, j = i+2, j+1 {
404 // Go figure this ;)
405 u := (pkt[i] & 15) + (pkt[i]>>6)*9
406 l := (pkt[i+1] & 15) + (pkt[i+1]>>6)*9
407 p[j] = u<<4 + l
408 }
409 onuLogger.Tracef("Omci decoded: %x.", p)
410 return p
Matteo Scandolo4b3fc7e2019-09-17 16:49:54 -0700411}