blob: 3174d63d3fd7252d20e81db6c233cf9eddd99cae [file] [log] [blame]
Shad Ansari2f7f9be2017-06-07 13:34:53 -07001/*
2 <:copyright-BRCM:2016:DUAL/GPL:standard
3
4 Broadcom Proprietary and Confidential.(c) 2016 Broadcom
5 All Rights Reserved
6
7 Unless you and Broadcom execute a separate written software license
8 agreement governing use of this software, this software is licensed
9 to you under the terms of the GNU General Public License version 2
10 (the "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php,
11 with the following added to such license:
12
13 As a special exception, the copyright holders of this software give
14 you permission to link this software with independent modules, and
15 to copy and distribute the resulting executable under terms of your
16 choice, provided that you also meet, for each linked independent
17 module, the terms and conditions of the license of that module.
18 An independent module is a module which is not derived from this
19 software. The special exception does not apply to any modifications
20 of the software.
21
22 Not withstanding the above, under no circumstances may you combine
23 this software in any way with any other Broadcom software provided
24 under a license other than the GPL, without Broadcom's express prior
25 written consent.
26
27 :>
28*/
29
30#include "dpoe_sec_fsm.h"
31#include "dpoe_sec_mka_fsm.h"
32#include "bcmolt_user_appl_epon_oam.h"
33#include "dpoe_sec_util.h"
34
35typedef enum dpoe_sec_mka_fsm_event_type
36{
37 DPOE_SEC_MKA_FSM_EVENT__INVALID = -1, /**< permits event validation */
38
39 DPOE_SEC_MKA_FSM_EVENT_INIT = 0,
40 DPOE_SEC_MKA_FSM_EVENT_RX_OAM ,
41 DPOE_SEC_MKA_FSM_EVENT_RX_EAPOL ,
42 DPOE_SEC_MKA_FSM_EVENT_RX_TIMEOUT ,
43 DPOE_SEC_MKA_FSM_EVENT_TX_TIMEOUT ,
44 DPOE_SEC_MKA_FSM_EVENT_STOP ,
45
46 DPOE_SEC_MKA_FSM_EVENT__COUNT
47} dpoe_sec_mka_fsm_event_type;
48
49/* MKA FSM Event contents. This is a union of information required by the MKA FSM. This data type permits a common
50 * function prototype for the state machine function table. */
51typedef struct dpoe_sec_mka_fsm_event
52{
53 dpoe_sec_mka_fsm_event_type type; /**< Type of event*/
54 union
55 {
56 bcmolt_u8_list_u16 rx_frame;
57 } data;
58} dpoe_sec_mka_fsm_event;
59
60typedef bcmos_errno (*f_dpoe_sec_mka_fsm)(dpoe_sec_link_rec *mka_ctrl, dpoe_sec_mka_fsm_event *evt);
61
62static const char *dpoe_sec_mka_fsm_event_name[DPOE_SEC_MKA_FSM_EVENT__COUNT] =
63{
64 [DPOE_SEC_MKA_FSM_EVENT_INIT] = "Initialization",
65 [DPOE_SEC_MKA_FSM_EVENT_RX_OAM] = "OAM Response",
66 [DPOE_SEC_MKA_FSM_EVENT_RX_EAPOL] = "RX EAPOL",
67 [DPOE_SEC_MKA_FSM_EVENT_RX_TIMEOUT] = "FSM Timeout",
68 [DPOE_SEC_MKA_FSM_EVENT_TX_TIMEOUT] = "MKA Timeout",
69 [DPOE_SEC_MKA_FSM_EVENT_STOP] = "Stop"
70};
71
72static const char *dpoe_sec_mka_fsm_state_name[DPOE_SEC_MKA_FSM_STATE__COUNT] =
73{
74 [DPOE_SEC_MKA_FSM_STATE_NULL] = "Null",
75 [DPOE_SEC_MKA_FSM_STATE_SET_ENCRYPTION] = "Set Encryption",
76 [DPOE_SEC_MKA_FSM_STATE_START_MKA ] = "Start MKA",
77 [DPOE_SEC_MKA_FSM_STATE_SEND_SAK] = "Send SAK",
78 [DPOE_SEC_MKA_FSM_STATE_OPERATIONAL] = "Operational",
79 [DPOE_SEC_MKA_FSM_STATE_SEND_NEW_SAK] = "Send New SAK"
80};
81
82static f_dpoe_sec_mka_cb _mka_done_cb;
83
84static bcmos_errno _dpoe_sec_mka_fsm_exec(dpoe_sec_link_rec *link, dpoe_sec_mka_fsm_event *evt);
85
86static bcmos_bool _dpoe_sec_mka_fsm_event_type_is_valid(dpoe_sec_mka_fsm_event_type type)
87{
88 return (type > DPOE_SEC_MKA_FSM_EVENT__INVALID) && (type < DPOE_SEC_MKA_FSM_EVENT__COUNT);
89}
90
91static bcmos_bool _dpoe_sec_mka_fsm_state_is_valid(dpoe_sec_mka_fsm_state state)
92{
93 return (state > DPOE_SEC_MKA_FSM_STATE__INVALID) && (state < DPOE_SEC_MKA_FSM_STATE__COUNT);
94}
95
96static const char *_dpoe_sec_mka_fsm_event_name(dpoe_sec_mka_fsm_event_type type)
97{
98 if (_dpoe_sec_mka_fsm_event_type_is_valid(type))
99 {
100 return dpoe_sec_mka_fsm_event_name[type];
101 }
102 else
103 {
104 return "Unknown Event";
105 }
106}
107
108static const char *_dpoe_sec_mka_fsm_state_name(dpoe_sec_mka_fsm_state state)
109{
110 if (_dpoe_sec_mka_fsm_state_is_valid(state))
111 {
112 return dpoe_sec_mka_fsm_state_name[state];
113 }
114 else
115 {
116 return "Unknown State";
117 }
118}
119
120static bcmos_errno _dpoe_sec_mka_fsm_error(dpoe_sec_link_rec *link_rec, dpoe_sec_mka_fsm_event *evt)
121{
122 /* Parameter checks */
123 BUG_ON(link_rec == NULL);
124 BUG_ON(link_rec->mka_ctrl.mka_fsm_info == NULL);
125 BUG_ON(evt == NULL);
126
127 /* TODO: log unexpected event */
128
129 return BCM_ERR_OK;
130}
131
132static void _dpoe_sec_mka_fsm_cleanup(dpoe_sec_mka_fsm_ctrl *mka_ctrl)
133{
134 /* Parameter checks. */
135 BUG_ON(mka_ctrl == NULL);
136
137 if (mka_ctrl->mka_info != NULL)
138 {
139 /* Clear all MKA information before freeing. */
140 memset(mka_ctrl->mka_info, 0, sizeof(*mka_ctrl->mka_info));
141 bcmos_free(mka_ctrl->mka_info);
142 mka_ctrl->mka_info = NULL;
143 }
144
145 if (mka_ctrl->mka_fsm_info != NULL)
146 {
147 /* Clear all MKA FSM information before freeing. */
148 memset(mka_ctrl->mka_fsm_info, 0, sizeof(*mka_ctrl->mka_fsm_info));
149 bcmos_free(mka_ctrl->mka_fsm_info);
150 mka_ctrl->mka_fsm_info = NULL;
151 }
152
153 mka_ctrl->mka_fsm_state = DPOE_SEC_MKA_FSM_STATE_NULL;
154}
155
156static bcmos_errno _dpoe_sec_mka_fsm_stop(dpoe_sec_link_rec *link_rec, dpoe_sec_mka_fsm_event *evt)
157{
158 /* Parameter checks */
159 BUG_ON(link_rec == NULL);
160 BUG_ON(link_rec->mka_ctrl.mka_fsm_info == NULL);
161 BUG_ON(evt == NULL);
162
163 /* The stop function is called each time the Link deregisters regardless of whether the MKA FSM is running or not.
164 Handle the case where it is not running. */
165 if (link_rec->mka_ctrl.mka_fsm_info == NULL)
166 {
167 return BCM_ERR_OK;
168 }
169
170 /* Stop any timers that may be running. */
171 bcmos_timer_stop(&link_rec->mka_ctrl.mka_fsm_info->rx_timer);
172 bcmos_timer_stop(&link_rec->mka_ctrl.mka_fsm_info->tx_timer);
173
174 /* Change to the NULL state */
175 link_rec->mka_ctrl.mka_fsm_state = DPOE_SEC_MKA_FSM_STATE_NULL;
176
177 /* Free dynamic MKA resources associated with the link. */
178 _dpoe_sec_mka_fsm_cleanup(&link_rec->mka_ctrl);
179
180 return BCM_ERR_OK;
181}
182
183static bcmos_timer_rc _dpoe_sec_mka_fsm_rx_timer_expire(bcmos_timer *timer, long data)
184{
185 dpoe_sec_link_rec *link_rec = (dpoe_sec_link_rec*)data;
186 dpoe_sec_mka_fsm_event evnt = {};
187
188 /* Parameter Checks */
189 BUG_ON(link_rec == NULL);
190 BUG_ON(link_rec->mka_ctrl.mka_fsm_info == NULL);
191
192 /* Set up the event */
193 evnt.type = DPOE_SEC_MKA_FSM_EVENT_RX_TIMEOUT;
194
195 /* Execute the state machine */
196 _dpoe_sec_mka_fsm_exec(link_rec, &evnt);
197
198 return BCMOS_TIMER_OK;
199}
200
201static bcmos_timer_rc _dpoe_sec_mka_fsm_tx_timer_expire(bcmos_timer *timer, long data)
202{
203 dpoe_sec_link_rec *link_rec = (dpoe_sec_link_rec*)data;
204 dpoe_sec_mka_fsm_event evnt = {};
205
206 /* Parameter Checks */
207 BUG_ON(link_rec == NULL);
208 BUG_ON(link_rec->mka_ctrl.mka_fsm_info == NULL);
209
210 /* Set up the event */
211 evnt.type = DPOE_SEC_MKA_FSM_EVENT_TX_TIMEOUT;
212
213 /* Execute the state machine */
214 _dpoe_sec_mka_fsm_exec(link_rec, &evnt);
215
216 return BCMOS_TIMER_OK;
217}
218
219static bcmos_errno _dpoe_sec_mka_fsm_initialize(dpoe_sec_link_rec *link_rec, dpoe_sec_mka_fsm_event *evt)
220{
221 bcmos_errno err;
222 bcmos_timer_parm rx_tp =
223 {
224 .name = "dpoe_sec_mka_fsm_timer",
225 .owner = BCMOS_MODULE_ID_USER_APPL_DPOE_SEC + link_rec->device,
226 .periodic = BCMOS_FALSE,
227 .handler = _dpoe_sec_mka_fsm_rx_timer_expire,
228 .data = (long)link_rec,
229 .flags = BCMOS_TIMER_PARM_FLAGS_NON_URGENT
230 };
231 bcmos_timer_parm tx_tp =
232 {
233 .name = "dpoe_sec_mka_mka_timer",
234 .owner = BCMOS_MODULE_ID_USER_APPL_DPOE_SEC + link_rec->device,
235 .periodic = BCMOS_TRUE,
236 .handler = _dpoe_sec_mka_fsm_tx_timer_expire,
237 .data = (long)link_rec,
238 .flags = BCMOS_TIMER_PARM_FLAGS_NON_URGENT
239 };
240
241 /* Parameter checks */
242 BUG_ON(link_rec == NULL);
243 BUG_ON(evt == NULL);
244
245 /* Allocate the MKA information structure. */
246 link_rec->mka_ctrl.mka_info = bcmos_calloc(sizeof(*link_rec->mka_ctrl.mka_info));
247 if (link_rec->mka_ctrl.mka_info == NULL)
248 {
249 return BCM_ERR_NOMEM;
250 }
251
252 /* Allocate the MKA FSM information structure. */
253 link_rec->mka_ctrl.mka_fsm_info = bcmos_calloc(sizeof(*link_rec->mka_ctrl.mka_fsm_info));
254 if (link_rec->mka_ctrl.mka_fsm_info == NULL)
255 {
256 _dpoe_sec_mka_fsm_cleanup(&link_rec->mka_ctrl);
257 return BCM_ERR_NOMEM;
258 }
259
260 err = bcmos_timer_create(&link_rec->mka_ctrl.mka_fsm_info->rx_timer, &rx_tp);
261 if (BCM_ERR_OK != err)
262 {
263 _dpoe_sec_mka_fsm_cleanup(&link_rec->mka_ctrl);
264 return err;
265 }
266
267 err = bcmos_timer_create(&link_rec->mka_ctrl.mka_fsm_info->tx_timer, &tx_tp);
268 if (BCM_ERR_OK != err)
269 {
270 _dpoe_sec_mka_fsm_cleanup(&link_rec->mka_ctrl);
271 return err;
272 }
273
274 /* Change to the SET_LINK_ENCRYPTION_MODE state */
275 link_rec->mka_ctrl.mka_fsm_state = DPOE_SEC_MKA_FSM_STATE_SET_ENCRYPTION;
276 bcmos_timer_start(&link_rec->mka_ctrl.mka_fsm_info->rx_timer, DPOE_SEC_OAM_TIMEOUT);
277
278 return epon_oam_dpoe_set_encryption(
279 link_rec->device,
280 link_rec->key.epon_ni,
281 &link_rec->key.mac_address,
282 link_rec->cfg.enc_mode,
283 0);
284}
285
286static bcmos_errno _dpoe_sec_mka_fsm_send_success(dpoe_sec_link_rec *link_rec)
287{
288 /* Parameter checks. */
289 BUG_ON(link_rec == NULL);
290 BUG_ON(_mka_done_cb == NULL);
291
292 _mka_done_cb(link_rec, BCM_ERR_OK);
293
294 return BCM_ERR_OK;
295}
296
297static bcmos_errno _dpoe_sec_mka_fsm_send_failure(dpoe_sec_link_rec *link_rec, bcmos_errno reason)
298{
299 dpoe_sec_mka_fsm_event event = { .type = DPOE_SEC_MKA_FSM_EVENT_STOP };
300
301 /* Parameter checks. */
302 BUG_ON(link_rec == NULL);
303 BUG_ON(_mka_done_cb == NULL);
304
305 DPOE_SEC_LINK_LOG(ERROR, link_rec, "MKA stopping!\n");
306
307 /* Notify the DPoE Security FSM of the MKA error. */
308 _mka_done_cb(link_rec, reason);
309
310 /* Stop the FSM due to the error. */
311 return _dpoe_sec_mka_fsm_stop(link_rec, &event);
312}
313
314static bcmos_errno _dpoe_sec_mka_fsm_rx_timeout(dpoe_sec_link_rec *link_rec, dpoe_sec_mka_fsm_event *evt)
315{
316 /* Parameter checks */
317 BUG_ON(link_rec == NULL);
318 BUG_ON(link_rec->mka_ctrl.mka_fsm_info == NULL);
319 BUG_ON(evt == NULL);
320
321 DPOE_SEC_LINK_LOG(ERROR, link_rec, "TIMEOUT error!\n");
322
323 /* Notify the DPoE Security FSM of the MKA error. */
324 return _dpoe_sec_mka_fsm_send_failure(link_rec, BCM_ERR_TIMEOUT);
325}
326
327static bcmos_errno _dpoe_sec_mka_fsm_rx_oam(dpoe_sec_link_rec *link_rec, dpoe_sec_mka_fsm_event *evt)
328{
329 bcmos_errno rc = BCM_ERR_OK;
330 bcmolt_epon_oam_ethernet_frame *oam_frame;
331 bcmolt_epon_oam_dpoe_vendor_extended_base *dpoe;
332
333 /* Parameter checks */
334 BUG_ON(link_rec == NULL);
335 BUG_ON(link_rec->mka_ctrl.mka_fsm_info == NULL);
336 BUG_ON(evt == NULL);
337 BUG_ON(evt->data.rx_frame.val == NULL);
338
339 oam_frame = epon_oam_unpack(link_rec->device, evt->data.rx_frame.len, evt->data.rx_frame.val);
340 if (NULL == oam_frame)
341 {
342 DPOE_SEC_LINK_LOG(ERROR, link_rec, "OAM unpack failed!\n");
343 return BCM_ERR_OK;
344 }
345
346 if (!epon_oam_is_dpoe(oam_frame))
347 {
348 bcmos_free(oam_frame);
349 return BCM_ERR_OK;
350 }
351
352 dpoe = &oam_frame->protocols[0].u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value;
353
354 if (epon_oam_is_dpoe_encrypt_response(dpoe))
355 {
356 if ((dpoe->u.set_response.vars[0].u.extended_attribute.attribute.width == 0x80) &&
357 (dpoe->u.set_response.vars[1].u.extended_attribute.attribute.width == 0x80))
358 {
359 bcmos_timer_stop(&link_rec->mka_ctrl.mka_fsm_info->rx_timer);
360
361 /* Change to the START_MKA state */
362 link_rec->mka_ctrl.mka_fsm_state = DPOE_SEC_MKA_FSM_STATE_START_MKA;
363
364 /* Send the initial MKA packet to the ONU for the specified link. */
365 rc = mka_start(link_rec);
366 }
367 else
368 {
369 DPOE_SEC_LINK_LOG(ERROR, link_rec, "ONU rejected encryption: [0] = 0x%x, [1] = 0x%x\n",
370 dpoe->u.set_response.vars[0].u.extended_attribute.attribute.width,
371 dpoe->u.set_response.vars[1].u.extended_attribute.attribute.width);
372 /* Notify the DPoE Security FSM of the MKA error. */
373 rc = _dpoe_sec_mka_fsm_send_failure(link_rec, BCM_ERR_ONU_ERR_RESP);
374 }
375 }
376 else
377 {
378 /* ignore other OAM */
379 }
380
381 bcmos_free(oam_frame);
382
383 return rc;
384}
385
386static bcmos_errno _dpoe_sec_mka_fsm_start_timeout(dpoe_sec_link_rec *link_rec, dpoe_sec_mka_fsm_event *evt)
387{
388 /* Parameter checks */
389 BUG_ON(link_rec == NULL);
390 BUG_ON(link_rec->mka_ctrl.mka_fsm_info == NULL);
391 BUG_ON(evt == NULL);
392
393 return mka_process_timeout(link_rec, MKA_OP_START_TIMEOUT);
394}
395
396static bcmos_errno _dpoe_sec_mka_fsm_start_rx_eapol(dpoe_sec_link_rec *link_rec, dpoe_sec_mka_fsm_event *evt)
397{
398 bcmos_errno rc = BCM_ERR_OK;
399
400 /* Parameter checks */
401 BUG_ON(link_rec == NULL);
402 BUG_ON(link_rec->mka_ctrl.mka_fsm_info == NULL);
403 BUG_ON(evt == NULL);
404
405 rc = mka_process_packet(link_rec, evt->data.rx_frame, MKA_OP_START_RSP);
406 if (rc == BCM_ERR_OK)
407 {
408 bcmolt_encryption_information_container key_info;
409
410 /* Re-start the rx timer */
411 bcmos_timer_start(&link_rec->mka_ctrl.mka_fsm_info->rx_timer, MKA_LIFE_TIME * 1000);
412
413 /* Generate the initial SAK. */
414 mka_generate_sak(link_rec, BCMOS_TRUE);
415
416 key_info.format = BCMOLT_EPON_ENCRYPTION_INFORMATION_FORMAT_CTR;
417 memcpy(key_info.u.ctr.key, link_rec->mka_ctrl.mka_info->sak, sizeof(key_info.u.ctr.key));
418 memcpy(key_info.u.ctr.sci, link_rec->mka_ctrl.mka_info->onu_sci, sizeof(key_info.u.ctr.sci));
419
420 /* Install the SAK as the US encryption key for this link. */
421 rc = bcmolt_epon_link_encryption_key_set(
422 link_rec->device,
423 &link_rec->key,
424 BCMOS_TRUE,
425 BCMOLT_EPON_ENCRYPTION_MODE_EPON_ZERO_OVERHEAD_AES,
426 (bcmolt_epon_key_choice)((link_rec->mka_ctrl.mka_info->key_number + 1) % 2),
427 &key_info);
428 if (rc == BCM_ERR_OK)
429 {
430 rc = mka_send_sak(link_rec, link_rec->mka_ctrl.mka_info->sak);
431 if (rc == BCM_ERR_OK)
432 {
433 /* Change to the SEND_SAK state */
434 link_rec->mka_ctrl.mka_fsm_state = DPOE_SEC_MKA_FSM_STATE_SEND_SAK;
435 }
436 else
437 {
438 DPOE_SEC_LINK_LOG(ERROR, link_rec, "send SAK failed!\n");
439 }
440 }
441 else
442 {
443 DPOE_SEC_LINK_LOG(ERROR, link_rec, "key set failed %d!\n", rc);
444 }
445 }
446 else
447 {
448 DPOE_SEC_LINK_LOG(ERROR, link_rec, "MKA process packet failed!\n");
449 }
450
451 if (rc != BCM_ERR_OK)
452 {
453 /* Notify the DPoE Security FSM of the MKA error. */
454 _dpoe_sec_mka_fsm_send_failure(link_rec, rc);
455 }
456
457 return rc;
458}
459
460static bcmos_errno _dpoe_sec_mka_fsm_sak_timeout(dpoe_sec_link_rec *link_rec, dpoe_sec_mka_fsm_event *evt)
461{
462 /* Parameter checks */
463 BUG_ON(link_rec == NULL);
464 BUG_ON(link_rec->mka_ctrl.mka_fsm_info == NULL);
465 BUG_ON(evt == NULL);
466
467 return mka_process_timeout(link_rec, MKA_OP_SAK_TIMEOUT);
468}
469
470static bcmos_errno _dpoe_sec_mka_fsm_sak_rx_eapol(dpoe_sec_link_rec *link_rec, dpoe_sec_mka_fsm_event *evt)
471{
472 bcmos_errno rc;
473
474 /* Parameter checks */
475 BUG_ON(link_rec == NULL);
476 BUG_ON(link_rec->mka_ctrl.mka_fsm_info == NULL);
477 BUG_ON(evt == NULL);
478
479 rc = mka_process_packet(link_rec, evt->data.rx_frame, MKA_OP_SAK_RSP);
480 if (rc == BCM_ERR_OK)
481 {
482 bcmolt_encryption_information_container key_info;
483
484 /* Re-start the rx timer */
485 bcmos_timer_start(&link_rec->mka_ctrl.mka_fsm_info->rx_timer, MKA_LIFE_TIME * 1000);
486
487 key_info.format = BCMOLT_EPON_ENCRYPTION_INFORMATION_FORMAT_CTR;
488 memcpy(key_info.u.ctr.key, link_rec->mka_ctrl.mka_info->sak, sizeof(key_info.u.ctr.key));
489 memcpy(key_info.u.ctr.sci, link_rec->ni_mac.u8, BCMOS_ETH_ALEN);
490 key_info.u.ctr.sci[6] = (link_rec->llid >> 8) & 0xff;
491 key_info.u.ctr.sci[7] = (link_rec->llid >> 0) & 0xff;
492
493 /* Install the SAK as the US and DS encryption key for this link. */
494 rc = bcmolt_epon_link_encryption_key_set(
495 link_rec->device,
496 &link_rec->key,
497 BCMOS_FALSE,
498 BCMOLT_EPON_ENCRYPTION_MODE_EPON_ZERO_OVERHEAD_AES,
499 (bcmolt_epon_key_choice)((link_rec->mka_ctrl.mka_info->key_number + 1) % 2),
500 &key_info);
501 if (rc == BCM_ERR_OK)
502 {
503 rc = mka_send_sak_confirm(link_rec);
504 if (rc == BCM_ERR_OK)
505 {
506 /* Notify the DPoE Security FSM of the MKA result. */
507 rc = _dpoe_sec_mka_fsm_send_success(link_rec);
508
509 /* Change to the OPERATIONAL state */
510 link_rec->mka_ctrl.mka_fsm_state = DPOE_SEC_MKA_FSM_STATE_OPERATIONAL;
511 }
512 }
513 }
514
515 if (rc != BCM_ERR_OK)
516 {
517 /* Notify the DPoE Security FSM of the MKA error. */
518 _dpoe_sec_mka_fsm_send_failure(link_rec, rc);
519 }
520
521 return rc;
522}
523
524static bcmos_errno _dpoe_sec_mka_fsm_send_keep_alive(dpoe_sec_link_rec *link_rec, dpoe_sec_mka_fsm_event *evt)
525{
526 /* Parameter checks */
527 BUG_ON(link_rec == NULL);
528 BUG_ON(link_rec->mka_ctrl.mka_fsm_info == NULL);
529 BUG_ON(evt == NULL);
530
531 return mka_process_timeout(link_rec, MKA_OP_SEND_KEEP_ALIVE);
532}
533
534static bcmos_errno _dpoe_sec_mka_fsm_sak_refresh(dpoe_sec_link_rec *link_rec, dpoe_sec_mka_fsm_event *evt)
535{
536 bcmos_errno rc = BCM_ERR_OK;
537
538 /* Parameter checks */
539 BUG_ON(link_rec == NULL);
540 BUG_ON(link_rec->mka_ctrl.mka_fsm_info == NULL);
541 BUG_ON(evt == NULL);
542
543 bcmolt_encryption_information_container key_info;
544
545 /* Generate the new SAK. */
546 mka_generate_sak(link_rec, BCMOS_FALSE);
547
548 key_info.format = BCMOLT_EPON_ENCRYPTION_INFORMATION_FORMAT_CTR;
549 memcpy(key_info.u.ctr.key, link_rec->mka_ctrl.mka_info->sak, sizeof(key_info.u.ctr.key));
550 memcpy(key_info.u.ctr.sci, link_rec->mka_ctrl.mka_info->onu_sci, sizeof(key_info.u.ctr.sci));
551
552 /* Install the new SAK as the US encryption key for this link. */
553 rc = bcmolt_epon_link_encryption_key_set(
554 link_rec->device,
555 &link_rec->key,
556 BCMOS_TRUE,
557 BCMOLT_EPON_ENCRYPTION_MODE_EPON_ZERO_OVERHEAD_AES,
558 (bcmolt_epon_key_choice)((link_rec->mka_ctrl.mka_info->key_number + 1) % 2),
559 &key_info);
560 if (rc == BCM_ERR_OK)
561 {
562 rc = mka_send_sak(link_rec, link_rec->mka_ctrl.mka_info->new_sak);
563 if (rc == BCM_ERR_OK)
564 {
565 /* Change to the SEND_SAK state */
566 link_rec->mka_ctrl.mka_fsm_state = DPOE_SEC_MKA_FSM_STATE_SEND_NEW_SAK;
567 }
568 }
569
570 if (BCM_ERR_OK != rc)
571 {
572 /* Notify the DPoE Security FSM of the MKA error. */
573 _dpoe_sec_mka_fsm_send_failure(link_rec, rc);
574 }
575
576 return rc;
577}
578
579static bcmos_errno _dpoe_sec_mka_fsm_handle_keep_alive(dpoe_sec_link_rec *link_rec, dpoe_sec_mka_fsm_event *evt)
580{
581 bcmos_errno rc = BCM_ERR_OK;
582
583 /* Parameter checks */
584 BUG_ON(link_rec == NULL);
585 BUG_ON(link_rec->mka_ctrl.mka_fsm_info == NULL);
586 BUG_ON(link_rec->mka_ctrl.mka_info == NULL);
587 BUG_ON(evt == NULL);
588
589 /* Pass the keep alive message to the MKA proper code. It's okay to ignore the return status. Failure to maintain
590 the MKA connection through MKA keep alive messages will tear down the MKA connection. */
591 rc = mka_process_packet(link_rec, evt->data.rx_frame, MKA_OP_KEEP_ALIVE);
592
593 /* Check if a SAK refresh is needed. */
594 if (rc == BCM_ERR_OK)
595 {
596 /* Re-start the rx timer */
597 bcmos_timer_start(&link_rec->mka_ctrl.mka_fsm_info->rx_timer, MKA_LIFE_TIME * 1000);
598
599 if (link_rec->mka_ctrl.mka_info->sak_refresh_needed)
600 {
601 /* Start the SAK refresh process. */
602 _dpoe_sec_mka_fsm_sak_refresh(link_rec, evt);
603
604 /* Clear the SAK refresh flag since the SAK refresh process has been started. */
605 link_rec->mka_ctrl.mka_info->sak_refresh_needed = BCMOS_FALSE;
606 }
607 }
608
609 return rc;
610}
611
612static bcmos_errno _dpoe_sec_mka_fsm_new_sak_rx_eapol(dpoe_sec_link_rec *link_rec, dpoe_sec_mka_fsm_event *evt)
613{
614 bcmos_errno rc;
615
616 /* Parameter checks */
617 BUG_ON(link_rec == NULL);
618 BUG_ON(link_rec->mka_ctrl.mka_fsm_info == NULL);
619 BUG_ON(link_rec->mka_ctrl.mka_info == NULL);
620 BUG_ON(evt == NULL);
621
622 rc = mka_process_packet(link_rec, evt->data.rx_frame, MKA_OP_SAK_RSP);
623 if (rc == BCM_ERR_OK)
624 {
625 /* Re-start the rx timer */
626 bcmos_timer_start(&link_rec->mka_ctrl.mka_fsm_info->rx_timer, MKA_LIFE_TIME * 1000);
627
628 bcmolt_encryption_information_container key_info;
629
630 key_info.format = BCMOLT_EPON_ENCRYPTION_INFORMATION_FORMAT_CTR;
631 memcpy(key_info.u.ctr.key, link_rec->mka_ctrl.mka_info->sak, sizeof(key_info.u.ctr.key));
632 memcpy(key_info.u.ctr.sci, link_rec->ni_mac.u8, BCMOS_ETH_ALEN);
633 key_info.u.ctr.sci[6] = (link_rec->llid >> 8) & 0xff;
634 key_info.u.ctr.sci[7] = (link_rec->llid >> 0) & 0xff;
635
636 /* Install the new SAK as the US and DS encryption key for this link. */
637 rc = bcmolt_epon_link_encryption_key_set(
638 link_rec->device,
639 &link_rec->key,
640 BCMOS_FALSE,
641 BCMOLT_EPON_ENCRYPTION_MODE_EPON_ZERO_OVERHEAD_AES,
642 (bcmolt_epon_key_choice)((link_rec->mka_ctrl.mka_info->key_number + 1) % 2),
643 &key_info);
644 if (rc == BCM_ERR_OK)
645 {
646 rc = mka_send_sak_confirm(link_rec);
647 if (rc == BCM_ERR_OK)
648 {
649 /* Update the current SAK with the new SAK */
650 memcpy(link_rec->mka_ctrl.mka_info->sak, link_rec->mka_ctrl.mka_info->new_sak,
651 sizeof(link_rec->mka_ctrl.mka_info->sak));
652
653 /* Change to the OPERATIONAL state */
654 link_rec->mka_ctrl.mka_fsm_state = DPOE_SEC_MKA_FSM_STATE_OPERATIONAL;
655 }
656 }
657 }
658
659 if (rc != BCM_ERR_OK)
660 {
661 /* Notify the DPoE Security FSM of the MKA error. */
662 _dpoe_sec_mka_fsm_send_failure(link_rec, rc);
663 }
664
665 return rc;
666}
667
668/** This is the ONU FSM Jump Table, indexed by STATE and EVENT. */
669static f_dpoe_sec_mka_fsm dpoe_sec_mka_fsm[DPOE_SEC_MKA_FSM_STATE__COUNT][DPOE_SEC_MKA_FSM_EVENT__COUNT] =
670{
671 [DPOE_SEC_MKA_FSM_STATE_NULL] =
672 {
673 [DPOE_SEC_MKA_FSM_EVENT_INIT] = _dpoe_sec_mka_fsm_initialize
674 },
675 [DPOE_SEC_MKA_FSM_STATE_SET_ENCRYPTION] =
676 {
677 [DPOE_SEC_MKA_FSM_EVENT_RX_OAM] = _dpoe_sec_mka_fsm_rx_oam,
678 [DPOE_SEC_MKA_FSM_EVENT_RX_TIMEOUT] = _dpoe_sec_mka_fsm_rx_timeout,
679 [DPOE_SEC_MKA_FSM_EVENT_STOP] = _dpoe_sec_mka_fsm_stop,
680 },
681 [DPOE_SEC_MKA_FSM_STATE_START_MKA] =
682 {
683 [DPOE_SEC_MKA_FSM_EVENT_RX_EAPOL] = _dpoe_sec_mka_fsm_start_rx_eapol,
684 [DPOE_SEC_MKA_FSM_EVENT_RX_TIMEOUT] = _dpoe_sec_mka_fsm_rx_timeout,
685 [DPOE_SEC_MKA_FSM_EVENT_TX_TIMEOUT] = _dpoe_sec_mka_fsm_start_timeout,
686 [DPOE_SEC_MKA_FSM_EVENT_STOP] = _dpoe_sec_mka_fsm_stop
687 },
688 [DPOE_SEC_MKA_FSM_STATE_SEND_SAK] =
689 {
690 [DPOE_SEC_MKA_FSM_EVENT_RX_EAPOL] = _dpoe_sec_mka_fsm_sak_rx_eapol,
691 [DPOE_SEC_MKA_FSM_EVENT_RX_TIMEOUT] = _dpoe_sec_mka_fsm_rx_timeout,
692 [DPOE_SEC_MKA_FSM_EVENT_TX_TIMEOUT] = _dpoe_sec_mka_fsm_sak_timeout,
693 [DPOE_SEC_MKA_FSM_EVENT_STOP] = _dpoe_sec_mka_fsm_stop
694 },
695 [DPOE_SEC_MKA_FSM_STATE_OPERATIONAL] =
696 {
697 [DPOE_SEC_MKA_FSM_EVENT_RX_EAPOL] = _dpoe_sec_mka_fsm_handle_keep_alive,
698 [DPOE_SEC_MKA_FSM_EVENT_RX_TIMEOUT] = _dpoe_sec_mka_fsm_rx_timeout,
699 [DPOE_SEC_MKA_FSM_EVENT_TX_TIMEOUT] = _dpoe_sec_mka_fsm_send_keep_alive,
700 [DPOE_SEC_MKA_FSM_EVENT_STOP] = _dpoe_sec_mka_fsm_stop
701 },
702 [DPOE_SEC_MKA_FSM_STATE_SEND_NEW_SAK] =
703 {
704 [DPOE_SEC_MKA_FSM_EVENT_RX_EAPOL] = _dpoe_sec_mka_fsm_new_sak_rx_eapol,
705 [DPOE_SEC_MKA_FSM_EVENT_RX_TIMEOUT] = _dpoe_sec_mka_fsm_rx_timeout,
706 [DPOE_SEC_MKA_FSM_EVENT_TX_TIMEOUT] = _dpoe_sec_mka_fsm_send_keep_alive,
707 [DPOE_SEC_MKA_FSM_EVENT_STOP] = _dpoe_sec_mka_fsm_stop
708 }
709};
710
711static bcmos_errno _dpoe_sec_mka_fsm_exec(dpoe_sec_link_rec *link_rec, dpoe_sec_mka_fsm_event *evt)
712{
713 bcmos_errno rc = BCM_ERR_PARM;
714
715 /* Parameter checks */
716 BUG_ON(link_rec == NULL);
717 BUG_ON(evt == NULL);
718
719 if (_dpoe_sec_mka_fsm_event_type_is_valid(evt->type))
720 {
721 dpoe_sec_mka_fsm_state pre_state = link_rec->mka_ctrl.mka_fsm_state;
722
723 DPOE_SEC_LINK_LOG(DEBUG, link_rec, "MKA: processing event %s in state %s\n",
724 _dpoe_sec_mka_fsm_event_name(evt->type), _dpoe_sec_mka_fsm_state_name(pre_state));
725
726 /* call the FSM */
727 if (NULL != dpoe_sec_mka_fsm[link_rec->mka_ctrl.mka_fsm_state][evt->type])
728 {
729 rc = dpoe_sec_mka_fsm[link_rec->mka_ctrl.mka_fsm_state][evt->type](link_rec, evt);
730 }
731 else
732 {
733 rc = _dpoe_sec_mka_fsm_error(link_rec, evt);
734 }
735
736 if (pre_state != link_rec->mka_ctrl.mka_fsm_state)
737 {
738 DPOE_SEC_LINK_LOG(DEBUG, link_rec, "MKA: transitioning from %s to %s\n",
739 _dpoe_sec_mka_fsm_state_name(pre_state),
740 _dpoe_sec_mka_fsm_state_name(link_rec->mka_ctrl.mka_fsm_state));
741 }
742 }
743
744 return rc;
745}
746
747void dpoe_sec_mka_fsm_rx_oam(dpoe_sec_link_rec *link_rec, uint8_t *frame, uint16_t length)
748{
749 dpoe_sec_mka_fsm_event evnt = {};
750
751 BUG_ON(link_rec == NULL);
752
753 /* Send the OAM PDU to the state machine. */
754 evnt.type = DPOE_SEC_MKA_FSM_EVENT_RX_OAM;
755 evnt.data.rx_frame.val = frame;
756 evnt.data.rx_frame.len = length;
757
758 /* Execute the state machine */
759 _dpoe_sec_mka_fsm_exec(link_rec, &evnt);
760}
761
762void dpoe_sec_mka_fsm_rx_eapol(dpoe_sec_link_rec *link_rec, uint8_t *frame, uint16_t length)
763{
764 dpoe_sec_mka_fsm_event evnt = {};
765
766 BUG_ON(link_rec == NULL);
767
768 /* Send the OAM PDU to the state machine. */
769 evnt.type = DPOE_SEC_MKA_FSM_EVENT_RX_EAPOL;
770 evnt.data.rx_frame.val = frame;
771 evnt.data.rx_frame.len = length;
772
773 /* Execute the state machine */
774 _dpoe_sec_mka_fsm_exec(link_rec, &evnt);
775}
776
777bcmos_errno dpoe_sec_mka_fsm_start(dpoe_sec_link_rec *link_rec)
778{
779 dpoe_sec_mka_fsm_event event = {};
780
781 /* Parameter checks. */
782 BUG_ON(link_rec == NULL);
783
784 /* Inject an INIT_EVENT into the FSM. */
785 event.type = DPOE_SEC_MKA_FSM_EVENT_INIT;
786
787 return _dpoe_sec_mka_fsm_exec(link_rec, &event);
788}
789
790bcmos_bool dpoe_sec_mka_fsm_running(dpoe_sec_link_rec *link_rec)
791{
792 bcmos_bool rc = BCMOS_FALSE;
793
794 /* Parameter checks. */
795 BUG_ON(link_rec == NULL);
796
797 if ((link_rec->mka_ctrl.mka_fsm_info != NULL) &&
798 (link_rec->mka_ctrl.mka_fsm_state > DPOE_SEC_MKA_FSM_STATE_NULL))
799 {
800 rc = BCMOS_TRUE;
801 }
802
803 return rc;
804}
805
806bcmos_errno dpoe_sec_mka_fsm_deregister(dpoe_sec_link_rec *link_rec)
807{
808 bcmos_errno rc = BCM_ERR_OK;
809 dpoe_sec_mka_fsm_event evnt = {};
810
811 /* Parameter checks. */
812 BUG_ON(link_rec == NULL);
813
814 /* The deregister function is called each time the Link deregisters regardless of whether the MKA FSM is running or
815 not. Handle the case where it is not running. */
816 if (link_rec->mka_ctrl.mka_fsm_info != NULL)
817 {
818 /* Inject a stop into the MKA FSM. */
819 evnt.type = DPOE_SEC_MKA_FSM_EVENT_STOP;
820 rc = _dpoe_sec_mka_fsm_exec(link_rec, &evnt);
821 }
822
823 return rc;
824}
825
826void dpoe_sec_mka_fsm_init(f_dpoe_sec_mka_cb mka_cb)
827{
828 _mka_done_cb = mka_cb;
829}
830