blob: a6c96deac3a074767ee006af1e1a3f7009d53c3b [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_util.h"
32#include "bcmos_hash_table.h"
33#include "bcmolt_epon_oam_types.h"
34#include "bcmolt_utils.h"
35#include "bcmolt_user_appl_epon_oam.h"
36#include "bcmolt_api.h"
37
38#define DPOE_SEC_FSM_MAX_LINKS 64
39#define DPOE_SEC_FSM_TASK_MSG_Q_SIZE 64
40
41static const uint16_t DPOE_SEC_FSM_DEFAULT_OAM_KEY_EXCHANGE_PERIOD = 600; /* 10 minutes */
42/**
43 * @brief Maximum ONU Authentication timeout value
44 * DPoE specification indicates that this value is 5 minutes.
45 */
46static const uint32_t DPOE_SEC_AUTH_TIMEOUT = 5 * 60 * 1000 * 1000;
47
48typedef struct
49{
50 bcmos_task task;
51 char task_name[MAX_TASK_NAME_SIZE];
52 char msg_queue_name[MAX_MSG_QUEUE_NAME_SIZE];
53 hash_table *link_map;
54} dpoe_sec_fsm_ctxt;
55
56dpoe_sec_fsm_ctxt ctxt[BCMTR_MAX_OLTS];
57
58typedef void (*f_dpoe_sec_fsm)(dpoe_sec_link_rec*, dpoe_sec_fsm_event_data*);
59
60/* DPoE Security FSM Event type to string definitions used for debug output */
61static const char *dpoe_sec_fsm_event_name[DPOE_SEC_FSM_EVENT__COUNT] =
62{
63 [DPOE_SEC_FSM_EVENT_ENCRYPT_START] = "Start Encryption",
64 [DPOE_SEC_FSM_EVENT_AUTH_START] = "Start Authentication",
65 [DPOE_SEC_FSM_EVENT_RX_OAM] = "Receive OAM",
66 [DPOE_SEC_FSM_EVENT_RX_EAPOL] = "Receive EAPOL",
67 [DPOE_SEC_FSM_EVENT_AUTH_COMPLETE] = "Authentication Complete",
68 [DPOE_SEC_FSM_EVENT_MKA_COMPLETE] = "MKA Complete",
69 [DPOE_SEC_FSM_EVENT_TIMEOUT] = "Timeout"
70};
71
72
73/* DPoE Security FSM State to string definitions used for debug output */
74static const char *dpoe_sec_fsm_state_name[DPOE_SEC_FSM_STATE__COUNT] =
75{
76 [DPOE_SEC_FSM_STATE_IDLE] = "Idle",
77 [DPOE_SEC_FSM_STATE_AUTH_WAIT] = "Authentication in progress",
78 [DPOE_SEC_FSM_STATE_ENCRYPT_DOWN_WAIT] = "OAM Key Exchange in progress",
79 [DPOE_SEC_FSM_STATE_ENCRYPT_BI_WAIT] = "MKA in progress",
80 [DPOE_SEC_FSM_STATE_COMPLETE] = "Authentication/Encryption Complete"
81};
82
83static f_dpoe_sec_fsm_cb _fsm_complete;
84
85static bcmos_bool _dpoe_sec_fsm_event_type_is_valid(dpoe_sec_fsm_event type)
86{
87 return type < DPOE_SEC_FSM_EVENT__COUNT;
88}
89
90static bcmos_bool _dpoe_sec_fsm_state_is_valid(dpoe_sec_fsm_state state)
91{
92 return state < DPOE_SEC_FSM_STATE__COUNT;
93}
94
95static const char *_dpoe_sec_fsm_event_name(dpoe_sec_fsm_event type)
96{
97 if (_dpoe_sec_fsm_event_type_is_valid(type))
98 {
99 return dpoe_sec_fsm_event_name[type];
100 }
101 else
102 {
103 return "Unknown Event";
104 }
105}
106
107static const char *_dpoe_sec_fsm_state_name(dpoe_sec_fsm_state state)
108{
109 if (_dpoe_sec_fsm_state_is_valid(state))
110 {
111 return dpoe_sec_fsm_state_name[state];
112 }
113 else
114 {
115 return "Unknown State";
116 }
117}
118
119static void _dpoe_sec_fsm_complete(dpoe_sec_link_rec *link_rec)
120{
121 /* Parameter checks */
122 BUG_ON(link_rec == NULL);
123
124 if (_fsm_complete != NULL)
125 {
126 _fsm_complete(link_rec->device, link_rec->key, link_rec->status);
127 }
128}
129
130static void _dpoe_sec_fsm_success(dpoe_sec_link_rec *link_rec)
131{
132 /* Parameter checks */
133 BUG_ON(link_rec == NULL);
134
135 link_rec->fsm_state = DPOE_SEC_FSM_STATE_COMPLETE;
136 link_rec->status = BCM_ERR_OK;
137
138 switch (link_rec->cfg.enc_mode)
139 {
140 case BCMOLT_EPON_OAM_DPOE_ENCRYPTION_MODE_NONE:
141 case BCMOLT_EPON_OAM_DPOE_ENCRYPTION_MODE_TEN_BI:
142 break;
143 case BCMOLT_EPON_OAM_DPOE_ENCRYPTION_MODE_ONE_DOWN:
144 case BCMOLT_EPON_OAM_DPOE_ENCRYPTION_MODE_TEN_DOWN:
145 bcmos_timer_start(
146 &link_rec->timeout,
147 (DPOE_SEC_FSM_DEFAULT_OAM_KEY_EXCHANGE_PERIOD * 1000 * 1000) + DPOE_SEC_OAM_TIMEOUT);
148 break;
149 default:
150 BUG();
151 }
152
153 _dpoe_sec_fsm_complete(link_rec);
154}
155
156static void _dpoe_sec_fsm_stop(dpoe_sec_link_rec *link_rec, bcmos_errno reason)
157{
158 /* Parameter checks */
159 BUG_ON(link_rec == NULL);
160
161 link_rec->fsm_state = DPOE_SEC_FSM_STATE_IDLE;
162 link_rec->status = reason;
163
164 bcmos_timer_stop(&link_rec->timeout);
165
166 /* Cleanup any EAP-TLS state. */
167 dpoe_eap_tls_cleanup(link_rec);
168
169 _dpoe_sec_fsm_complete(link_rec);
170}
171
172static void _dpoe_sec_fsm_auth_start(dpoe_sec_link_rec *link_rec, dpoe_sec_fsm_event_data *evt)
173{
174 bcmos_errno rc;
175
176 /* Parameter checks */
177 BUG_ON(link_rec == NULL);
178 BUG_ON(evt == NULL);
179
180 /* Start ONU Authentication */
181 rc = dpoe_eap_tls_send_start(link_rec);
182 if (BCM_ERR_OK != rc)
183 {
184 DPOE_SEC_LINK_LOG(ERROR, link_rec, "Failed to start authentication: %s (%d)\n", bcmos_strerror(rc), rc);
185 _dpoe_sec_fsm_stop(link_rec, rc);
186 }
187 else
188 {
189 link_rec->fsm_state = DPOE_SEC_FSM_STATE_AUTH_WAIT;
190 bcmos_timer_start(&link_rec->timeout, DPOE_SEC_AUTH_TIMEOUT);
191 DPOE_SEC_LINK_LOG(DEBUG, link_rec, "Starting authentication\n");
192 }
193}
194
195static void _dpoe_sec_fsm_mka_start(dpoe_sec_link_rec *link_rec)
196{
197 bcmos_errno rc = dpoe_sec_mka_fsm_start(link_rec);
198 if (BCM_ERR_OK != rc)
199 {
200 DPOE_SEC_LINK_LOG(ERROR, link_rec, "Failed to start MKA: %s (%d)\n", bcmos_strerror(rc), rc);
201 _dpoe_sec_fsm_stop(link_rec, rc);
202 }
203 else
204 {
205 link_rec->fsm_state = DPOE_SEC_FSM_STATE_ENCRYPT_BI_WAIT;
206 DPOE_SEC_LINK_LOG(DEBUG, link_rec, "Starting MKA\n");
207 }
208}
209
210static void _dpoe_sec_fsm_encrypt_start(dpoe_sec_link_rec *link_rec, dpoe_sec_fsm_event_data *evt)
211{
212 bcmos_errno rc;
213
214 /* Parameter checks */
215 BUG_ON(link_rec == NULL);
216 BUG_ON(evt == NULL);
217
218 if (link_rec->cfg.enc_mode == BCMOLT_EPON_OAM_DPOE_ENCRYPTION_MODE_TEN_BI)
219 {
220 _dpoe_sec_fsm_mka_start(link_rec);
221 }
222 else
223 {
224 rc = epon_oam_dpoe_set_encryption(
225 link_rec->device,
226 link_rec->key.epon_ni,
227 &link_rec->key.mac_address,
228 link_rec->cfg.enc_mode,
229 DPOE_SEC_FSM_DEFAULT_OAM_KEY_EXCHANGE_PERIOD);
230 if (BCM_ERR_OK != rc)
231 {
232 DPOE_SEC_LINK_LOG(ERROR, link_rec, "Failed to set encryption: %s (%d)\n", bcmos_strerror(rc), rc);
233 _dpoe_sec_fsm_stop(link_rec, rc);
234 }
235 else
236 {
237 link_rec->fsm_state = DPOE_SEC_FSM_STATE_ENCRYPT_DOWN_WAIT;
238 bcmos_timer_start(&link_rec->timeout, DPOE_SEC_OAM_TIMEOUT);
239 }
240 }
241}
242
243static void _dpoe_sec_fsm_auth_rx_eapol(dpoe_sec_link_rec *link_rec, dpoe_sec_fsm_event_data *evt)
244{
245 bcmos_errno rc;
246
247 /* Parameter checks */
248 BUG_ON(link_rec == NULL);
249 BUG_ON(evt == NULL);
250
251 rc = dpoe_eap_tls_process_eapol_pkt(link_rec, evt->data.rx_frame.val, evt->data.rx_frame.len);
252 if ((BCM_ERR_OK != rc) && (BCM_ERR_IN_PROGRESS != rc))
253 {
254 DPOE_SEC_LINK_LOG(ERROR, link_rec, "Error processing EAPOL packet: %s (%d)\n", bcmos_strerror(rc), rc);
255 _dpoe_sec_fsm_stop(link_rec, rc);
256 }
257}
258
259static void _dpoe_sec_fsm_auth_complete(dpoe_sec_link_rec *link_rec, dpoe_sec_fsm_event_data *evt)
260{
261 /* Parameter checks */
262 BUG_ON(link_rec == NULL);
263 BUG_ON(evt == NULL);
264
265 bcmos_timer_stop(&link_rec->timeout);
266 if (BCM_ERR_OK == evt->data.sub_status)
267 {
268 if (link_rec->cfg.enc_mode == BCMOLT_EPON_OAM_DPOE_ENCRYPTION_MODE_TEN_BI)
269 {
270 _dpoe_sec_fsm_mka_start(link_rec);
271 }
272 else
273 {
274 _dpoe_sec_fsm_success(link_rec);
275 }
276 }
277 else
278 {
279 _dpoe_sec_fsm_stop(link_rec, evt->data.sub_status);
280 }
281}
282
283static bcmos_errno _dpoe_sec_fsm_install_dn_key(
284 dpoe_sec_link_rec *link_rec,
285 bcmolt_epon_oam_dpoe_vendor_extended_base *dpoe)
286{
287 bcmolt_encryption_information_container key_info;
288
289 if (BCMOLT_EPON_OAM_DPOE_ENCRYPTION_MODE_ONE_DOWN == link_rec->cfg.enc_mode)
290 {
291 key_info.format = BCMOLT_EPON_ENCRYPTION_INFORMATION_FORMAT_CFB;
292 memcpy(key_info.u.cfb.key, dpoe->u.key_exchange.key_data, sizeof(key_info.u.cfb.key));
293 }
294 else
295 {
296 key_info.format = BCMOLT_EPON_ENCRYPTION_INFORMATION_FORMAT_CTR;
297 memcpy(key_info.u.ctr.key, dpoe->u.key_exchange.key_data, sizeof(key_info.u.ctr.key));
298 memcpy(key_info.u.ctr.sci, link_rec->ni_mac.u8, BCMOS_ETH_ALEN);
299 key_info.u.ctr.sci[6] = (link_rec->llid >> 8) & 0xff;
300 key_info.u.ctr.sci[7] = (link_rec->llid >> 0) & 0xff;
301 }
302
303 return bcmolt_epon_link_encryption_key_set(
304 link_rec->device,
305 &link_rec->key,
306 BCMOS_FALSE,
307 BCMOLT_EPON_ENCRYPTION_MODE_EPON_ZERO_OVERHEAD_AES,
308 (bcmolt_epon_key_choice)dpoe->u.key_exchange.key_number,
309 &key_info);
310}
311
312static void _dpoe_sec_fsm_enc_dn_rx_oam(dpoe_sec_link_rec *link_rec, dpoe_sec_fsm_event_data *evt)
313{
314 bcmolt_epon_oam_ethernet_frame *oam_frame;
315 bcmolt_epon_oam_dpoe_vendor_extended_base *dpoe;
316
317 /* Parameter checks */
318 BUG_ON(link_rec == NULL);
319 BUG_ON(evt == NULL);
320
321 oam_frame = epon_oam_unpack(link_rec->device, evt->data.rx_frame.len, evt->data.rx_frame.val);
322 if (NULL == oam_frame)
323 {
324 DPOE_SEC_LINK_LOG(WARNING, link_rec, "Failed to parse OAM frame\n");
325 return;
326 }
327
328 if (!epon_oam_is_dpoe(oam_frame))
329 {
330 bcmos_free(oam_frame);
331 return;
332 }
333
334 dpoe = &oam_frame->protocols[0].u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value;
335
336 if (epon_oam_is_dpoe_encrypt_response(dpoe))
337 {
338 if ((dpoe->u.set_response.vars[0].u.extended_attribute.attribute.width == 0x80) &&
339 (dpoe->u.set_response.vars[1].u.extended_attribute.attribute.width == 0x80))
340 {
341 bcmos_timer_start(&link_rec->timeout, DPOE_SEC_OAM_TIMEOUT); /* restart timer to wait for key */
342 }
343 else
344 {
345 DPOE_SEC_LINK_LOG(ERROR, link_rec, "ONU rejected encryption: [0] = 0x%x, [1] = 0x%x\n",
346 dpoe->u.set_response.vars[0].u.extended_attribute.attribute.width,
347 dpoe->u.set_response.vars[1].u.extended_attribute.attribute.width);
348 _dpoe_sec_fsm_stop(link_rec, BCM_ERR_ONU_ERR_RESP);
349 }
350 }
351 else if (BCMOLT_EPON_OAM_DPOE_OPCODE_KEY_EXCHANGE == dpoe->op)
352 {
353 _dpoe_sec_fsm_install_dn_key(link_rec, dpoe);
354 if (link_rec->cfg.auth)
355 {
356 _dpoe_sec_fsm_auth_start(link_rec, evt);
357 }
358 else
359 {
360 _dpoe_sec_fsm_success(link_rec);
361 }
362 }
363 else
364 {
365 /* ignore other OAM */
366 }
367
368 bcmos_free(oam_frame);
369}
370
371static void _dpoe_sec_fsm_enc_bi_rx_oam(dpoe_sec_link_rec *link_rec, dpoe_sec_fsm_event_data *evt)
372{
373 /* Parameter checks */
374 BUG_ON(link_rec == NULL);
375 BUG_ON(evt == NULL);
376
377 dpoe_sec_mka_fsm_rx_oam(link_rec, evt->data.rx_frame.val, evt->data.rx_frame.len);
378}
379
380static void _dpoe_sec_fsm_enc_bi_rx_eapol(dpoe_sec_link_rec *link_rec, dpoe_sec_fsm_event_data *evt)
381{
382 /* Parameter checks */
383 BUG_ON(link_rec == NULL);
384 BUG_ON(evt == NULL);
385
386 dpoe_sec_mka_fsm_rx_eapol(link_rec, evt->data.rx_frame.val, evt->data.rx_frame.len);
387}
388
389static void _dpoe_sec_fsm_mka_complete(dpoe_sec_link_rec *link_rec, dpoe_sec_fsm_event_data *evt)
390{
391 /* Parameter checks */
392 BUG_ON(link_rec == NULL);
393 BUG_ON(evt == NULL);
394
395 if (BCM_ERR_OK == evt->data.sub_status)
396 {
397 _dpoe_sec_fsm_success(link_rec);
398 }
399 else
400 {
401 _dpoe_sec_fsm_stop(link_rec, evt->data.sub_status);
402 }
403}
404
405static void _dpoe_sec_fsm_comp_rx_oam(dpoe_sec_link_rec *link_rec, dpoe_sec_fsm_event_data *evt)
406{
407 /* Parameter checks */
408 BUG_ON(link_rec == NULL);
409 BUG_ON(evt == NULL);
410
411 if ((link_rec->cfg.enc_mode == BCMOLT_EPON_OAM_DPOE_ENCRYPTION_MODE_ONE_DOWN) ||
412 (link_rec->cfg.enc_mode == BCMOLT_EPON_OAM_DPOE_ENCRYPTION_MODE_TEN_DOWN))
413 {
414 bcmolt_epon_oam_ethernet_frame *oam_frame;
415 bcmolt_epon_oam_dpoe_vendor_extended_base *dpoe;
416
417 oam_frame = epon_oam_unpack(link_rec->device, evt->data.rx_frame.len, evt->data.rx_frame.val);
418 if (NULL == oam_frame)
419 {
420 DPOE_SEC_LINK_LOG(WARNING, link_rec, "Failed to parse OAM frame\n");
421 return;
422 }
423
424 if (!epon_oam_is_dpoe(oam_frame))
425 {
426 bcmos_free(oam_frame);
427 return;
428 }
429
430 dpoe = &oam_frame->protocols[0].u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value;
431
432 if (BCMOLT_EPON_OAM_DPOE_OPCODE_KEY_EXCHANGE == dpoe->op)
433 {
434 _dpoe_sec_fsm_install_dn_key(link_rec, dpoe);
435 }
436 }
437}
438
439static void _dpoe_sec_fsm_comp_rx_eapol(dpoe_sec_link_rec *link_rec, dpoe_sec_fsm_event_data *evt)
440{
441 /* Parameter checks */
442 BUG_ON(link_rec == NULL);
443 BUG_ON(evt == NULL);
444
445 if (link_rec->cfg.enc_mode == BCMOLT_EPON_OAM_DPOE_ENCRYPTION_MODE_TEN_BI)
446 {
447 dpoe_sec_mka_fsm_rx_eapol(link_rec, evt->data.rx_frame.val, evt->data.rx_frame.len);
448 }
449}
450
451static void _dpoe_sec_fsm_timeout(dpoe_sec_link_rec *link_rec, dpoe_sec_fsm_event_data *evt)
452{
453 /* Parameter checks */
454 BUG_ON(link_rec == NULL);
455 BUG_ON(evt == NULL);
456
457 _dpoe_sec_fsm_stop(link_rec, BCM_ERR_TIMEOUT);
458}
459
460static f_dpoe_sec_fsm dpoe_sec_fsm[DPOE_SEC_FSM_STATE__COUNT][DPOE_SEC_FSM_EVENT__COUNT] =
461{
462 [DPOE_SEC_FSM_STATE_IDLE] =
463 {
464 [DPOE_SEC_FSM_EVENT_AUTH_START] = _dpoe_sec_fsm_auth_start,
465 [DPOE_SEC_FSM_EVENT_ENCRYPT_START] = _dpoe_sec_fsm_encrypt_start
466 },
467 [DPOE_SEC_FSM_STATE_AUTH_WAIT] =
468 {
469 [DPOE_SEC_FSM_EVENT_RX_EAPOL] = _dpoe_sec_fsm_auth_rx_eapol,
470 [DPOE_SEC_FSM_EVENT_AUTH_COMPLETE] = _dpoe_sec_fsm_auth_complete,
471 [DPOE_SEC_FSM_EVENT_TIMEOUT] = _dpoe_sec_fsm_timeout
472 },
473 [DPOE_SEC_FSM_STATE_ENCRYPT_DOWN_WAIT] =
474 {
475 [DPOE_SEC_FSM_EVENT_RX_OAM] = _dpoe_sec_fsm_enc_dn_rx_oam,
476 [DPOE_SEC_FSM_EVENT_TIMEOUT] = _dpoe_sec_fsm_timeout
477 },
478 [DPOE_SEC_FSM_STATE_ENCRYPT_BI_WAIT] =
479 {
480 [DPOE_SEC_FSM_EVENT_RX_OAM] = _dpoe_sec_fsm_enc_bi_rx_oam,
481 [DPOE_SEC_FSM_EVENT_RX_EAPOL] = _dpoe_sec_fsm_enc_bi_rx_eapol,
482 [DPOE_SEC_FSM_EVENT_MKA_COMPLETE] = _dpoe_sec_fsm_mka_complete,
483 [DPOE_SEC_FSM_EVENT_TIMEOUT] = _dpoe_sec_fsm_timeout
484 },
485 [DPOE_SEC_FSM_STATE_COMPLETE] =
486 {
487 [DPOE_SEC_FSM_EVENT_RX_OAM] = _dpoe_sec_fsm_comp_rx_oam,
488 [DPOE_SEC_FSM_EVENT_RX_EAPOL] = _dpoe_sec_fsm_comp_rx_eapol,
489 [DPOE_SEC_FSM_EVENT_TIMEOUT] = _dpoe_sec_fsm_timeout
490 }
491};
492
493static void _dpoe_sec_fsm_unexpected(dpoe_sec_link_rec *link_rec, dpoe_sec_fsm_event_data *evt)
494{
495 /* Parameter checks */
496 BUG_ON(link_rec == NULL);
497 BUG_ON(evt == NULL);
498
499 DPOE_SEC_LINK_LOG(WARNING, link_rec, "Unexpected event %s (%u) in state %s (%u)\n",
500 _dpoe_sec_fsm_event_name(evt->type), evt->type, _dpoe_sec_fsm_state_name(link_rec->fsm_state), link_rec->fsm_state);
501}
502
503static void _dpoe_sec_fsm_exec(dpoe_sec_link_rec *link_rec, dpoe_sec_fsm_event_data *evt)
504{
505 /* Parameter checks */
506 BUG_ON(link_rec == NULL);
507 BUG_ON(evt == NULL);
508
509 if (evt->type < DPOE_SEC_FSM_EVENT__COUNT)
510 {
511 dpoe_sec_fsm_state pre_state = link_rec->fsm_state;
512
513 if (dpoe_sec_fsm[link_rec->fsm_state][evt->type] != NULL)
514 {
515 DPOE_SEC_LINK_LOG(DEBUG, link_rec, "processing event %s in state %s\n",
516 _dpoe_sec_fsm_event_name(evt->type), _dpoe_sec_fsm_state_name(link_rec->fsm_state));
517 dpoe_sec_fsm[link_rec->fsm_state][evt->type](link_rec, evt);
518 }
519 else
520 {
521 _dpoe_sec_fsm_unexpected(link_rec, evt);
522 }
523
524 if (link_rec->fsm_state != pre_state)
525 {
526 DPOE_SEC_LINK_LOG(DEBUG, link_rec, "transition from %s to %s\n",
527 _dpoe_sec_fsm_state_name(pre_state), _dpoe_sec_fsm_state_name(link_rec->fsm_state));
528 }
529 }
530 else
531 {
532 DPOE_SEC_LINK_LOG(ERROR, link_rec, "Unknown event: %u", evt->type);
533 }
534}
535
536static bcmos_timer_rc _dpoe_sec_fsm_link_timer_expired(bcmos_timer *timer, long data)
537{
538 dpoe_sec_link_rec *link_rec = (dpoe_sec_link_rec*)data;
539 dpoe_sec_fsm_event_data evt;
540
541 evt.type = DPOE_SEC_FSM_EVENT_TIMEOUT;
542
543 _dpoe_sec_fsm_exec(link_rec, &evt);
544
545 return BCMOS_TIMER_OK;
546}
547
548static void _dpoe_sec_fsm_link_start_handle(bcmos_module_id module_id, bcmos_msg *os_msg)
549{
550 dpoe_sec_fsm_msg *msg = (dpoe_sec_fsm_msg*)os_msg;
551 bcmolt_devid device = os_msg->instance;
552 dpoe_sec_link_rec *link_rec;
553 dpoe_sec_fsm_event_data evt;
554 bcmos_errno err;
555
556 link_rec = hash_table_get(ctxt[device].link_map, (const uint8_t*)&msg->link);
557 if (link_rec == NULL)
558 {
559 dpoe_sec_link_rec new_link;
560 bcmolt_epon_ni_cfg pon_cfg;
561 bcmolt_epon_link_cfg link_cfg;
562 bcmolt_epon_ni_key pon_key = { .epon_ni = msg->link.epon_ni };
563 bcmos_timer_parm tp =
564 {
565 .name = "dpoe_sec_fsm_timer",
566 .owner = BCMOS_MODULE_ID_USER_APPL_DPOE_SEC + device,
567 .periodic = BCMOS_FALSE,
568 .handler = _dpoe_sec_fsm_link_timer_expired,
569 .flags = BCMOS_TIMER_PARM_FLAGS_NON_URGENT
570 };
571
572 /* retrieve the EPON NI MAC address */
573 BCMOLT_CFG_INIT(&pon_cfg, epon_ni, pon_key);
574 BCMOLT_CFG_PROP_GET(&pon_cfg, epon_ni, mac_address);
575 err = bcmolt_cfg_get(device, &pon_cfg.hdr);
576 BUG_ON(BCM_ERR_OK != err);
577
578 BCMOLT_CFG_INIT(&link_cfg, epon_link, msg->link);
579 BCMOLT_CFG_PROP_GET(&link_cfg, epon_link, llid);
580 err = bcmolt_cfg_get(device, &link_cfg.hdr);
581 if (BCM_ERR_OK != err)
582 {
583 BCM_LOG(ERROR, dpoe_sec_log_id[device], "Failed to get LLID\n");
584 }
585
586 new_link.device = device;
587 new_link.key = msg->link;
588 new_link.ni_mac = pon_cfg.data.mac_address;
589 new_link.llid = link_cfg.data.llid;
590 new_link.fsm_state = DPOE_SEC_FSM_STATE_IDLE;
591 new_link.status = BCM_ERR_IN_PROGRESS;
592
593 /* add new rec to hash table */
594 link_rec = hash_table_put(ctxt[device].link_map, (uint8_t*)&msg->link, &new_link);
595 if (link_rec == NULL)
596 {
597 DPOE_SEC_LINK_LOG(ERROR, &new_link, "Failed to store link record\n");
598 }
599
600 tp.data = (long)link_rec;
601 err = bcmos_timer_create(&link_rec->timeout, &tp);
602 BUG_ON(BCM_ERR_OK != err);
603 }
604
605 link_rec->cfg = msg->data.start;
606
607 if (!link_rec->cfg.auth || (link_rec->cfg.enc_mode != BCMOLT_EPON_OAM_DPOE_ENCRYPTION_MODE_TEN_BI))
608 {
609 evt.type = DPOE_SEC_FSM_EVENT_ENCRYPT_START;
610 }
611 else
612 {
613 evt.type = DPOE_SEC_FSM_EVENT_AUTH_START;
614 }
615
616 _dpoe_sec_fsm_exec(link_rec, &evt);
617
618 bcmos_free(os_msg);
619}
620
621static void _dpoe_sec_fsm_link_rx_oam_handle(bcmos_module_id module_id, bcmos_msg *os_msg)
622{
623 dpoe_sec_fsm_msg *msg = (dpoe_sec_fsm_msg*)os_msg;
624 bcmolt_devid device = os_msg->instance;
625 dpoe_sec_link_rec *link_rec;
626 dpoe_sec_fsm_event_data evt;
627
628 link_rec = hash_table_get(ctxt[device].link_map, (uint8_t*)&msg->link);
629 if (link_rec == NULL)
630 {
631 BCM_LOG(DEBUG, dpoe_sec_log_id[device], "Failed to find link: PON %u, "BCMOS_MACADDR_FMT_STR"\n",
632 msg->link.epon_ni, BCMOS_MACADDR_PARAMS(&msg->link.mac_address));
633 }
634 else
635 {
636 evt.type = DPOE_SEC_FSM_EVENT_RX_OAM;
637 evt.data.rx_frame.val = msg->data.rx_frame.frame;
638 evt.data.rx_frame.len = msg->data.rx_frame.length;
639 _dpoe_sec_fsm_exec(link_rec, &evt);
640 }
641
642 bcmos_free(msg->data.rx_frame.frame);
643 bcmos_free(os_msg);
644}
645
646static void _dpoe_sec_fsm_link_rx_eapol_handle(bcmos_module_id module_id, bcmos_msg *os_msg)
647{
648 dpoe_sec_fsm_msg *msg = (dpoe_sec_fsm_msg*)os_msg;
649 bcmolt_devid device = os_msg->instance;
650 dpoe_sec_link_rec *link_rec;
651 dpoe_sec_fsm_event_data evt;
652
653 link_rec = hash_table_get(ctxt[device].link_map, (uint8_t*)&msg->link);
654 if (link_rec == NULL)
655 {
656 BCM_LOG(INFO, dpoe_sec_log_id[device], "Failed to find link: PON %u, "BCMOS_MACADDR_FMT_STR"\n",
657 msg->link.epon_ni, BCMOS_MACADDR_PARAMS(&msg->link.mac_address));
658 }
659 else
660 {
661 evt.type = DPOE_SEC_FSM_EVENT_RX_EAPOL;
662 evt.data.rx_frame.val = msg->data.rx_frame.frame;
663 evt.data.rx_frame.len = msg->data.rx_frame.length;
664 _dpoe_sec_fsm_exec(link_rec, &evt);
665 }
666
667 bcmos_free(os_msg);
668}
669
670static void _dpoe_sec_fsm_link_auth_complete(dpoe_sec_link_rec* link_rec, bcmos_errno status)
671{
672 dpoe_sec_fsm_event_data evt;
673
674 evt.type = DPOE_SEC_FSM_EVENT_AUTH_COMPLETE;
675 evt.data.sub_status = status;
676
677 _dpoe_sec_fsm_exec(link_rec, &evt);
678}
679
680static void _dpoe_sec_fsm_link_mka_complete(dpoe_sec_link_rec* link_rec, bcmos_errno status)
681{
682 dpoe_sec_fsm_event_data evt;
683
684 evt.type = DPOE_SEC_FSM_EVENT_MKA_COMPLETE;
685 evt.data.sub_status = status;
686
687 _dpoe_sec_fsm_exec(link_rec, &evt);
688}
689
690static bcmos_errno _dpoe_sec_fsm_init_task(bcmolt_devid device)
691{
692 bcmos_task_parm task_params =
693 {
694 .name = ctxt[device].task_name,
695 .priority = TASK_PRIORITY_USER_APPL_DPOE_SEC,
696 .core = BCMOS_CPU_CORE_ANY, /* No CPU affinity */
697 .init_handler = NULL
698 };
699 snprintf(ctxt[device].task_name, sizeof(ctxt[device].task_name), "user_appl_dpoe_sec%u", device);
700 bcmos_errno rc = bcmos_task_create(&ctxt[device].task, &task_params);
701
702 return rc;
703}
704
705
706static bcmos_errno _dpoe_sec_fsm_init_module(bcmolt_devid device)
707{
708 bcmos_module_parm module_params =
709 {
710 .qparm = { .name = ctxt[device].msg_queue_name, .size = DPOE_SEC_FSM_TASK_MSG_Q_SIZE },
711 .init = NULL
712 };
713 snprintf(ctxt[device].msg_queue_name, sizeof(ctxt[device].msg_queue_name), "dpoe_sec_msg_q%u", device);
714 return bcmos_module_create(BCMOS_MODULE_ID_USER_APPL_DPOE_SEC + device, &ctxt[device].task, &module_params);
715}
716
717static bcmos_errno _dpoe_sec_fsm_send_os_msg(
718 bcmolt_devid device,
719 bcmolt_epon_link_key link_key,
720 bcmos_msg_id type,
721 dpoe_sec_fsm_msg_data *data)
722{
723 bcmos_errno rc;
724 dpoe_sec_fsm_msg *msg = bcmos_calloc(sizeof(*msg));
725 if (msg == NULL)
726 {
727 BCM_LOG(ERROR, dpoe_sec_log_id[device], "OS Message calloc failed\n");
728 return BCM_ERR_NOMEM;
729 }
730
731 msg->os_msg.instance = device;
732 msg->os_msg.type = type;
733 msg->link = link_key;
734 msg->data = *data;
735 rc = bcmos_msg_dispatch(&msg->os_msg, BCMOS_MSG_SEND_AUTO_FREE);
736 if (BCM_ERR_OK != rc)
737 {
738 BCM_LOG(ERROR, dpoe_sec_log_id[device], "OS Message send failed (%s)\n", bcmos_strerror(rc));
739 }
740
741 return rc;
742}
743
744bcmos_errno dpoe_sec_fsm_link_start(bcmolt_devid device, bcmolt_epon_link_key link_key, dpoe_sec_fsm_start_data *cfg)
745{
746 dpoe_sec_fsm_msg_data data;
747
748 data.start = *cfg;
749
750 return _dpoe_sec_fsm_send_os_msg(device, link_key, BCMOS_MSG_ID_DPOE_SEC_START, &data);
751}
752
753bcmos_errno dpoe_sec_fsm_link_rx_oam(bcmolt_devid device, bcmolt_epon_link_key link_key, uint8_t *oam, uint16_t length)
754{
755 dpoe_sec_fsm_msg_data data;
756
757 data.rx_frame.frame = oam;
758 data.rx_frame.length = length;
759
760 return _dpoe_sec_fsm_send_os_msg(device, link_key, BCMOS_MSG_ID_DPOE_SEC_RX_OAM, &data);
761}
762
763bcmos_errno dpoe_sec_fsm_link_rx_eapol(
764 bcmolt_devid device,
765 bcmolt_epon_link_key link_key,
766 uint8_t *eapol,
767 uint16_t length)
768{
769 dpoe_sec_fsm_msg_data data;
770
771 data.rx_frame.frame = eapol;
772 data.rx_frame.length = length;
773
774 return _dpoe_sec_fsm_send_os_msg(device, link_key, BCMOS_MSG_ID_DPOE_SEC_RX_EAPOL, &data);
775}
776
777bcmos_errno dpoe_sec_fsm_init(
778 f_dpoe_sec_cert_trust_cb cert_trust_cb,
779 f_dpoe_sec_fsm_cb fsm_complete_cb)
780{
781 bcmos_errno rc;
782
783 for (uint32_t device = 0; device < BCMTR_MAX_OLTS; device++)
784 {
785 rc = _dpoe_sec_fsm_init_task(device);
786 BUG_ON(rc != BCM_ERR_OK);
787
788 rc = _dpoe_sec_fsm_init_module(device);
789 BUG_ON(rc != BCM_ERR_OK);
790
791 char log_name[MAX_DEV_LOG_ID_NAME];
792 snprintf(log_name, sizeof(log_name), "user_appl_dpoe_sec%u", device);
793 dpoe_sec_log_id[device] = bcm_dev_log_id_register(log_name, DEV_LOG_LEVEL_INFO, DEV_LOG_ID_TYPE_BOTH);
794
795 bcmos_msg_register(
796 BCMOS_MSG_ID_DPOE_SEC_START,
797 device,
798 BCMOS_MODULE_ID_USER_APPL_DPOE_SEC + device,
799 _dpoe_sec_fsm_link_start_handle);
800 bcmos_msg_register(
801 BCMOS_MSG_ID_DPOE_SEC_RX_OAM,
802 device,
803 BCMOS_MODULE_ID_USER_APPL_DPOE_SEC + device,
804 _dpoe_sec_fsm_link_rx_oam_handle);
805 bcmos_msg_register(
806 BCMOS_MSG_ID_DPOE_SEC_RX_EAPOL,
807 device,
808 BCMOS_MODULE_ID_USER_APPL_DPOE_SEC + device,
809 _dpoe_sec_fsm_link_rx_eapol_handle);
810
811 ctxt[device].link_map = hash_table_create(
812 DPOE_SEC_FSM_MAX_LINKS,
813 sizeof(dpoe_sec_link_rec),
814 sizeof(bcmolt_epon_link_key),
815 "dpoe_sec_link_state");
816 BUG_ON(ctxt[device].link_map == NULL);
817 }
818
819 _fsm_complete = fsm_complete_cb;
820
821 dpoe_eap_tls_init(_dpoe_sec_fsm_link_auth_complete, cert_trust_cb);
822 dpoe_sec_mka_fsm_init(_dpoe_sec_fsm_link_mka_complete);
823
824 return rc;
825}
826