blob: e193148a49d6aa7e21c18e7230de4dd757858974 [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
7Unless you and Broadcom execute a separate written software license
8agreement governing use of this software, this software is licensed
9to you under the terms of the GNU General Public License version 2
10(the "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php,
11with 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
22Not withstanding the above, under no circumstances may you combine
23this software in any way with any other Broadcom software provided
24under a license other than the GPL, without Broadcom's express prior
25written consent.
26
27:>
28*/
29
30/* This file is the master event handler for the EPON OAM negotiation task -
31 It accepts events from the embedded software and the host interface, supported events are
32 1. Start OAM negotiaton (from host interface)
33 2. Stop OAM negotiation (from host interface)
34 3. RX Frame (from ONU via embedded firmware)
35 4. Timeout
36
37 It dispatches these events to the OAM specific state machine. Currently we support
38 OAM negotiation for BRCM, DPoE, and CTC OAM standards.
39*/
40
41#include "bcmolt_eon_private.h"
42#include <bcmolt_api.h>
43#include <bcmolt_model_types.h>
44#include <bcmolt_msg_pack.h>
45#include "oam_sets/oam_common.h"
46
47#define EON_TASK_MSG_Q_SIZE 64
48
49typedef enum
50{
51 EON_EVENT_TYPE_FRAME_RX,
52 EON_EVENT_TYPE_OAM_NEG_START,
53 EON_EVENT_TYPE_OAM_NEG_STOP,
54 EON_EVENT_TYPE_OAM_TIMER_EXPIRE,
55
56 EON_EVENT_TYPE_COUNT
57} eon_event_type;
58
59typedef union
60{
61 eon_frame_data frame_rx;
62} eon_event_data;
63
64typedef struct
65{
66 eon_event_type type;
67 eon_link_state *link;
68 eon_event_data data;
69} eon_event;
70
71typedef bcmos_errno (*eon_event_handler)(const eon_event* in_event);
72
73static const char* _evname[EON_EVENT_TYPE_COUNT] =
74{
75 [EON_EVENT_TYPE_FRAME_RX] = "eon_event_type_frame_rx",
76 [EON_EVENT_TYPE_OAM_NEG_START] = "eon_event_type_oam_neg_start",
77 [EON_EVENT_TYPE_OAM_NEG_STOP] = "eon_event_type_oam_neg_stop",
78 [EON_EVENT_TYPE_OAM_TIMER_EXPIRE] = "eon_event_type_oam_timer_expire"
79};
80
81static bcmcli_enum_val eon_oam_set_id_table[EON_OAM_SET_ID_COUNT+1] =
82{
83 { .name = "dpoe", .val = EON_OAM_SET_ID_DPOE },
84 { .name = "brcm", .val = EON_OAM_SET_ID_BRCM },
85 { .name = "ctc", .val = EON_OAM_SET_ID_CTC },
86 BCMCLI_ENUM_LAST
87};
88
89eon_global_state eon_state[BCMTR_MAX_OLTS] = {};
90
91#define HEARTBEAT_SEND_PERIOD 1
92#define HEARTBEAT_SEND_OFFSET 15
93#define HEARTBEAT_RECEIVE_TIMEOUT 5
94#define OAM_TIMEOUT_US (HEARTBEAT_RECEIVE_TIMEOUT * 1000 * 1000)
95
96static bcmos_bool epon_oam_neg_running = BCMOS_FALSE;
97
98static inline int _link_key_cmp(const eon_link_state* a, const eon_link_state* b)
99{
100 return memcmp(&a->link_key.link, &b->link_key.link, sizeof(a->link_key.link));
101}
102
103RB_GENERATE_INLINE(link_state_map, eon_link_state, rb_entry, _link_key_cmp);
104
105
106static bcmos_errno _eon_init_task(bcmolt_devid device)
107{
108 bcmos_task_parm task_params =
109 {
110 .name = eon_state[device].task_name,
111 .priority = TASK_PRIORITY_USER_APPL_EON,
112 .core = BCMOS_CPU_CORE_ANY, /* No CPU affinity */
113 .init_handler = NULL
114 };
115 snprintf(eon_state[device].task_name, sizeof(eon_state[device].task_name), "user_appl_eon%u", device);
116 bcmos_errno rc = bcmos_task_create(&eon_state[device].task, &task_params);
117
118 return rc;
119}
120
121
122static bcmos_errno _eon_init_module(bcmolt_devid device)
123{
124 bcmos_module_parm module_params =
125 {
126 .qparm = { .name = eon_state[device].msg_queue_name, .size = EON_TASK_MSG_Q_SIZE },
127 .init = NULL
128 };
129 snprintf(eon_state[device].msg_queue_name, sizeof(eon_state[device].msg_queue_name), "eon_msg_q%u", device);
130 return bcmos_module_create(BCMOS_MODULE_ID_USER_APPL_EON + device, &eon_state[device].task, &module_params);
131}
132
133static bcmos_errno _eon_send_os_msg(bcmolt_devid device, bcmos_msg_id type, eon_task_msg_data *data)
134{
135 bcmos_errno rc;
136 eon_task_msg *msg = bcmos_calloc(sizeof(*msg));
137 if (msg == NULL)
138 {
139 EON_LOG(ERROR, device, "OS Message calloc failed\n");
140 return BCM_ERR_NOMEM;
141 }
142
143 msg->os_msg.instance = device;
144 msg->os_msg.type = type;
145 msg->data = *data;
146 rc = bcmos_msg_dispatch(&msg->os_msg, BCMOS_MSG_SEND_AUTO_FREE);
147 if (BCM_ERR_OK != rc)
148 {
149 EON_LOG(ERROR, device, "OS Message send failed (%s)\n", bcmos_strerror(rc));
150 }
151
152 return rc;
153}
154
155static void _eon_destroy_link_state(eon_link_state* link_state)
156{
157 EON_LINK_LOG(DEBUG, &link_state->link_key, "Destroying link\n");
158 bcmos_timer_destroy(&link_state->oam_timer);
159 RB_REMOVE(link_state_map, &eon_state[link_state->link_key.device_id].link_state_map, link_state);
160 if (NULL != link_state->tx.payload)
161 {
162 bcmos_free(link_state->tx.payload);
163 }
164 if (NULL != link_state->rx.payload)
165 {
166 bcmos_free(link_state->rx.payload);
167 }
168 if (NULL != link_state->org_spec_state)
169 {
170 bcmos_free(link_state->org_spec_state);
171 }
172 bcmos_free(link_state);
173}
174
175static eon_link_state* _eon_find_link_state(const eon_link_key* link_key)
176{
177 eon_link_state query_key = { .link_key.link = link_key->link };
178
179 return RB_FIND(link_state_map, &eon_state[link_key->device_id].link_state_map, &query_key);
180}
181
182static void _eon_default_callback_fn(void *context, const eon_link_key* link_key, bcmos_errno result)
183{
184 eon_link_state *link_state = _eon_find_link_state(link_key);
185
186 EON_LINK_LOG(
187 INFO, link_key, "OAM negotiation completed (%s), flags %04x\n", bcmos_strerror(result), link_state->oam_state);
188}
189
190static bcmos_errno _eon_inject_frame(eon_link_key* link_key, uint16_t payload_length, uint8_t *payload_addr)
191{
192 bcmos_errno rc;
193 bcmolt_epon_link_inject_frame inject_frame;
194 bcmolt_epon_link_key epon_link_key = link_key->link;
195 bcmolt_ethernet_frame_unmasked frame =
196 {
197 .frame_octets =
198 {
199 .len = payload_length,
200 .val = payload_addr
201 }
202 };
203
204 BCMOLT_PROXY_INIT(&inject_frame, epon_link, inject_frame, epon_link_key);
205 BCMOLT_PROXY_PROP_SET(&inject_frame, epon_link, inject_frame, frame, frame);
206 rc = bcmolt_proxy_send(link_key->device_id, &inject_frame.hdr);
207 if (BCM_ERR_OK != rc)
208 {
209 EON_LINK_LOG(ERROR, link_key, "inject operation failed (%s)\n", bcmos_strerror(rc));
210 }
211
212 return rc;
213}
214
215static bcmos_errno _eon_clear_prov(eon_link_key *link_key)
216{
217 bcmos_errno err;
218 bcmolt_epon_link_key key = link_key->link;
219 bcmolt_epon_link_oam_keepalive_timer_stop stop_oper;
220 bcmolt_oam_heartbeat_config hb_cfg = {};
221 bcmolt_epon_link_cfg link_cfg;
222
223 BCMOLT_OPER_INIT(&stop_oper, epon_link, oam_keepalive_timer_stop, key);
224 err = bcmolt_oper_submit(link_key->device_id, &stop_oper.hdr);
225 if (BCM_ERR_OK != err)
226 {
227 return err;
228 }
229
230 hb_cfg.transmit_frame.len = 0;
231 hb_cfg.transmit_frame.val = NULL;
232 hb_cfg.ignored_receive_frame_template.frame_octets.len = 0;
233 hb_cfg.ignored_receive_frame_template.frame_octets.val = NULL;
234 hb_cfg.ignored_receive_frame_template.mask_octets.len = 0;
235 hb_cfg.ignored_receive_frame_template.mask_octets.val = NULL;
236 hb_cfg.receive_timeout = 5;
237 hb_cfg.maximum_receive_size = 0;
238 BCMOLT_CFG_INIT(&link_cfg, epon_link, key);
239 BCMOLT_CFG_PROP_SET(&link_cfg, epon_link, oam_heartbeat_config, hb_cfg);
240 err = bcmolt_cfg_set(link_key->device_id, &link_cfg.hdr);
241
242 return err;
243}
244
245static bcmos_errno _eon_set_oam_heartbeat_config(const eon_link_state *link_state)
246{
247 bcmos_errno rc;
248 bcmolt_oam_heartbeat_config oam_heartbeat_config = {};
249
250 oam_heartbeat_config.receive_timeout = HEARTBEAT_RECEIVE_TIMEOUT;
251 oam_heartbeat_config.maximum_receive_size = link_state->max_pdu_size;
252
253 /* The BCM68620 TX heartbeat provisioning does not include the first 15 bytes - SA, DA, EtherType or Subtype */
254 oam_heartbeat_config.transmit_frame.val = &link_state->tx.payload[HEARTBEAT_SEND_OFFSET];
255 oam_heartbeat_config.transmit_frame.len = link_state->tx.length - HEARTBEAT_SEND_OFFSET;
256
257 oam_heartbeat_config.ignored_receive_frame_template.frame_octets.val = link_state->rx.payload;
258 oam_heartbeat_config.ignored_receive_frame_template.frame_octets.len = link_state->rx.length;
259
260 /* forward OAM frames with any differences to the host */
261 oam_heartbeat_config.ignored_receive_frame_template.mask_octets.val = bcmos_calloc(link_state->rx.length);
262 if (NULL != oam_heartbeat_config.ignored_receive_frame_template.mask_octets.val)
263 {
264 memset(oam_heartbeat_config.ignored_receive_frame_template.mask_octets.val, 0xFF, link_state->rx.length);
265 oam_heartbeat_config.ignored_receive_frame_template.mask_octets.len = link_state->rx.length;
266 }
267 else
268 {
269 return BCM_ERR_NOMEM;
270 }
271
272 bcmolt_epon_link_cfg link_cfg;
273 BCMOLT_CFG_INIT(&link_cfg, epon_link, link_state->link_key.link);
274 BCMOLT_CFG_PROP_SET(&link_cfg, epon_link, oam_heartbeat_config, oam_heartbeat_config);
275 rc = bcmolt_cfg_set(link_state->link_key.device_id, &link_cfg.hdr); /* call API */
276
277 bcmos_free(oam_heartbeat_config.ignored_receive_frame_template.mask_octets.val);
278
279 return rc;
280}
281
282static bcmos_errno _eon_start_oam_heartbeat(eon_link_state *link_state)
283{
284 bcmos_errno rc;
285
286 rc = _eon_set_oam_heartbeat_config(link_state);
287 if (BCM_ERR_OK == rc)
288 {
289 bcmolt_epon_link_key emb_link_key = link_state->link_key.link;
290 bcmolt_epon_link_oam_keepalive_timer_start start_heartbeat_op;
291 BCMOLT_OPER_INIT(&start_heartbeat_op, epon_link, oam_keepalive_timer_start, emb_link_key);
292 BCMOLT_OPER_PROP_SET(
293 &start_heartbeat_op,
294 epon_link,
295 oam_keepalive_timer_start,
296 send_period,
297 HEARTBEAT_SEND_PERIOD);
298 rc = bcmolt_oper_submit(link_state->link_key.device_id, &start_heartbeat_op.hdr);
299 if (BCM_ERR_OK != rc)
300 {
301 EON_LINK_LOG(ERROR, &link_state->link_key, "keepalive start operation submit failed (%s)\n",
302 bcmos_strerror(rc));
303 }
304 }
305 else
306 {
307 EON_LINK_LOG(ERROR, &link_state->link_key, "failed to set heartbeat configuration(%s)\n", bcmos_strerror(rc));
308 }
309
310 return rc;
311}
312
313static bcmos_errno _eon_send_info_frame(eon_link_state *link_state)
314{
315 eon_frame_data frame_tx_req;
316 bcmos_errno rc;
317
318 rc = build_tx_info_frame(link_state, &frame_tx_req);
319 if (BCM_ERR_OK == rc)
320 {
321 rc = _eon_inject_frame(&link_state->link_key, frame_tx_req.length, frame_tx_req.payload);
322 if (BCM_ERR_OK == rc)
323 {
324 bcmos_timer_start(&link_state->oam_timer, OAM_TIMEOUT_US); /* start timer for rx frame */
325 }
326 else
327 {
328 EON_LINK_LOG(WARNING, &link_state->link_key, "failed to inject frame (%s)\n", bcmos_strerror(rc));
329 }
330 bcmos_free(frame_tx_req.payload);
331 }
332
333 return rc;
334}
335
336static bcmos_errno _eon_complete_negotiation(eon_link_state *link_state, uint8_t *rx_payload, uint16_t rx_length)
337{
338 bcmos_errno rc;
339 eon_frame_data frame_tx_req;
340
341 rc = build_tx_info_frame(link_state, &frame_tx_req);
342 if (BCM_ERR_OK != rc)
343 {
344 return rc;
345 }
346 link_state->tx.payload = frame_tx_req.payload;
347 link_state->tx.length = frame_tx_req.length;
348 EON_LINK_LOG(DEBUG, &link_state->link_key, "Setting TX payload\n");
349
350 link_state->rx.payload = bcmos_calloc(rx_length);
351 if (NULL == link_state->rx.payload)
352 {
353 return BCM_ERR_NOMEM;
354 }
355 memcpy(link_state->rx.payload, rx_payload, rx_length);
356 link_state->rx.length = rx_length;
357 EON_LINK_LOG(DEBUG, &link_state->link_key, "Setting RX mask\n");
358
359 if (link_state->is_heartbeat_autostart)
360 {
361 rc = _eon_start_oam_heartbeat(link_state);
362 EON_LINK_LOG(INFO, &link_state->link_key, "start OAM heartbeat: %s\n", bcmos_strerror(rc));
363 }
364 link_state->callback(link_state->context, &link_state->link_key, rc);
365 _eon_destroy_link_state(link_state);
366
367 return BCM_ERR_OK;
368}
369
370static bcmos_errno _eon_event_handler_frame_rx(const eon_event* event)
371{
372 bcmos_errno rc;
373
374 EON_LINK_LOG(DEBUG, &event->link->link_key, "received %u-byte frame beginning at %p\n",
375 event->data.frame_rx.length, event->data.frame_rx.payload);
376
377 /* validates frame, updates flags */
378 rc = handle_rx_info_frame(event->link, event->data.frame_rx.length, event->data.frame_rx.payload);
379 switch (rc)
380 {
381 case BCM_ERR_OK: /* Completed Negotiation */
382 rc = _eon_complete_negotiation(event->link, event->data.frame_rx.payload, event->data.frame_rx.length);
383 break;
384 case BCM_ERR_IN_PROGRESS:
385 rc = _eon_send_info_frame(event->link);
386 break;
387 case BCM_ERR_PARSE:
388 EON_LINK_LOG(INFO, &event->link->link_key, "received non info frame; ignoring\n");
389 rc = BCM_ERR_OK; /* ...and keep running */
390 break;
391 default:
392 break;
393 }
394
395 return rc;
396}
397
398static bcmos_errno _eon_event_handler_start(const eon_event* event)
399{
400 bcmos_errno rc;
401
402 rc = _eon_clear_prov(&event->link->link_key);
403 if (BCM_ERR_OK == rc)
404 {
405 event->link->oam_state = BCMOLT_EPON_OAM_OAM_FLAGS_LOCAL_EVALUATING;
406 rc = _eon_send_info_frame(event->link);
407 }
408 return rc;
409}
410
411static bcmos_errno _eon_event_handler_stop(const eon_event* event)
412{
413 EON_LINK_LOG(INFO, &event->link->link_key, "OAM stop command received\n");
414 _eon_destroy_link_state(event->link);
415 return BCM_ERR_OK;
416}
417
418static bcmos_errno _eon_event_handler_oam_timer_expire(const eon_event* event)
419{
420 EON_LINK_LOG(WARNING, &event->link->link_key, "OAM timer expired\n");
421 return BCM_ERR_TIMEOUT;
422}
423
424static const eon_event_handler event_sm[EON_EVENT_TYPE_COUNT] =
425{
426 [EON_EVENT_TYPE_FRAME_RX] = _eon_event_handler_frame_rx,
427 [EON_EVENT_TYPE_OAM_NEG_START] = _eon_event_handler_start,
428 [EON_EVENT_TYPE_OAM_NEG_STOP] = _eon_event_handler_stop,
429 [EON_EVENT_TYPE_OAM_TIMER_EXPIRE] = _eon_event_handler_oam_timer_expire
430};
431
432static bcmos_errno _eon_event_handler(const eon_event* event)
433{
434 bcmos_errno rc = BCM_ERR_OK;
435
436 if (event->type < EON_EVENT_TYPE_COUNT)
437 {
438 EON_LINK_LOG(DEBUG, &event->link->link_key, "event %s\n", _evname[event->type]);
439 rc = event_sm[event->type](event);
440 }
441 else
442 {
443 EON_LINK_LOG(ERROR, &event->link->link_key, "unknown event %d\n", event->type);
444 }
445
446 return rc;
447}
448
449static void _eon_event_dispatch(const eon_event* event_in)
450{
451 bcmos_errno rc;
452
453 rc = _eon_event_handler(event_in);
454 if (rc != BCM_ERR_OK)
455 {
456 event_in->link->callback(event_in->link->context, &event_in->link->link_key, rc);
457 _eon_destroy_link_state(event_in->link);
458 }
459}
460
461static bcmos_timer_rc _eon_oam_timer_expire(bcmos_timer* timer, long pUser)
462{
463 eon_event event = { .type = EON_EVENT_TYPE_OAM_TIMER_EXPIRE, .link = (eon_link_state *)pUser };
464
465 _eon_event_dispatch(&event);
466
467 return BCMOS_TIMER_OK;
468}
469
470static bcmos_errno _eon_create_link_state(
471 eon_link_state **state,
472 eon_link_key* link_key,
473 eon_oam_set_id oam_set,
474 bcmolt_eon_result_cb cb,
475 void *context,
476 bcmos_bool is_heartbeat_autostart)
477{
478 bcmos_errno rc;
479 eon_link_state *link_state;
480
481 link_state = _eon_find_link_state(link_key);
482 if (link_state != NULL)
483 {
484 EON_LINK_LOG(ERROR, link_key, "OAM negotiation is already in progress\n");
485 return BCM_ERR_ALREADY;
486 }
487
488 link_state = bcmos_calloc(sizeof(*link_state));
489 if (link_state == NULL)
490 {
491 EON_LINK_LOG(ERROR, link_key, "Failed to allocate state record\n");
492 return BCM_ERR_NOMEM;
493 }
494
495 bcmolt_epon_ni_key ni_key = { .epon_ni = link_key->link.epon_ni };
496 bcmolt_epon_ni_cfg ni_cfg;
497
498 BCMOLT_CFG_INIT(&ni_cfg, epon_ni, ni_key);
499 BCMOLT_CFG_PROP_GET(&ni_cfg, epon_ni, mac_address);
500 rc = bcmolt_cfg_get(link_key->device_id, &ni_cfg.hdr);
501 if (BCM_ERR_OK == rc)
502 {
503 link_state->epon_ni_mac_addr = ni_cfg.data.mac_address;
504 }
505 else
506 {
507 EON_LINK_LOG(ERROR, link_key, "Failed to retrieve EPON NI MAC address: %s\n", bcmos_strerror(rc));
508 bcmos_free(link_state);
509 return rc;
510 }
511
512 bcmos_timer_parm timer_spec =
513 {
514 .owner = BCMOS_MODULE_ID_USER_APPL_EON + link_key->device_id,
515 .handler = _eon_oam_timer_expire,
516 .data = (long)link_state
517 };
518 rc = bcmos_timer_create(&link_state->oam_timer, &timer_spec);
519 if (BCM_ERR_OK != rc)
520 {
521 EON_LINK_LOG(ERROR, link_key, "Failed to create timer: %s\n", bcmos_strerror(rc));
522 bcmos_free(link_state);
523 return rc;
524 }
525
526 link_state->link_key = *link_key;
527 link_state->callback = cb ? cb : _eon_default_callback_fn;
528 link_state->context = context;
529 link_state->is_heartbeat_autostart = is_heartbeat_autostart;
530 link_state->oam_set = oam_set;
531 link_state->max_pdu_size = 1536;
532
533 RB_INSERT(link_state_map, &eon_state[link_key->device_id].link_state_map, link_state);
534
535 *state = link_state;
536
537 return BCM_ERR_OK;
538}
539
540static void _eon_task_process_rx(bcmolt_devid device_id, const bcmolt_proxy_rx *rx)
541{
542 eon_event event = { .type = EON_EVENT_TYPE_FRAME_RX };
543
544 const bcmolt_epon_link_key* epon_link_key = (const bcmolt_epon_link_key*)(rx + 1);
545 eon_link_key link_key = { .device_id = device_id, .link = *epon_link_key };
546 eon_link_state *link_state = _eon_find_link_state(&link_key);
547
548 if (link_state != NULL)
549 {
550 EON_LINK_LOG(DEBUG, &link_key, "found existing link\n");
551 const bcmolt_u8_list_u32 frame = ((const bcmolt_epon_link_frame_captured*)rx)->data.frame;
552 event.link = link_state;
553 event.data.frame_rx.payload = frame.val;
554 event.data.frame_rx.length = frame.len;
555 _eon_event_dispatch(&event);
556 }
557 else
558 {
559 EON_LINK_LOG(DEBUG, &link_key, "rx on unknown link\n");
560 }
561}
562
563static void _eon_handle_proxy_rx(bcmos_module_id module_id, bcmos_msg *os_msg)
564{
565 eon_task_msg *msg = (eon_task_msg*)os_msg;
566
567 _eon_task_process_rx(os_msg->instance, msg->data.proxy_rx.rx);
568
569 bcmolt_msg_free(&msg->data.proxy_rx.rx->hdr); /* free cloned indication */
570 bcmos_free(os_msg);
571}
572
573static void _eon_handle_start(bcmos_module_id module_id, bcmos_msg *os_msg)
574{
575 eon_task_msg *msg = (eon_task_msg*)os_msg;
576 eon_link_key link_key = { .device_id = os_msg->instance, .link = msg->data.start.link_key };
577 eon_event event = { .type = EON_EVENT_TYPE_OAM_NEG_START };
578
579 if (BCM_ERR_OK == _eon_create_link_state(
580 &event.link,
581 &link_key,
582 msg->data.start.oam_set,
583 msg->data.start.cb,
584 msg->data.start.context,
585 msg->data.start.is_heartbeat_autostart))
586 {
587 _eon_event_dispatch(&event);
588 }
589
590 bcmos_free(os_msg);
591}
592
593static void _eon_handle_stop(bcmos_module_id module_id, bcmos_msg *os_msg)
594{
595 eon_task_msg *msg = (eon_task_msg*)os_msg;
596 eon_link_key link_key = { .device_id = os_msg->instance, .link = msg->data.stop.link_key };
597 eon_event event = { .type = EON_EVENT_TYPE_OAM_NEG_STOP, .link = _eon_find_link_state(&link_key) };
598
599 if (NULL != event.link)
600 {
601 _eon_event_dispatch(&event);
602 }
603
604 bcmos_free(os_msg);
605}
606
607static bcmos_errno _eon_cmd_start(bcmcli_session *session, const bcmcli_cmd_parm parm[], uint16_t n_parms)
608{
609 bcmos_errno rc;
610 eon_task_msg_data msg_data;
611
612 msg_data.start.link_key.epon_ni = (bcmolt_epon_ni)bcmcli_find_named_parm(session, "epon_ni")->value.unumber;
613 msg_data.start.link_key.mac_address = bcmcli_find_named_parm(session, "mac_address")->value.mac;
614 msg_data.start.oam_set = (eon_oam_set_id)bcmcli_find_named_parm(session, "oam_set")->value.enum_val;
615 msg_data.start.cb = NULL;
616 msg_data.start.context = NULL;
617 msg_data.start.is_heartbeat_autostart = BCMOS_TRUE;
618
619 rc = _eon_send_os_msg(current_device, BCMOS_MSG_ID_EON_START, &msg_data);
620
621 return rc;
622}
623
624static bcmos_errno _eon_cmd_stop(bcmcli_session *session,
625 const bcmcli_cmd_parm parm[],
626 uint16_t n_parms)
627{
628 bcmos_errno rc;
629 eon_task_msg_data msg_data;
630
631 msg_data.stop.link_key.epon_ni = (bcmolt_epon_ni)bcmcli_find_named_parm(session, "epon_ni")->value.unumber;
632 msg_data.stop.link_key.mac_address = bcmcli_find_named_parm(session, "mac_address")->value.mac;
633
634 rc = _eon_send_os_msg(current_device, BCMOS_MSG_ID_EON_STOP, &msg_data);
635
636 return rc;
637}
638
639
640static bcmos_errno _eon_cmd_show(
641 bcmcli_session *session,
642 const bcmcli_cmd_parm parm[],
643 uint16_t n_parms)
644{
645 eon_link_state* link_state;
646 bcmos_bool no_links = BCMOS_TRUE;
647
648 RB_FOREACH(link_state, link_state_map, &eon_state[current_device].link_state_map)
649 {
650 no_links = BCMOS_FALSE;
651 bcmcli_session_print(session,
652 "--> "LINK_KEY_FMT_STR" OAM set %u state %04x\n",
653 LINK_KEY_DATA(&link_state->link_key),
654 link_state->oam_set,
655 link_state->oam_state);
656 }
657 if (no_links)
658 {
659 bcmcli_session_print(session, "no links\n");
660 }
661
662 return BCM_ERR_OK;
663}
664
665
666void bcmolt_user_appl_eon_cli_init(bcmcli_entry *top_dir)
667{
668 static const char *dir_name = "eon";
669
670 if (bcmcli_dir_find(top_dir, dir_name))
671 {
672 return;
673 }
674
675 bcmcli_entry *dir = bcmcli_dir_add(top_dir,
676 dir_name,
677 "EPON OAM negotiation commands",
678 BCMCLI_ACCESS_ADMIN, NULL);
679 BUG_ON(dir == NULL);
680
681 BCMCLI_MAKE_CMD_NOPARM(dir,
682 "show",
683 "Show current EON configuration and state",
684 _eon_cmd_show);
685
686 BCMCLI_MAKE_CMD(dir,
687 "start_oam_negotiation",
688 "Start OAM negotiation for an EPON link",
689 _eon_cmd_start,
690 BCMCLI_MAKE_PARM("epon_ni", "EPON NI", BCMCLI_PARM_UNUMBER, BCMCLI_PARM_FLAG_NONE),
691 BCMCLI_MAKE_PARM("mac_address", "MAC address", BCMCLI_PARM_MAC, BCMCLI_PARM_FLAG_NONE),
692 BCMCLI_MAKE_PARM_ENUM("oam_set", "OAM set", eon_oam_set_id_table, BCMCLI_PARM_FLAG_NONE));
693
694
695 BCMCLI_MAKE_CMD(dir,
696 "stop_oam_negotiation",
697 "Stop in progress OAM negotiation for an EPON link",
698 _eon_cmd_stop,
699 BCMCLI_MAKE_PARM("epon_ni", "EPON NI", BCMCLI_PARM_NUMBER, BCMCLI_PARM_FLAG_NONE),
700 BCMCLI_MAKE_PARM("mac_address", "MAC address", BCMCLI_PARM_MAC, BCMCLI_PARM_FLAG_NONE) );
701}
702
703
704void bcmolt_user_appl_eon_init(void)
705{
706 bcmos_errno rc;
707
708 if (epon_oam_neg_running)
709 {
710 return;
711 }
712
713 for (bcmolt_devid device = 0; device < BCMTR_MAX_OLTS; device++)
714 {
715 rc = _eon_init_task(device);
716 BUG_ON(rc != BCM_ERR_OK);
717
718 rc = _eon_init_module(device);
719 BUG_ON(rc != BCM_ERR_OK);
720
721 char log_name[MAX_DEV_LOG_ID_NAME];
722 snprintf(log_name, sizeof(log_name), "user_appl_eon%u", device);
723 eon_state[device].log_id = bcm_dev_log_id_register(log_name, DEV_LOG_LEVEL_INFO, DEV_LOG_ID_TYPE_BOTH);
724
725 bcmos_msg_register(
726 BCMOS_MSG_ID_EON_START,
727 device,
728 BCMOS_MODULE_ID_USER_APPL_EON + device,
729 _eon_handle_start);
730 bcmos_msg_register(
731 BCMOS_MSG_ID_EON_STOP,
732 device,
733 BCMOS_MODULE_ID_USER_APPL_EON + device,
734 _eon_handle_stop);
735 bcmos_msg_register(
736 BCMOS_MSG_ID_EON_PROXY_RX,
737 device,
738 BCMOS_MODULE_ID_USER_APPL_EON + device,
739 _eon_handle_proxy_rx);
740
741 // initialize the state map
742 RB_INIT(&eon_state[device].link_state_map);
743 }
744
745 epon_oam_neg_running = BCMOS_TRUE;
746}
747
748// public indication handler interface -- called in transport layer context
749bcmos_errno bcmolt_user_appl_eon_process_rx(bcmolt_devid device_id, bcmolt_proxy_rx *rx)
750{
751 bcmos_errno rc;
752 eon_task_msg_data msg_data = {};
753
754 /* Not running --> silently ignore */
755 if (!epon_oam_neg_running)
756 {
757 return BCM_ERR_OK;
758 }
759
760 /* Not our message --> silenty ignore */
761 if ( (BCMOLT_OBJ_ID_EPON_LINK != rx->hdr.obj_type) ||
762 (BCMOLT_EPON_LINK_PROXY_RX_ID_FRAME_CAPTURED != rx->hdr.subgroup) )
763 {
764 return BCM_ERR_OK;
765 }
766
767 /* This is something this application does care about - so clone the message into
768 newly-allocated memory so we can handle it after the original message has been freed */
769 rc = bcmolt_msg_clone((bcmolt_msg**)&msg_data.proxy_rx.rx, &rx->hdr);
770 if (rc != BCM_ERR_OK)
771 {
772 EON_LOG(ERROR, device_id, "Message clone failed: %s\n", bcmos_strerror(rc));
773 return rc;
774 }
775
776 rc = _eon_send_os_msg(device_id, BCMOS_MSG_ID_EON_PROXY_RX, &msg_data);
777 if (rc != BCM_ERR_OK)
778 {
779 bcmolt_msg_free(&msg_data.proxy_rx.rx->hdr);
780 }
781 return rc;
782}
783