blob: 558594c27b5bc314b039a64db9ed78f0b53a6e66 [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 "bcmos_system.h"
31#include "bcmolt_math.h"
32#include "bcmolt_utils.h"
33#include "bcm_dev_log.h"
34#include "bcmolt_msg.h"
35#include "bcmolt_msg_pack.h"
36#include "bcmolt_api.h"
37#include "bcmolt_model_types.h"
38#include "bcmolt_user_appl_epon_oam.h"
39#include "bcmos_hash_table.h"
40
41#define MAX_CONCURRENT_LINKS 2048
42
43typedef struct
44{
45 bcmolt_devid device_id;
46 bcmolt_epon_link_key key;
47 FILE *file;
48 void *buf;
49 uint16_t block_size;
50 uint16_t last_block;
51 uint16_t last_block_size;
52 uint8_t retries;
53 bcmos_bool done;
54 bcmos_timer timer;
55 uint32_t timeout_us;
56 uint32_t last_time;
57} epon_oam_dpoe_fw_upgrade_state;
58
59typedef struct
60{
61 bcmolt_devid device_id;
62 bcmolt_proxy_rx *rx;
63 bcmolt_user_appl_epon_oam_handle_rx_cb cb;
64} epon_oam_proxy_rx_data;
65
66typedef struct
67{
68 epon_oam_dpoe_fw_upgrade_state *state;
69} epon_oam_timeout_data;
70
71typedef union
72{
73 epon_oam_proxy_rx_data proxy_rx;
74 epon_oam_timeout_data timeout;
75} epon_oam_msg_data;
76
77typedef struct
78{
79 bcmos_msg os_msg;
80 epon_oam_msg_data data;
81} epon_oam_msg;
82
83static bcmos_bool is_running = BCMOS_FALSE;
84static dev_log_id epon_oam_log[BCMTR_MAX_OLTS];
85static char mac_buf[MAC_STR_LEN];
86static bcmos_task epon_oam_task;
87static hash_table *dpoe_fw_upgrade_state;
88
89static void epon_oam_handle_os_msg(bcmos_module_id module_id, bcmos_msg *os_msg);
90
91#define EPON_OAM_LOG(level, device, link, fmt, args...) \
92 BCM_LOG_CALLER_FMT(level, epon_oam_log[device], "%u-%s: "fmt, (link)->epon_ni, bcmos_mac_2_str(&(link)->mac_address, mac_buf), ##args)
93
94static bcmos_errno epon_oam_get_mac_da(bcmolt_devid device_id, bcmolt_epon_ni epon, bcmos_mac_address *mac)
95{
96 bcmos_errno err;
97 bcmolt_epon_ni_cfg pon_cfg;
98 bcmolt_epon_ni_key pon_key = { .epon_ni = epon };
99
100 /* retrieve the EPON NI MAC address */
101 BCMOLT_CFG_INIT(&pon_cfg, epon_ni, pon_key);
102 BCMOLT_CFG_PROP_GET(&pon_cfg, epon_ni, mac_address);
103 err = bcmolt_cfg_get(device_id, &pon_cfg.hdr);
104 if (BCM_ERR_OK != err)
105 {
106 BCM_LOG(ERROR, epon_oam_log[device_id], "Failed to retrieve EPON NI MAC address!\n");
107 }
108 else
109 {
110 *mac = pon_cfg.data.mac_address;
111 }
112 return err;
113}
114
115bcmos_errno epon_oam_pack_frame(bcmolt_epon_oam_ethernet_frame *oam_frame, uint8_t **buffer, uint16_t *length)
116{
117 bcmolt_buf buf;
118
119 *length = MAX(bcmolt_epon_oam_ethernet_frame_get_packed_length(oam_frame), 60);
120 *buffer = bcmos_calloc(*length);
121 if (NULL == *buffer)
122 {
123 return BCM_ERR_NOMEM;
124 }
125 bcmolt_buf_init(&buf, *length, *buffer, BCMOLT_BUF_ENDIAN_FIXED);
126 if (!bcmolt_epon_oam_ethernet_frame_pack(oam_frame, &buf))
127 {
128 bcmos_free(*buffer);
129 return BCM_ERR_INTERNAL;
130 }
131
132 return BCM_ERR_OK;
133}
134
135bcmos_errno epon_oam_pack_and_send(bcmolt_devid device_id,
136 bcmolt_epon_ni epon,
137 const bcmos_mac_address *mac,
138 bcmolt_epon_oam_ethernet_frame *oam_frame)
139{
140 bcmos_errno err;
141 bcmolt_epon_link_inject_frame inject_frame;
142 bcmolt_epon_link_key link_key = { .epon_ni = epon, .mac_address = *mac };
143 bcmolt_ethernet_frame_unmasked frame;
144
145 err = epon_oam_pack_frame(oam_frame, &frame.frame_octets.val, &frame.frame_octets.len);
146 if (BCM_ERR_OK != err)
147 {
148 EPON_OAM_LOG(ERROR, device_id, &link_key, "Failed to pack OAM frame: %s!\n", bcmos_strerror(err));
149 return err;
150 }
151
152 BCMOLT_PROXY_INIT(&inject_frame, epon_link, inject_frame, link_key);
153 BCMOLT_PROXY_PROP_SET(&inject_frame, epon_link, inject_frame, frame, frame);
154 err = bcmolt_proxy_send(device_id, &inject_frame.hdr);
155
156 bcmos_free(frame.frame_octets.val);
157
158 return err;
159}
160
161bcmolt_epon_oam_ethernet_frame *epon_oam_unpack(bcmolt_devid device_id, uint32_t len, uint8_t *bytes)
162{
163 bcmolt_buf buf;
164 uint32_t unpack_bytes = sizeof(bcmolt_epon_oam_ethernet_frame);
165 void *unpack_mem;
166 bcmolt_epon_oam_ethernet_frame *frame;
167 void *extra_mem;
168
169 /* We don't know how much space we'll need to unpack the OAM frame. Starting with the known fixed size, we scan the
170 frame to determine the exact space needed */
171 bcmolt_buf_init(&buf, len, bytes, BCMOLT_BUF_ENDIAN_FIXED);
172 if (!bcmolt_epon_oam_ethernet_frame_scan(&buf, &unpack_bytes))
173 {
174 BCM_LOG(ERROR, epon_oam_log[device_id], "Failed to scan OAM frame\n");
175 return NULL;
176 }
177 unpack_mem = bcmos_calloc(unpack_bytes);
178 if (NULL == unpack_mem)
179 {
180 BCM_LOG(ERROR, epon_oam_log[device_id], "Failed to allocate %u bytes required to unpack\n", unpack_bytes);
181 return NULL;
182 }
183 else
184 {
185 BCM_LOG(DEBUG, epon_oam_log[device_id], "Successfully allocated %u bytes required to unpack\n", unpack_bytes);
186 }
187 /* Now that we have an appropriately sized buffer to unpack into, point the fixed structure to the start of the
188 buffer and direct the unpacker to store any additional data immediately after that */
189 frame = (bcmolt_epon_oam_ethernet_frame*)unpack_mem;
190 extra_mem = (void*)(frame + 1);
191
192 bcmolt_buf_init(&buf, len, bytes, BCMOLT_BUF_ENDIAN_FIXED);
193 if (!bcmolt_epon_oam_ethernet_frame_unpack(frame, &buf, &extra_mem))
194 {
195 BCM_LOG(ERROR, epon_oam_log[device_id], "Failed to unpack OAM frame\n");
196 bcmos_free(unpack_mem);
197 return NULL;
198 }
199
200 return frame;
201}
202
203static bcmos_errno epon_oam_make_dpoe_frame(bcmolt_devid device_id,
204 bcmolt_epon_ni epon,
205 bcmolt_epon_oam_ethernet_frame *oam_frame,
206 bcmolt_epon_oam_ethernet_protocol *protocol)
207{
208 bcmos_errno err;
209
210 oam_frame->da = slow_protocol_multicast_mac;
211 err = epon_oam_get_mac_da(device_id, epon, &oam_frame->sa);
212 BCMOS_CHECK_RETURN_ERROR(BCM_ERR_OK != err, err);
213 oam_frame->protocols_count = 1;
214 oam_frame->protocols = protocol;
215 protocol->ethertype = BCMOLT_EPON_OAM_PROTOCOL_TYPE_SLOW_PROTOCOL;
216 protocol->u.slow_protocol.value.subtype = BCMOLT_EPON_OAM_SLOW_PROTOCOL_SUBTYPE_OAM;
217 protocol->u.slow_protocol.value.u.oam.flags =
218 BCMOLT_EPON_OAM_OAM_FLAGS_LOCAL_STABLE | BCMOLT_EPON_OAM_OAM_FLAGS_REMOTE_STABLE;
219 protocol->u.slow_protocol.value.u.oam.content.code = BCMOLT_EPON_OAM_OAM_OPCODE_ORGANIZATION_SPECIFIC;
220 protocol->u.slow_protocol.value.u.oam.content.u.organization_specific.value.oui =
221 BCMOLT_EPON_OAM_WELL_KNOWN_OUI_DPOE;
222
223 return err;
224}
225
226static bcmos_errno epon_oam_send_os_msg(bcmos_msg_id type, epon_oam_msg_data *msg_data)
227{
228 bcmos_errno rc;
229 epon_oam_msg *msg = bcmos_calloc(sizeof(*msg));
230
231 if (msg == NULL)
232 {
233 BCM_LOG(ERROR, epon_oam_log[msg_data->proxy_rx.device_id], "OS msg calloc failed\n");
234 return BCM_ERR_NOMEM;
235 }
236
237 msg->os_msg.type = type;
238 msg->os_msg.handler = epon_oam_handle_os_msg;
239 msg->data = *msg_data;
240 rc = bcmos_msg_send_to_module(BCMOS_MODULE_ID_USER_APPL_EPON_OAM, &msg->os_msg, 0);
241 if (BCM_ERR_OK != rc)
242 {
243 BCM_LOG(ERROR, epon_oam_log[msg_data->proxy_rx.device_id], "OS msg send failed\n");
244 }
245 return rc;
246}
247
248bcmos_errno epon_oam_dpoe_get_critical_info(bcmolt_devid device_id,
249 bcmolt_epon_ni epon,
250 bcmos_mac_address *mac)
251{
252 bcmos_errno err = BCM_ERR_OK;
253
254 /* OAM stuff */
255 bcmolt_epon_oam_ethernet_frame oam_frame;
256 bcmolt_epon_oam_ethernet_protocol protocol;
257 bcmolt_epon_oam_dpoe_var_descriptor vars[3] = {};
258
259 err = epon_oam_make_dpoe_frame(device_id, epon, &oam_frame, &protocol);
260 BCMOS_CHECK_RETURN_ERROR(BCM_ERR_OK != err, err);
261 protocol.u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value.op =
262 BCMOLT_EPON_OAM_DPOE_OPCODE_GET_REQUEST;
263 protocol.u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value.u.get_request.vars_count =
264 3;
265 protocol.u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value.u.get_request.vars = vars;
266 vars[0].branch = BCMOLT_EPON_OAM_DPOE_BRANCH_EXTENDED_ATTRIBUTE;
267 vars[0].u.extended_attribute.leaf = BCMOLT_EPON_OAM_DPOE_LEAF_ATTRIBUTE_ONU_ID;
268 vars[1].branch = BCMOLT_EPON_OAM_DPOE_BRANCH_EXTENDED_ATTRIBUTE;
269 vars[1].u.extended_attribute.leaf = BCMOLT_EPON_OAM_DPOE_LEAF_ATTRIBUTE_MAX_LOGICAL_LINKS;
270 vars[2].branch = BCMOLT_EPON_OAM_DPOE_BRANCH_END;
271 vars[2].u.end.unknown_count = 0;
272 vars[2].u.end.unknown = NULL;
273
274 return epon_oam_pack_and_send(device_id, epon, mac, &oam_frame);
275}
276
277bcmos_errno epon_oam_dpoe_set_oam_rate(bcmolt_devid device_id,
278 bcmolt_epon_ni epon,
279 bcmos_mac_address *mac,
280 uint8_t min,
281 uint8_t max)
282{
283 bcmos_errno err = BCM_ERR_OK;
284
285 /* OAM stuff */
286 bcmolt_epon_oam_ethernet_frame oam_frame;
287 bcmolt_epon_oam_ethernet_protocol protocol;
288 bcmolt_epon_oam_dpoe_var_container_base vars[2] = {};
289
290 err = epon_oam_make_dpoe_frame(device_id, epon, &oam_frame, &protocol);
291 BCMOS_CHECK_RETURN_ERROR(BCM_ERR_OK != err, err);
292 protocol.u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value.op =
293 BCMOLT_EPON_OAM_DPOE_OPCODE_SET_REQUEST;
294 protocol.u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value.u.set_request.vars_count =
295 2;
296 protocol.u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value.u.set_request.vars = vars;
297 vars[0].branch = BCMOLT_EPON_OAM_DPOE_BRANCH_EXTENDED_ATTRIBUTE;
298 vars[0].u.extended_attribute.attribute.leaf = BCMOLT_EPON_OAM_DPOE_LEAF_ATTRIBUTE_OAM_RATE;
299 vars[0].u.extended_attribute.attribute.u.oam_rate.minimum_oam_rate = min;
300 vars[0].u.extended_attribute.attribute.u.oam_rate.maximum_oam_rate = max;
301 vars[1].branch = BCMOLT_EPON_OAM_DPOE_BRANCH_END;
302 vars[1].u.end.unknown_count = 0;
303 vars[1].u.end.unknown = NULL;
304
305 return epon_oam_pack_and_send(device_id, epon, mac, &oam_frame);
306}
307
308bcmos_errno epon_oam_dpoe_set_report_thresholds(bcmolt_devid device_id,
309 bcmolt_epon_ni epon,
310 bcmos_mac_address *mac,
311 uint8_t report_values_per_queue_set,
312 bcmolt_epon_oam_queue_sets queue_sets,
313 uint8_t num_queue_sets)
314{
315 bcmos_errno err = BCM_ERR_OK;
316
317 /* OAM stuff */
318 bcmolt_epon_oam_ethernet_frame oam_frame;
319 bcmolt_epon_oam_ethernet_protocol protocol;
320 bcmolt_epon_oam_dpoe_var_container_base vars[2] = {};
321
322 err = epon_oam_make_dpoe_frame(device_id, epon, &oam_frame, &protocol);
323 BCMOS_CHECK_RETURN_ERROR(BCM_ERR_OK != err, err);
324 protocol.u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value.op =
325 BCMOLT_EPON_OAM_DPOE_OPCODE_SET_REQUEST;
326 protocol.u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value.u.set_request.vars_count =
327 2;
328 protocol.u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value.u.set_request.vars = vars;
329 vars[0].branch = BCMOLT_EPON_OAM_DPOE_BRANCH_EXTENDED_ATTRIBUTE;
330 vars[0].u.extended_attribute.attribute.leaf = BCMOLT_EPON_OAM_DPOE_LEAF_ATTRIBUTE_REPORT_THRESHOLDS;
331 vars[0].u.extended_attribute.attribute.u.report_thresholds.number_of_queue_sets = num_queue_sets;
332 vars[0].u.extended_attribute.attribute.u.report_thresholds.report_values_per_queue_set =
333 report_values_per_queue_set;
334 vars[0].u.extended_attribute.attribute.u.report_thresholds.queue_set0 = queue_sets[0];
335 vars[0].u.extended_attribute.attribute.u.report_thresholds.queue_set1 = queue_sets[1];
336 vars[0].u.extended_attribute.attribute.u.report_thresholds.queue_set2 = queue_sets[2];
337 vars[0].u.extended_attribute.attribute.u.report_thresholds.queue_set3 = queue_sets[3];
338 vars[1].branch = BCMOLT_EPON_OAM_DPOE_BRANCH_END;
339 vars[1].u.end.unknown_count = 0;
340 vars[1].u.end.unknown = NULL;
341
342 return epon_oam_pack_and_send(device_id, epon, mac, &oam_frame);
343}
344
345bcmos_errno epon_oam_dpoe_set_encryption(
346 bcmolt_devid device_id,
347 bcmolt_epon_ni epon,
348 bcmos_mac_address *mac,
349 bcmolt_epon_oam_dpoe_encryption_mode enc_mode,
350 uint16_t period)
351{
352 bcmos_errno err = BCM_ERR_OK;
353
354 /* OAM stuff */
355 bcmolt_epon_oam_ethernet_frame oam_frame;
356 bcmolt_epon_oam_ethernet_protocol protocol;
357 bcmolt_epon_oam_dpoe_var_container_base vars[3] = {};
358
359 err = epon_oam_make_dpoe_frame(device_id, epon, &oam_frame, &protocol);
360 BCMOS_CHECK_RETURN_ERROR(BCM_ERR_OK != err, err);
361 protocol.u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value.op =
362 BCMOLT_EPON_OAM_DPOE_OPCODE_SET_REQUEST;
363 protocol.u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value.u.set_request.vars_count =
364 3;
365 protocol.u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value.u.set_request.vars = vars;
366 vars[0].branch = BCMOLT_EPON_OAM_DPOE_BRANCH_EXTENDED_ATTRIBUTE;
367 vars[0].u.extended_attribute.attribute.leaf = BCMOLT_EPON_OAM_DPOE_LEAF_ATTRIBUTE_ENCRYPT_MODE;
368 vars[0].u.extended_attribute.attribute.u.encrypt_mode.encryption_method = enc_mode;
369 vars[1].branch = BCMOLT_EPON_OAM_DPOE_BRANCH_EXTENDED_ATTRIBUTE;
370 vars[1].u.extended_attribute.attribute.leaf = BCMOLT_EPON_OAM_DPOE_LEAF_ATTRIBUTE_KEY_EXPIRY_TIME;
371 vars[1].u.extended_attribute.attribute.u.key_expiry_time.time = period;
372 vars[2].branch = BCMOLT_EPON_OAM_DPOE_BRANCH_END;
373 vars[2].u.end.unknown_count = 0;
374 vars[2].u.end.unknown = NULL;
375
376 return epon_oam_pack_and_send(device_id, epon, mac, &oam_frame);
377}
378
379bcmos_bool epon_oam_is_dpoe(bcmolt_epon_oam_ethernet_frame *oam)
380{
381 return ((oam->protocols_count > 0) &&
382 (BCMOLT_EPON_OAM_PROTOCOL_TYPE_SLOW_PROTOCOL == oam->protocols[0].ethertype) &&
383 (BCMOLT_EPON_OAM_SLOW_PROTOCOL_SUBTYPE_OAM == oam->protocols[0].u.slow_protocol.value.subtype) &&
384 (BCMOLT_EPON_OAM_OAM_OPCODE_ORGANIZATION_SPECIFIC ==
385 oam->protocols[0].u.slow_protocol.value.u.oam.content.code) &&
386 (BCMOLT_EPON_OAM_WELL_KNOWN_OUI_DPOE ==
387 oam->protocols[0].u.slow_protocol.value.u.oam.content.u.organization_specific.value.oui));
388}
389
390bcmos_bool epon_oam_is_dpoe_encrypt_response(bcmolt_epon_oam_dpoe_vendor_extended_base *dpoe)
391{
392 return (BCMOLT_EPON_OAM_DPOE_OPCODE_SET_RESPONSE == dpoe->op) &&
393 (dpoe->u.set_response.vars_count > 2) &&
394 (BCMOLT_EPON_OAM_DPOE_BRANCH_EXTENDED_ATTRIBUTE == dpoe->u.set_response.vars[0].branch) &&
395 (BCMOLT_EPON_OAM_DPOE_LEAF_ATTRIBUTE_ENCRYPT_MODE ==
396 dpoe->u.set_response.vars[0].u.extended_attribute.attribute.leaf) &&
397 (BCMOLT_EPON_OAM_DPOE_BRANCH_EXTENDED_ATTRIBUTE == dpoe->u.set_response.vars[1].branch) &&
398 (BCMOLT_EPON_OAM_DPOE_LEAF_ATTRIBUTE_KEY_EXPIRY_TIME ==
399 dpoe->u.set_response.vars[1].u.extended_attribute.attribute.leaf);
400}
401
402static bcmos_errno epon_oam_dpoe_clear_ingress_rules_make_frame(bcmolt_devid device_id,
403 bcmolt_epon_ni epon,
404 bcmos_mac_address *mac,
405 bcmolt_epon_oam_ethernet_frame *oam_frame,
406 bcmolt_epon_oam_ethernet_protocol *protocol,
407 bcmolt_epon_oam_dpoe_var_container_base *vars)
408{
409 bcmos_errno err = BCM_ERR_OK;
410
411 /* OAM stuff */
412 err = epon_oam_make_dpoe_frame(device_id, epon, oam_frame, protocol);
413 BCMOS_CHECK_RETURN_ERROR(BCM_ERR_OK != err, err);
414 protocol->u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value.op =
415 BCMOLT_EPON_OAM_DPOE_OPCODE_SET_REQUEST;
416 protocol->u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value.u.set_request.vars_count =
417 3;
418 protocol->u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value.u.set_request.vars = vars;
419 vars[0].branch = BCMOLT_EPON_OAM_DPOE_BRANCH_OBJECT;
420 vars[1].branch = BCMOLT_EPON_OAM_DPOE_BRANCH_EXTENDED_ACTION;
421 vars[1].u.extended_action.action.leaf = BCMOLT_EPON_OAM_DPOE_LEAF_ACTION_CLEAR_INGRESS_RULES;
422 vars[2].branch = BCMOLT_EPON_OAM_DPOE_BRANCH_END;
423 vars[2].u.end.unknown_count = 0;
424 vars[2].u.end.unknown = NULL;
425
426 return BCM_ERR_OK;
427}
428
429bcmos_errno epon_oam_dpoe_clear_ingress_rules_network_pon(bcmolt_devid device_id,
430 bcmolt_epon_ni epon,
431 bcmos_mac_address *mac)
432{
433 bcmos_errno err = BCM_ERR_OK;
434
435 /* OAM stuff */
436 bcmolt_epon_oam_ethernet_frame oam_frame;
437 bcmolt_epon_oam_ethernet_protocol protocol;
438 bcmolt_epon_oam_dpoe_var_container_base vars[3] = {};
439 uint8_t port = 0;
440
441 epon_oam_dpoe_clear_ingress_rules_make_frame(device_id, epon, mac, &oam_frame, &protocol, vars);
442 BCMOS_CHECK_RETURN_ERROR(BCM_ERR_OK != err, err);
443
444 vars[0].u.object.object_context.object_type = BCMOLT_EPON_OAM_DPOE_OBJECT_TYPE_NETWORK_PON;
445 vars[0].u.object.object_context.u.network_pon.pon_count = 1;
446 vars[0].u.object.object_context.u.network_pon.pon = &port;
447
448 return epon_oam_pack_and_send(device_id, epon, mac, &oam_frame);
449}
450
451bcmos_errno epon_oam_dpoe_clear_ingress_rules_user_port(bcmolt_devid device_id,
452 bcmolt_epon_ni epon,
453 bcmos_mac_address *mac)
454{
455 bcmos_errno err = BCM_ERR_OK;
456
457 /* OAM stuff */
458 bcmolt_epon_oam_ethernet_frame oam_frame;
459 bcmolt_epon_oam_ethernet_protocol protocol;
460 bcmolt_epon_oam_dpoe_var_container_base vars[3] = {};
461 uint8_t port = 0;
462
463 epon_oam_dpoe_clear_ingress_rules_make_frame(device_id, epon, mac, &oam_frame, &protocol, vars);
464 BCMOS_CHECK_RETURN_ERROR(BCM_ERR_OK != err, err);
465
466 vars[0].u.object.object_context.object_type = BCMOLT_EPON_OAM_DPOE_OBJECT_TYPE_USER_PORT;
467 vars[0].u.object.object_context.u.user_port.port_count = 1;
468 vars[0].u.object.object_context.u.user_port.port = &port;
469
470 return epon_oam_pack_and_send(device_id, epon, mac, &oam_frame);
471}
472
473bcmos_errno epon_oam_dpoe_clear_ingress_rules(bcmolt_devid device_id,
474 bcmolt_epon_ni epon,
475 bcmos_mac_address *mac)
476{
477 bcmos_errno err = BCM_ERR_OK;
478
479 err = epon_oam_dpoe_clear_ingress_rules_network_pon(device_id, epon, mac);
480 BCMOS_CHECK_RETURN_ERROR(BCM_ERR_OK != err, err);
481
482 return epon_oam_dpoe_clear_ingress_rules_user_port(device_id, epon, mac);
483}
484
485bcmos_errno epon_oam_dpoe_set_basic_queue_config(bcmolt_devid device_id,
486 bcmolt_epon_ni epon,
487 bcmos_mac_address *mac,
488 uint8_t up_queue_size,
489 uint8_t dn_queue_size)
490{
491 bcmos_errno err = BCM_ERR_OK;
492
493 /* OAM stuff */
494 bcmolt_epon_oam_ethernet_frame oam_frame;
495 bcmolt_epon_oam_ethernet_protocol protocol;
496 bcmolt_epon_oam_dpoe_var_container_base vars[2] = {};
497 bcmolt_epon_oam_dpoe_queue_set up_queue_set;
498 bcmolt_epon_oam_dpoe_queue_set dn_queue_set;
499
500 err = epon_oam_make_dpoe_frame(device_id, epon, &oam_frame, &protocol);
501 BCMOS_CHECK_RETURN_ERROR(BCM_ERR_OK != err, err);
502 protocol.u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value.op =
503 BCMOLT_EPON_OAM_DPOE_OPCODE_SET_REQUEST;
504 protocol.u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value.u.set_request.vars_count =
505 2;
506 protocol.u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value.u.set_request.vars = vars;
507 vars[0].branch = BCMOLT_EPON_OAM_DPOE_BRANCH_EXTENDED_ATTRIBUTE;
508 vars[0].u.extended_attribute.attribute.leaf = BCMOLT_EPON_OAM_DPOE_LEAF_ATTRIBUTE_QUEUE_CONFIG;
509 vars[0].u.extended_attribute.attribute.u.queue_config.number_of_links = 1;
510 vars[0].u.extended_attribute.attribute.u.queue_config.link_configuration = &up_queue_set;
511 up_queue_set.queue_count = 1;
512 up_queue_set.queue_sizes = &up_queue_size;
513 vars[0].u.extended_attribute.attribute.u.queue_config.number_of_ports = 1;
514 vars[0].u.extended_attribute.attribute.u.queue_config.port_configuration = &dn_queue_set;
515 dn_queue_set.queue_count = 1;
516 dn_queue_set.queue_sizes = &dn_queue_size;
517 vars[1].branch = BCMOLT_EPON_OAM_DPOE_BRANCH_END;
518 vars[1].u.end.unknown_count = 0;
519 vars[1].u.end.unknown = NULL;
520
521 return epon_oam_pack_and_send(device_id, epon, mac, &oam_frame);
522}
523
524static bcmos_errno epon_oam_dpoe_add_ingress_rules_make_frame(bcmolt_devid device_id,
525 bcmolt_epon_ni epon,
526 bcmos_mac_address *mac,
527 bcmolt_epon_oam_ethernet_frame *oam_frame,
528 bcmolt_epon_oam_ethernet_protocol *protocol,
529 bcmolt_epon_oam_dpoe_var_container_base *vars,
530 dpoe_rule_vlan_mode vlan_mode,
531 uint8_t vlan_tag[4])
532{
533 static const uint32_t var_count[DPOE_RULE_VLAN_MODE_COUNT] =
534 {
535 [DPOE_RULE_VLAN_MODE_NONE] = 8,
536 [DPOE_RULE_VLAN_MODE_ADD] = 10,
537 [DPOE_RULE_VLAN_MODE_REMOVE] = 9
538 };
539 bcmos_errno err = BCM_ERR_OK;
540
541 /* OAM stuff */
542 err = epon_oam_make_dpoe_frame(device_id, epon, oam_frame, protocol);
543 BCMOS_CHECK_RETURN_ERROR(BCM_ERR_OK != err, err);
544 protocol->u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value.op =
545 BCMOLT_EPON_OAM_DPOE_OPCODE_SET_REQUEST;
546 protocol->u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value.u.set_request.vars_count =
547 var_count[vlan_mode];
548 protocol->u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value.u.set_request.vars = vars;
549 vars[0].branch = BCMOLT_EPON_OAM_DPOE_BRANCH_OBJECT;
550 vars[1].branch = BCMOLT_EPON_OAM_DPOE_BRANCH_EXTENDED_ATTRIBUTE;
551 vars[1].u.extended_attribute.attribute.leaf = BCMOLT_EPON_OAM_DPOE_LEAF_ATTRIBUTE_PORT_INGRESS_RULE;
552 vars[1].u.extended_attribute.attribute.u.port_ingress_rule.rule.subtype = BCMOLT_EPON_OAM_RULE_TYPE_HEADER;
553 vars[1].u.extended_attribute.attribute.u.port_ingress_rule.rule.u.header.precedence = 10;
554 vars[2].branch = BCMOLT_EPON_OAM_DPOE_BRANCH_EXTENDED_ATTRIBUTE;
555 vars[2].u.extended_attribute.attribute.leaf = BCMOLT_EPON_OAM_DPOE_LEAF_ATTRIBUTE_PORT_INGRESS_RULE;
556 vars[2].u.extended_attribute.attribute.u.port_ingress_rule.rule.subtype = BCMOLT_EPON_OAM_RULE_TYPE_CLAUSE;
557 vars[2].u.extended_attribute.attribute.u.port_ingress_rule.rule.u.clause.field_code.code =
558 BCMOLT_EPON_OAM_DPOE_FIELD_CODE_L2DA;
559 vars[2].u.extended_attribute.attribute.u.port_ingress_rule.rule.u.clause.field_code.instance = 0;
560 vars[2].u.extended_attribute.attribute.u.port_ingress_rule.rule.u.clause.msb_mask = 0;
561 vars[2].u.extended_attribute.attribute.u.port_ingress_rule.rule.u.clause.lsb_mask = 0;
562 vars[2].u.extended_attribute.attribute.u.port_ingress_rule.rule.u.clause.operator =
563 BCMOLT_EPON_OAM_RULE_OPERATOR_ALWAYS_MATCH;
564 vars[2].u.extended_attribute.attribute.u.port_ingress_rule.rule.u.clause.match_value_length = 0;
565 vars[2].u.extended_attribute.attribute.u.port_ingress_rule.rule.u.clause.match_value = NULL;
566 vars[3].branch = BCMOLT_EPON_OAM_DPOE_BRANCH_EXTENDED_ATTRIBUTE;
567 vars[3].u.extended_attribute.attribute.leaf = BCMOLT_EPON_OAM_DPOE_LEAF_ATTRIBUTE_PORT_INGRESS_RULE;
568 vars[3].u.extended_attribute.attribute.u.port_ingress_rule.rule.subtype = BCMOLT_EPON_OAM_RULE_TYPE_RESULT;
569 vars[3].u.extended_attribute.attribute.u.port_ingress_rule.rule.u.result.result.result =
570 BCMOLT_EPON_OAM_DPOE_RESULT_QUEUE;
571 vars[4].branch = BCMOLT_EPON_OAM_DPOE_BRANCH_EXTENDED_ATTRIBUTE;
572 vars[4].u.extended_attribute.attribute.leaf = BCMOLT_EPON_OAM_DPOE_LEAF_ATTRIBUTE_PORT_INGRESS_RULE;
573 vars[4].u.extended_attribute.attribute.u.port_ingress_rule.rule.subtype = BCMOLT_EPON_OAM_RULE_TYPE_RESULT;
574 vars[4].u.extended_attribute.attribute.u.port_ingress_rule.rule.u.result.result.result =
575 BCMOLT_EPON_OAM_DPOE_RESULT_FORWARD;
576
577 switch (vlan_mode)
578 {
579 case DPOE_RULE_VLAN_MODE_NONE:
580 break; /* nothing to do */
581 case DPOE_RULE_VLAN_MODE_ADD:
582 vars[5].branch = BCMOLT_EPON_OAM_DPOE_BRANCH_EXTENDED_ATTRIBUTE;
583 vars[5].u.extended_attribute.attribute.leaf = BCMOLT_EPON_OAM_DPOE_LEAF_ATTRIBUTE_PORT_INGRESS_RULE;
584 vars[5].u.extended_attribute.attribute.u.port_ingress_rule.rule.subtype = BCMOLT_EPON_OAM_RULE_TYPE_RESULT;
585 vars[5].u.extended_attribute.attribute.u.port_ingress_rule.rule.u.result.result.result =
586 BCMOLT_EPON_OAM_DPOE_RESULT_INSERT;
587 vars[5].u.extended_attribute.attribute.u.port_ingress_rule.rule.u.result.result.u.insert.field.field.code =
588 BCMOLT_EPON_OAM_DPOE_FIELD_CODE_CVLAN;
589 vars[5].u.extended_attribute.attribute.u.port_ingress_rule.rule.u.result.result.u.insert.field.field.instance = 0;
590 vars[6].branch = BCMOLT_EPON_OAM_DPOE_BRANCH_EXTENDED_ATTRIBUTE;
591 vars[6].u.extended_attribute.attribute.leaf = BCMOLT_EPON_OAM_DPOE_LEAF_ATTRIBUTE_PORT_INGRESS_RULE;
592 vars[6].u.extended_attribute.attribute.u.port_ingress_rule.rule.subtype = BCMOLT_EPON_OAM_RULE_TYPE_RESULT;
593 vars[6].u.extended_attribute.attribute.u.port_ingress_rule.rule.u.result.result.result =
594 BCMOLT_EPON_OAM_DPOE_RESULT_SET;
595 vars[6].u.extended_attribute.attribute.u.port_ingress_rule.rule.u.result.result.u.set.field.field.code =
596 BCMOLT_EPON_OAM_DPOE_FIELD_CODE_CVLAN;
597 vars[6].u.extended_attribute.attribute.u.port_ingress_rule.rule.u.result.result.u.set.field.field.instance = 0;
598 vars[6].u.extended_attribute.attribute.u.port_ingress_rule.rule.u.result.result.u.set.value_count = 4;
599 vars[6].u.extended_attribute.attribute.u.port_ingress_rule.rule.u.result.result.u.set.value = vlan_tag;
600 break;
601 case DPOE_RULE_VLAN_MODE_REMOVE:
602 vars[5].branch = BCMOLT_EPON_OAM_DPOE_BRANCH_EXTENDED_ATTRIBUTE;
603 vars[5].u.extended_attribute.attribute.leaf = BCMOLT_EPON_OAM_DPOE_LEAF_ATTRIBUTE_PORT_INGRESS_RULE;
604 vars[5].u.extended_attribute.attribute.u.port_ingress_rule.rule.subtype = BCMOLT_EPON_OAM_RULE_TYPE_RESULT;
605 vars[5].u.extended_attribute.attribute.u.port_ingress_rule.rule.u.result.result.result =
606 BCMOLT_EPON_OAM_DPOE_RESULT_DELETE;
607 vars[5].u.extended_attribute.attribute.u.port_ingress_rule.rule.u.result.result.u.delete.field.field.code =
608 BCMOLT_EPON_OAM_DPOE_FIELD_CODE_CVLAN;
609 vars[5].u.extended_attribute.attribute.u.port_ingress_rule.rule.u.result.result.u.delete.field.field.instance = 0;
610 break;
611 default:
612 return BCM_ERR_PARM;
613 }
614
615 vars[var_count[vlan_mode]-3].branch = BCMOLT_EPON_OAM_DPOE_BRANCH_EXTENDED_ATTRIBUTE;
616 vars[var_count[vlan_mode]-3].u.extended_attribute.attribute.leaf = BCMOLT_EPON_OAM_DPOE_LEAF_ATTRIBUTE_PORT_INGRESS_RULE;
617 vars[var_count[vlan_mode]-3].u.extended_attribute.attribute.u.port_ingress_rule.rule.subtype = BCMOLT_EPON_OAM_RULE_TYPE_TERMINATOR;
618 vars[var_count[vlan_mode]-2].branch = BCMOLT_EPON_OAM_DPOE_BRANCH_EXTENDED_ACTION;
619 vars[var_count[vlan_mode]-2].u.extended_action.action.leaf = BCMOLT_EPON_OAM_DPOE_LEAF_ACTION_ADD_INGRESS_RULES;
620 vars[var_count[vlan_mode]-1].branch = BCMOLT_EPON_OAM_DPOE_BRANCH_END;
621 vars[var_count[vlan_mode]-1].u.end.unknown_count = 0;
622 vars[var_count[vlan_mode]-1].u.end.unknown = NULL;
623
624 return BCM_ERR_OK;
625}
626
627bcmos_errno epon_oam_dpoe_add_ingress_rules_network_pon(bcmolt_devid device_id,
628 bcmolt_epon_ni epon,
629 bcmos_mac_address *mac,
630 dpoe_rule_vlan_mode vlan_mode,
631 uint8_t vlan_tag[4])
632{
633 bcmos_errno err = BCM_ERR_OK;
634
635 /* OAM stuff */
636 bcmolt_epon_oam_ethernet_frame oam_frame;
637 bcmolt_epon_oam_ethernet_protocol protocol;
638 bcmolt_epon_oam_dpoe_var_container_base vars[10] = {};
639 uint8_t port = 0;
640
641 err = epon_oam_dpoe_add_ingress_rules_make_frame(device_id,
642 epon,
643 mac,
644 &oam_frame,
645 &protocol,
646 vars,
647 vlan_mode,
648 vlan_tag);
649 BCMOS_CHECK_RETURN_ERROR(BCM_ERR_OK != err, err);
650
651 vars[0].u.object.object_context.object_type = BCMOLT_EPON_OAM_DPOE_OBJECT_TYPE_NETWORK_PON;
652 vars[0].u.object.object_context.u.network_pon.pon_count = 1;
653 vars[0].u.object.object_context.u.network_pon.pon = &port;
654 vars[3].u.extended_attribute.attribute.u.port_ingress_rule.rule.u.result.result.u.queue.queue.type =
655 BCMOLT_EPON_OAM_DPOE_OBJECT_TYPE_USER_PORT;
656 vars[3].u.extended_attribute.attribute.u.port_ingress_rule.rule.u.result.result.u.queue.queue.instance = 0;
657 vars[3].u.extended_attribute.attribute.u.port_ingress_rule.rule.u.result.result.u.queue.queue.queue = 0;
658
659 return epon_oam_pack_and_send(device_id, epon, mac, &oam_frame);
660}
661
662bcmos_errno epon_oam_dpoe_add_ingress_rules_user_port(bcmolt_devid device_id,
663 bcmolt_epon_ni epon,
664 bcmos_mac_address *mac,
665 dpoe_rule_vlan_mode vlan_mode,
666 uint8_t vlan_tag[4])
667{
668 bcmos_errno err = BCM_ERR_OK;
669
670 /* OAM stuff */
671 bcmolt_epon_oam_ethernet_frame oam_frame;
672 bcmolt_epon_oam_ethernet_protocol protocol;
673 bcmolt_epon_oam_dpoe_var_container_base vars[10] = {};
674 uint8_t port = 0;
675
676 err = epon_oam_dpoe_add_ingress_rules_make_frame(device_id,
677 epon,
678 mac,
679 &oam_frame,
680 &protocol,
681 vars,
682 vlan_mode,
683 vlan_tag);
684 BCMOS_CHECK_RETURN_ERROR(BCM_ERR_OK != err, err);
685
686 vars[0].u.object.object_context.object_type = BCMOLT_EPON_OAM_DPOE_OBJECT_TYPE_USER_PORT;
687 vars[0].u.object.object_context.u.user_port.port_count = 1;
688 vars[0].u.object.object_context.u.user_port.port = &port;
689 vars[3].u.extended_attribute.attribute.u.port_ingress_rule.rule.u.result.result.u.queue.queue.type =
690 BCMOLT_EPON_OAM_DPOE_OBJECT_TYPE_LINK;
691 vars[3].u.extended_attribute.attribute.u.port_ingress_rule.rule.u.result.result.u.queue.queue.instance = 0;
692 vars[3].u.extended_attribute.attribute.u.port_ingress_rule.rule.u.result.result.u.queue.queue.queue = 0;
693 return epon_oam_pack_and_send(device_id, epon, mac, &oam_frame);
694}
695
696bcmos_errno epon_oam_dpoe_add_ingress_rules(bcmolt_devid device_id,
697 bcmolt_epon_ni epon,
698 bcmos_mac_address *mac)
699{
700 bcmos_errno err = BCM_ERR_OK;
701
702 err = epon_oam_dpoe_add_ingress_rules_network_pon(device_id, epon, mac, DPOE_RULE_VLAN_MODE_NONE, NULL);
703 BCMOS_CHECK_RETURN_ERROR(BCM_ERR_OK != err, err);
704
705 return epon_oam_dpoe_add_ingress_rules_user_port(device_id, epon, mac, DPOE_RULE_VLAN_MODE_NONE, NULL);
706}
707
708bcmos_errno epon_oam_dpoe_add_ingress_rules_with_vlan(bcmolt_devid device_id,
709 bcmolt_epon_ni epon,
710 bcmos_mac_address *mac,
711 uint8_t vlan_tag[4])
712{
713 static uint8_t example_vlan[4] = { 0x81, 0x00, 0x12, 0x34 };
714 bcmos_errno err = BCM_ERR_OK;
715
716 err = epon_oam_dpoe_add_ingress_rules_network_pon(device_id, epon, mac, DPOE_RULE_VLAN_MODE_REMOVE, NULL);
717 BCMOS_CHECK_RETURN_ERROR(BCM_ERR_OK != err, err);
718
719 if (NULL == vlan_tag)
720 {
721 vlan_tag = example_vlan;
722 }
723 return epon_oam_dpoe_add_ingress_rules_user_port(device_id, epon, mac, DPOE_RULE_VLAN_MODE_ADD, vlan_tag);
724}
725
726static bcmos_errno _epon_oam_dpoe_user_traffic_set_action(bcmolt_devid device_id,
727 bcmolt_epon_ni epon,
728 bcmos_mac_address *mac,
729 bcmolt_epon_oam_dpoe_leaf_action action)
730{
731 bcmos_errno err = BCM_ERR_OK;
732
733 /* OAM stuff */
734 bcmolt_epon_oam_ethernet_frame oam_frame;
735 bcmolt_epon_oam_ethernet_protocol protocol;
736 bcmolt_epon_oam_dpoe_var_container_base vars[2] = {};
737
738 err = epon_oam_make_dpoe_frame(device_id, epon, &oam_frame, &protocol);
739 BCMOS_CHECK_RETURN_ERROR(BCM_ERR_OK != err, err);
740 protocol.u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value.op =
741 BCMOLT_EPON_OAM_DPOE_OPCODE_SET_REQUEST;
742 protocol.u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value.u.set_request.vars_count =
743 2;
744 protocol.u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value.u.set_request.vars = vars;
745 vars[0].branch = BCMOLT_EPON_OAM_DPOE_BRANCH_EXTENDED_ACTION;
746 vars[0].u.extended_action.action.leaf = action;
747 vars[1].branch = BCMOLT_EPON_OAM_DPOE_BRANCH_END;
748 vars[1].u.end.unknown_count = 0;
749 vars[1].u.end.unknown = NULL;
750
751 return epon_oam_pack_and_send(device_id, epon, mac, &oam_frame);
752}
753
754bcmos_errno epon_oam_dpoe_disable_user_traffic(bcmolt_devid device_id,
755 bcmolt_epon_ni epon,
756 bcmos_mac_address *mac)
757{
758 return _epon_oam_dpoe_user_traffic_set_action(device_id,
759 epon,
760 mac,
761 BCMOLT_EPON_OAM_DPOE_LEAF_ACTION_DISABLE_USER_TRAFFIC);
762}
763
764bcmos_errno epon_oam_dpoe_enable_user_traffic(bcmolt_devid device_id,
765 bcmolt_epon_ni epon,
766 bcmos_mac_address *mac)
767{
768 return _epon_oam_dpoe_user_traffic_set_action(device_id,
769 epon,
770 mac,
771 BCMOLT_EPON_OAM_DPOE_LEAF_ACTION_ENABLE_USER_TRAFFIC);
772}
773
774static epon_oam_dpoe_fw_upgrade_state *epon_oam_dpoe_fw_upgrade_state_add(const bcmolt_epon_link_key *key)
775{
776 epon_oam_dpoe_fw_upgrade_state state = {};
777 return hash_table_put(dpoe_fw_upgrade_state, (const uint8_t*)key, &state);
778}
779
780static epon_oam_dpoe_fw_upgrade_state* epon_oam_dpoe_fw_upgrade_state_get(const bcmolt_epon_link_key *key)
781{
782 return hash_table_get(dpoe_fw_upgrade_state, (const uint8_t*)key);
783}
784
785static void epon_oam_dpoe_fw_upgrade_state_release(epon_oam_dpoe_fw_upgrade_state *state)
786{
787 if (NULL == state)
788 {
789 BCM_LOG(ERROR, epon_oam_log[0], "Tried to release NULL state\n");
790 return;
791 }
792
793 if (NULL != state->file)
794 {
795 fclose(state->file);
796 }
797 bcmos_free(state->buf);
798 bcmos_timer_destroy(&state->timer);
799 if (!hash_table_remove(dpoe_fw_upgrade_state, (const uint8_t*)&state->key))
800 {
801 BCM_LOG(ERROR, epon_oam_log[state->device_id], "Unable to remove from hash table\n");
802 }
803}
804
805static void epon_oam_dpoe_send_block(bcmolt_devid device_id,
806 const bcmolt_epon_link_key *key,
807 uint16_t block,
808 uint8_t *data,
809 uint16_t length)
810{
811 bcmos_errno err;
812 /* OAM stuff */
813 bcmolt_epon_oam_ethernet_frame oam_frame;
814 bcmolt_epon_oam_ethernet_protocol protocol;
815
816 err = epon_oam_make_dpoe_frame(device_id, key->epon_ni, &oam_frame, &protocol);
817 BCMOS_RETURN_ON_ERROR(err);
818 protocol.u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value.op =
819 BCMOLT_EPON_OAM_DPOE_OPCODE_FILE_TRANSFER;
820 protocol.u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value.u.file_transfer.file_transfer.opcode = BCMOLT_EPON_OAM_DPOE_FILE_TRANSFER_OPCODE_FILE_DATA;
821 protocol.u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value.u.file_transfer.file_transfer.u.file_data.block = block;
822 protocol.u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value.u.file_transfer.file_transfer.u.file_data.length = length;
823 protocol.u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value.u.file_transfer.file_transfer.u.file_data.data = data;
824
825 if (BCM_ERR_OK != epon_oam_pack_and_send(device_id, key->epon_ni, &key->mac_address, &oam_frame))
826 {
827 EPON_OAM_LOG(ERROR, device_id, key, "Failed to send fw upgrade block %u\n", block);
828 }
829 else
830 {
831 EPON_OAM_LOG(DEBUG, device_id, key, "Sent block %u\n", block);
832 }
833}
834
835static void epon_oam_dpoe_send_ack(bcmolt_devid device_id,
836 const bcmolt_epon_link_key *key,
837 bcmolt_epon_oam_dpoe_file_transfer_error error)
838{
839 bcmos_errno err;
840 /* OAM stuff */
841 bcmolt_epon_oam_ethernet_frame oam_frame;
842 bcmolt_epon_oam_ethernet_protocol protocol;
843
844 err = epon_oam_make_dpoe_frame(device_id, key->epon_ni, &oam_frame, &protocol);
845 BCMOS_RETURN_ON_ERROR(err);
846 protocol.u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value.op =
847 BCMOLT_EPON_OAM_DPOE_OPCODE_FILE_TRANSFER;
848 protocol.u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value.u.file_transfer.file_transfer.opcode = BCMOLT_EPON_OAM_DPOE_FILE_TRANSFER_OPCODE_FILE_ACK;
849 protocol.u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value.u.file_transfer.file_transfer.u.file_ack.block = 0;
850 protocol.u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value.u.file_transfer.file_transfer.u.file_ack.error = error;
851
852 if (BCM_ERR_OK != epon_oam_pack_and_send(device_id, key->epon_ni, &key->mac_address, &oam_frame))
853 {
854 EPON_OAM_LOG(ERROR, device_id, key, "Failed to send fw upgrade ack\n");
855 }
856 else
857 {
858 EPON_OAM_LOG(DEBUG, device_id, key, "Sent ack: error %u\n", error);
859 }
860}
861
862static void epon_oam_dpoe_reset_timeout(epon_oam_dpoe_fw_upgrade_state *state)
863{
864 EPON_OAM_LOG(DEBUG, state->device_id, &state->key, "ONU took %u us to respond\n", bcmos_timestamp() - state->last_time);
865 state->last_time = bcmos_timestamp();
866 bcmos_timer_start(&state->timer, state->timeout_us);
867}
868
869static void epon_oam_dpoe_handle_ack(bcmolt_devid device_id,
870 const bcmolt_epon_link_key *key,
871 const bcmolt_epon_oam_dpoe_file_transfer_base *ft,
872 bcmolt_user_appl_epon_oam_handle_rx_cb cb)
873{
874 epon_oam_dpoe_fw_upgrade_state *state;
875 int block_size;
876
877 state = epon_oam_dpoe_fw_upgrade_state_get(key);
878
879 if (NULL == state)
880 {
881 EPON_OAM_LOG(DEBUG, device_id, key, "Rx unexpected ack\n");
882 return;
883 }
884
885 if (state->done)
886 {
887 if (ft->u.file_ack.block != 0)
888 {
889 EPON_OAM_LOG(ERROR, device_id, key, "Final ack contained non-zero block: %u\n", ft->u.file_ack.block);
890 }
891 switch (ft->u.file_ack.error)
892 {
893 case BCMOLT_EPON_OAM_DPOE_FILE_TRANSFER_ERROR_OK:
894 EPON_OAM_LOG(INFO, device_id, key, "Upgrade successful\n");
895 break;
896 default:
897 EPON_OAM_LOG(ERROR, device_id, key, "Upgrade failed with error %u\n", ft->u.file_ack.error);
898 break;
899 }
900 epon_oam_dpoe_fw_upgrade_state_release(state);
901 return;
902 }
903
904 state->last_block++;
905 if ((state->last_block - 1) == ft->u.file_ack.block)
906 { /* retry last block */
907 state->last_block--;
908 state->retries++;
909 if (state->retries > 3)
910 {
911 EPON_OAM_LOG(ERROR, device_id, key, "Exceeded retry limit on block %u\n", ft->u.file_ack.block);
912 epon_oam_dpoe_send_ack(device_id, key, BCMOLT_EPON_OAM_DPOE_FILE_TRANSFER_ERROR_TIMEOUT);
913 epon_oam_dpoe_fw_upgrade_state_release(state);
914 }
915 else
916 {
917 epon_oam_dpoe_send_block(device_id, key, ft->u.file_ack.block, state->buf, state->last_block_size);
918 epon_oam_dpoe_reset_timeout(state);
919 }
920 }
921 else if (state->last_block == ft->u.file_ack.block)
922 { /* send next block */
923 state->retries = 0;
924 block_size = fread(state->buf, 1, state->block_size, state->file);
925 if (block_size > 0)
926 {
927 epon_oam_dpoe_send_block(device_id, key, ft->u.file_ack.block, state->buf, block_size);
928 }
929 else
930 {
931 state->done = BCMOS_TRUE;
932 epon_oam_dpoe_send_ack(device_id, key, BCMOLT_EPON_OAM_DPOE_FILE_TRANSFER_ERROR_OK);
933 }
934 state->last_block_size = block_size;
935 epon_oam_dpoe_reset_timeout(state);
936 }
937 else
938 { /* unexpected block */
939 EPON_OAM_LOG(ERROR, device_id, key, "Unexpected block requested: %u (expecting %u)\n",
940 ft->u.file_ack.block, state->last_block + 1);
941 epon_oam_dpoe_send_ack(device_id, key, BCMOLT_EPON_OAM_DPOE_FILE_TRANSFER_ERROR_BAD_BLOCK);
942 epon_oam_dpoe_fw_upgrade_state_release(state);
943 }
944}
945
946static bcmos_timer_rc epon_oam_dpoe_fw_upgrade_timeout(bcmos_timer *timer, long data)
947{
948 epon_oam_msg_data msg_data;
949
950 msg_data.timeout.state = (epon_oam_dpoe_fw_upgrade_state*)data;
951 epon_oam_send_os_msg(BCMOS_MSG_ID_EPON_OAM_TIMEOUT, &msg_data);
952
953 return BCMOS_TIMER_OK;
954}
955
956bcmos_errno epon_oam_dpoe_start_upgrade(bcmolt_devid device_id,
957 bcmolt_epon_ni epon,
958 bcmos_mac_address *mac,
959 const char *fw_file,
960 uint16_t block_size,
961 uint8_t timeout_sec)
962{
963 bcmos_errno err = BCM_ERR_OK;
964 bcmolt_epon_link_key link_key = { .epon_ni = epon, .mac_address = *mac };
965 bcmos_timer_parm tp =
966 {
967 .name = "fw_upgrade_timer",
968 .owner = BCMOS_MODULE_ID_USER_APPL_EPON_OAM,
969 .periodic = BCMOS_FALSE,
970 .handler = epon_oam_dpoe_fw_upgrade_timeout
971 };
972 /* OAM stuff */
973 bcmolt_epon_oam_ethernet_frame oam_frame;
974 bcmolt_epon_oam_ethernet_protocol protocol;
975 epon_oam_dpoe_fw_upgrade_state *state;
976
977 if (NULL != epon_oam_dpoe_fw_upgrade_state_get(&link_key))
978 {
979 return BCM_ERR_ALREADY;
980 }
981 state = epon_oam_dpoe_fw_upgrade_state_add(&link_key);
982 if (NULL == state)
983 {
984 return BCM_ERR_NOMEM;
985 }
986
987 state->device_id = device_id;
988 state->key = link_key;
989 state->file = fopen(fw_file, "rb");
990 if (NULL == state->file)
991 {
992 epon_oam_dpoe_fw_upgrade_state_release(state);
993 return BCM_ERR_IO;
994 }
995 state->block_size = block_size;
996 state->buf = bcmos_calloc(block_size);
997 if (NULL == state->buf)
998 {
999 epon_oam_dpoe_fw_upgrade_state_release(state);
1000 return BCM_ERR_NOMEM;
1001 }
1002 state->last_block = 0xffff;/*-1*/
1003 state->retries = 0;
1004 state->done = BCMOS_FALSE;
1005 tp.data = (long)state;
1006 err = bcmos_timer_create(&state->timer, &tp);
1007 if (BCM_ERR_OK != err)
1008 {
1009 epon_oam_dpoe_fw_upgrade_state_release(state);
1010 return err;
1011 }
1012 state->timeout_us = timeout_sec * 1000 * 1000;
1013 state->last_time = bcmos_timestamp();
1014 bcmos_timer_start(&state->timer, state->timeout_us);
1015
1016 err = epon_oam_make_dpoe_frame(device_id, epon, &oam_frame, &protocol);
1017 if (BCM_ERR_OK != err)
1018 {
1019 epon_oam_dpoe_fw_upgrade_state_release(state);
1020 return err;
1021 }
1022 protocol.u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value.op =
1023 BCMOLT_EPON_OAM_DPOE_OPCODE_FILE_TRANSFER;
1024 protocol.u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value.u.file_transfer.file_transfer.opcode = BCMOLT_EPON_OAM_DPOE_FILE_TRANSFER_OPCODE_FILE_WRITE;
1025 protocol.u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value.u.file_transfer.file_transfer.u.file_write.filename_count = 0;
1026 protocol.u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value.u.file_transfer.file_transfer.u.file_write.filename = NULL;
1027
1028 err = epon_oam_pack_and_send(device_id, epon, mac, &oam_frame);
1029 if (BCM_ERR_OK != err)
1030 {
1031 epon_oam_dpoe_fw_upgrade_state_release(state);
1032 }
1033 return err;
1034}
1035
1036bcmos_errno epon_oam_dpoe_reset_onu(bcmolt_devid device_id, bcmolt_epon_ni epon, bcmos_mac_address *mac)
1037{
1038 bcmos_errno err = BCM_ERR_OK;
1039
1040 /* OAM stuff */
1041 bcmolt_epon_oam_ethernet_frame oam_frame;
1042 bcmolt_epon_oam_ethernet_protocol protocol;
1043 bcmolt_epon_oam_dpoe_var_container_base vars[2] = {};
1044
1045 err = epon_oam_make_dpoe_frame(device_id, epon, &oam_frame, &protocol);
1046 BCMOS_CHECK_RETURN_ERROR(BCM_ERR_OK != err, err);
1047 protocol.u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value.op =
1048 BCMOLT_EPON_OAM_DPOE_OPCODE_SET_REQUEST;
1049 protocol.u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value.u.set_request.vars_count =
1050 2;
1051 protocol.u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value.u.set_request.vars = vars;
1052 vars[0].branch = BCMOLT_EPON_OAM_DPOE_BRANCH_EXTENDED_ACTION;
1053 vars[0].u.extended_action.action.leaf = BCMOLT_EPON_OAM_DPOE_LEAF_ACTION_RESET_ONU;
1054 vars[1].branch = BCMOLT_EPON_OAM_DPOE_BRANCH_END;
1055 vars[1].u.end.unknown_count = 0;
1056 vars[1].u.end.unknown = NULL;
1057
1058 return epon_oam_pack_and_send(device_id, epon, mac, &oam_frame);
1059}
1060
1061static void epon_oam_handle_event(bcmolt_devid device_id,
1062 bcmolt_epon_oam_oam_pdu_content *content,
1063 const bcmolt_epon_link_key *key,
1064 bcmolt_user_appl_epon_oam_handle_rx_cb cb)
1065{
1066 for (uint32_t i = 0; i < content->u.event_notification.tlvs_count; i++)
1067 {
1068 if (BCMOLT_EPON_OAM_LINK_EVENT_TYPE_ORGANIZATION_SPECIFIC == content->u.event_notification.tlvs[i].type)
1069 {
1070 switch (content->u.event_notification.tlvs[i].u.organization_specific.value.oui)
1071 {
1072 case BCMOLT_EPON_OAM_WELL_KNOWN_OUI_DPOE:
1073 if (NULL != cb)
1074 {
1075 cb(device_id, key->epon_ni, &key->mac_address, BCMOLT_USER_APPL_EPON_OAM_RX_ID_DPOE_EVENT, BCM_ERR_OK);
1076 }
1077 EPON_OAM_LOG(INFO, device_id, key, "Received DPoE event %u\n",
1078 content->u.event_notification.tlvs[i].u.organization_specific.value.u.dpoe.value.event_code);
1079 break;
1080 default:
1081 break;
1082 }
1083 }
1084 }
1085}
1086
1087static void epon_oam_handle_dpoe_get_response(bcmolt_devid device_id,
1088 bcmolt_epon_oam_dpoe_vendor_extended_base *dpoe,
1089 const bcmolt_epon_link_key *key,
1090 bcmolt_user_appl_epon_oam_handle_rx_cb cb)
1091{
1092 bcmos_errno rc = BCM_ERR_OK;
1093
1094 EPON_OAM_LOG(DEBUG, device_id, key, "Rx %u vars\n", dpoe->u.get_response.vars_count);
1095 for (uint32_t i = 0; i < dpoe->u.get_response.vars_count; i++)
1096 {
1097 EPON_OAM_LOG(DEBUG, device_id, key, " %u: branch %u\n", i, dpoe->u.get_response.vars[i].branch);
1098 if (BCMOLT_EPON_OAM_DPOE_BRANCH_EXTENDED_ATTRIBUTE == dpoe->u.get_response.vars[i].branch)
1099 {
1100 if (dpoe->u.get_response.vars[i].u.extended_attribute.attribute.width >
1101 BCMOLT_EPON_OAM_DPOE_ERROR_CODE_NO_ERROR)
1102 {
1103 EPON_OAM_LOG(ERROR, device_id, key, "Error 0x%x getting DPoE extended attribute 0x%04x\n",
1104 dpoe->u.get_response.vars[i].u.extended_attribute.attribute.width,
1105 dpoe->u.get_response.vars[i].u.extended_attribute.attribute.leaf);
1106 rc = BCM_ERR_ONU_ERR_RESP;
1107 }
1108 switch (dpoe->u.get_response.vars[i].u.extended_attribute.attribute.leaf)
1109 {
1110 case BCMOLT_EPON_OAM_DPOE_LEAF_ATTRIBUTE_ONU_ID:
1111 EPON_OAM_LOG(INFO, device_id, key, "Got DPoE ONUID %02x%02x%02x%02x%02x%02x\n",
1112 dpoe->u.get_response.vars[i].u.extended_attribute.attribute.u.onu_id.id.u8[0],
1113 dpoe->u.get_response.vars[i].u.extended_attribute.attribute.u.onu_id.id.u8[1],
1114 dpoe->u.get_response.vars[i].u.extended_attribute.attribute.u.onu_id.id.u8[2],
1115 dpoe->u.get_response.vars[i].u.extended_attribute.attribute.u.onu_id.id.u8[3],
1116 dpoe->u.get_response.vars[i].u.extended_attribute.attribute.u.onu_id.id.u8[4],
1117 dpoe->u.get_response.vars[i].u.extended_attribute.attribute.u.onu_id.id.u8[5]);
1118 break;
1119 case BCMOLT_EPON_OAM_DPOE_LEAF_ATTRIBUTE_MAX_LOGICAL_LINKS:
1120 EPON_OAM_LOG(INFO, device_id, key, "Got DPoE Max Logical Links BiDir %u, DownOnly %u\n",
1121 dpoe->u.get_response.vars[i].u.extended_attribute.attribute.u.max_logical_links.bidirectional,
1122 dpoe->u.get_response.vars[i].u.extended_attribute.attribute.u.max_logical_links.downstream_only);
1123 break;
1124 default:
1125 break;
1126 }
1127 }
1128 }
1129 if (NULL != cb)
1130 {
1131 cb(device_id, key->epon_ni, &key->mac_address, BCMOLT_USER_APPL_EPON_OAM_RX_ID_DPOE_GET_RESPONSE, rc);
1132 }
1133}
1134
1135static void epon_oam_handle_dpoe_set_response(bcmolt_devid device_id,
1136 bcmolt_epon_oam_dpoe_vendor_extended_base *dpoe,
1137 const bcmolt_epon_link_key *key,
1138 bcmolt_user_appl_epon_oam_handle_rx_cb cb)
1139{
1140 bcmos_errno rc = BCM_ERR_OK;
1141
1142 EPON_OAM_LOG(DEBUG, device_id, key, "Rx %u vars\n", dpoe->u.set_response.vars_count);
1143 for (uint32_t i = 0; i < dpoe->u.set_response.vars_count; i++)
1144 {
1145 EPON_OAM_LOG(DEBUG, device_id, key, " %u: branch %u\n", i, dpoe->u.set_response.vars[i].branch);
1146 switch (dpoe->u.set_response.vars[i].branch)
1147 {
1148 case BCMOLT_EPON_OAM_DPOE_BRANCH_EXTENDED_ATTRIBUTE:
1149 if (dpoe->u.set_response.vars[i].u.extended_attribute.attribute.width >
1150 BCMOLT_EPON_OAM_DPOE_ERROR_CODE_NO_ERROR)
1151 {
1152 EPON_OAM_LOG(ERROR, device_id, key, "Error 0x%x setting DPoE extended attribute 0x%04x\n",
1153 dpoe->u.set_response.vars[i].u.extended_attribute.attribute.width,
1154 dpoe->u.set_response.vars[i].u.extended_attribute.attribute.leaf);
1155 rc = BCM_ERR_ONU_ERR_RESP;
1156 }
1157 else
1158 {
1159 EPON_OAM_LOG(INFO, device_id, key, "Successfully set DPoE extended attribute 0x%04x\n",
1160 dpoe->u.set_response.vars[i].u.extended_attribute.attribute.leaf);
1161 }
1162 break;
1163 case BCMOLT_EPON_OAM_DPOE_BRANCH_EXTENDED_ACTION:
1164 if (dpoe->u.set_response.vars[i].u.extended_action.action.width >
1165 BCMOLT_EPON_OAM_DPOE_ERROR_CODE_NO_ERROR)
1166 {
1167 EPON_OAM_LOG(ERROR, device_id, key, "Error 0x%x performing DPoE extended action 0x%04x\n",
1168 dpoe->u.set_response.vars[i].u.extended_action.action.width,
1169 dpoe->u.set_response.vars[i].u.extended_action.action.leaf);
1170 rc = BCM_ERR_ONU_ERR_RESP;
1171 }
1172 else
1173 {
1174 EPON_OAM_LOG(INFO, device_id, key, "Successfully performed DPoE extended action 0x%04x\n",
1175 dpoe->u.set_response.vars[i].u.extended_action.action.leaf);
1176 }
1177 break;
1178 default:
1179 break;
1180 }
1181 }
1182 if (NULL != cb)
1183 {
1184 cb(device_id, key->epon_ni, &key->mac_address, BCMOLT_USER_APPL_EPON_OAM_RX_ID_DPOE_SET_RESPONSE, rc);
1185 }
1186}
1187
1188static void epon_oam_handle_dpoe_file_transfer(bcmolt_devid device_id,
1189 bcmolt_epon_oam_dpoe_vendor_extended_base *dpoe,
1190 const bcmolt_epon_link_key *key,
1191 bcmolt_user_appl_epon_oam_handle_rx_cb cb)
1192{
1193 EPON_OAM_LOG(DEBUG, device_id, key, "Got DPoE File Transfer: %u\n", dpoe->u.file_transfer.file_transfer.opcode);
1194 switch (dpoe->u.file_transfer.file_transfer.opcode)
1195 {
1196 case BCMOLT_EPON_OAM_DPOE_FILE_TRANSFER_OPCODE_FILE_ACK:
1197 EPON_OAM_LOG(DEBUG, device_id, key, "Rx ack block %u error %u\n",
1198 dpoe->u.file_transfer.file_transfer.u.file_ack.block,
1199 dpoe->u.file_transfer.file_transfer.u.file_ack.error);
1200 switch (dpoe->u.file_transfer.file_transfer.u.file_ack.error)
1201 {
1202 case BCMOLT_EPON_OAM_DPOE_FILE_TRANSFER_ERROR_OK:
1203 epon_oam_dpoe_handle_ack(device_id, key, &dpoe->u.file_transfer.file_transfer, cb);
1204 break;
1205 default:
1206 EPON_OAM_LOG(ERROR, device_id, key, "File transfer failed on block %u with error %u\n",
1207 dpoe->u.file_transfer.file_transfer.u.file_ack.block,
1208 dpoe->u.file_transfer.file_transfer.u.file_ack.error);
1209 break;
1210 }
1211 break;
1212 case BCMOLT_EPON_OAM_DPOE_FILE_TRANSFER_OPCODE_FILE_DATA:
1213 EPON_OAM_LOG(DEBUG, device_id, key, "Rx data\n");
1214 break;
1215 case BCMOLT_EPON_OAM_DPOE_FILE_TRANSFER_OPCODE_FILE_READ:
1216 EPON_OAM_LOG(ERROR, device_id, key, "Rx read request\n");
1217 break;
1218 case BCMOLT_EPON_OAM_DPOE_FILE_TRANSFER_OPCODE_FILE_WRITE:
1219 EPON_OAM_LOG(ERROR, device_id, key, "Rx write request\n");
1220 break;
1221 default:
1222 EPON_OAM_LOG(ERROR, device_id, key, "Unknown DPoE File Transfer opcode: %u\n",
1223 dpoe->u.file_transfer.file_transfer.opcode);
1224 break;
1225 }
1226}
1227
1228static void epon_oam_handle_dpoe(bcmolt_devid device_id,
1229 bcmolt_epon_oam_dpoe_vendor_extended_base *dpoe,
1230 const bcmolt_epon_link_key *key,
1231 bcmolt_user_appl_epon_oam_handle_rx_cb cb)
1232{
1233 EPON_OAM_LOG(DEBUG, device_id, key, "Rx DPoE opcode %u\n", dpoe->op);
1234 switch (dpoe->op)
1235 {
1236 case BCMOLT_EPON_OAM_DPOE_OPCODE_GET_RESPONSE:
1237 epon_oam_handle_dpoe_get_response(device_id, dpoe, key, cb);
1238 break;
1239 case BCMOLT_EPON_OAM_DPOE_OPCODE_SET_RESPONSE:
1240 epon_oam_handle_dpoe_set_response(device_id, dpoe, key, cb);
1241 break;
1242 case BCMOLT_EPON_OAM_DPOE_OPCODE_FILE_TRANSFER:
1243 epon_oam_handle_dpoe_file_transfer(device_id, dpoe, key, cb);
1244 break;
1245 default:
1246 break;
1247 }
1248}
1249
1250static void bcmolt_user_appl_epon_oam_handle_proxy_rx(epon_oam_proxy_rx_data *data)
1251{
1252 const bcmolt_epon_link_frame_captured *cap = (bcmolt_epon_link_frame_captured*)data->rx;
1253 bcmolt_epon_oam_ethernet_frame *oam_frame;
1254
1255 oam_frame = epon_oam_unpack(data->device_id, cap->data.frame.len, cap->data.frame.val);
1256 if (NULL == oam_frame)
1257 {
1258 return;
1259 }
1260
1261 if (oam_frame->protocols_count == 0)
1262 {
1263 EPON_OAM_LOG(ERROR, data->device_id, &cap->key, "No protocols in OAM frame\n");
1264 bcmos_free(oam_frame);
1265 return;
1266 }
1267
1268 EPON_OAM_LOG(DEBUG, data->device_id, &cap->key, "Rx ethertype %04x subtype %02x\n",
1269 oam_frame->protocols[0].ethertype, oam_frame->protocols[0].u.slow_protocol.value.subtype);
1270 if ((BCMOLT_EPON_OAM_PROTOCOL_TYPE_SLOW_PROTOCOL == oam_frame->protocols[0].ethertype) &&
1271 (BCMOLT_EPON_OAM_SLOW_PROTOCOL_SUBTYPE_OAM == oam_frame->protocols[0].u.slow_protocol.value.subtype))
1272 {
1273 if (oam_frame->protocols[0].u.slow_protocol.value.u.oam.flags & BCMOLT_EPON_OAM_OAM_FLAGS_LINK_FAULT)
1274 {
1275 if (NULL != data->cb)
1276 {
1277 data->cb(data->device_id, cap->key.epon_ni, &cap->key.mac_address, BCMOLT_USER_APPL_EPON_OAM_RX_ID_LINK_FAULT, BCM_ERR_OK);
1278 }
1279 EPON_OAM_LOG(ERROR, data->device_id, &cap->key, "Received OAM link fault\n");
1280 }
1281 if (oam_frame->protocols[0].u.slow_protocol.value.u.oam.flags & BCMOLT_EPON_OAM_OAM_FLAGS_DYING_GASP)
1282 {
1283 if (NULL != data->cb)
1284 {
1285 data->cb(data->device_id, cap->key.epon_ni, &cap->key.mac_address, BCMOLT_USER_APPL_EPON_OAM_RX_ID_DYING_GASP, BCM_ERR_OK);
1286 }
1287 EPON_OAM_LOG(ERROR, data->device_id, &cap->key, "Received OAM dying gasp\n");
1288 }
1289 if (oam_frame->protocols[0].u.slow_protocol.value.u.oam.flags & BCMOLT_EPON_OAM_OAM_FLAGS_CRITICAL_EVENT)
1290 {
1291 if (NULL != data->cb)
1292 {
1293 data->cb(data->device_id, cap->key.epon_ni, &cap->key.mac_address, BCMOLT_USER_APPL_EPON_OAM_RX_ID_CRITICAL_EVENT, BCM_ERR_OK);
1294 }
1295 EPON_OAM_LOG(ERROR, data->device_id, &cap->key, "Received OAM critical event\n");
1296 }
1297 EPON_OAM_LOG(DEBUG, data->device_id, &cap->key, "Rx opcode %u\n",
1298 oam_frame->protocols[0].u.slow_protocol.value.u.oam.content.code);
1299 switch (oam_frame->protocols[0].u.slow_protocol.value.u.oam.content.code)
1300 {
1301 case BCMOLT_EPON_OAM_OAM_OPCODE_INFO:
1302 break; /* ignore info - this should be handled by eon */
1303 case BCMOLT_EPON_OAM_OAM_OPCODE_EVENT_NOTIFICATION:
1304 epon_oam_handle_event(data->device_id, &oam_frame->protocols[0].u.slow_protocol.value.u.oam.content, &cap->key, data->cb);
1305 break;
1306 case BCMOLT_EPON_OAM_OAM_OPCODE_ORGANIZATION_SPECIFIC:
1307 EPON_OAM_LOG(DEBUG, data->device_id, &cap->key, "Rx OUI %u\n",
1308 oam_frame->protocols[0].u.slow_protocol.value.u.oam.content.u.organization_specific.value.oui);
1309 switch (oam_frame->protocols[0].u.slow_protocol.value.u.oam.content.u.organization_specific.value.oui)
1310 {
1311 case BCMOLT_EPON_OAM_WELL_KNOWN_OUI_DPOE:
1312 epon_oam_handle_dpoe(data->device_id, &oam_frame->protocols[0].u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value, &cap->key, data->cb);
1313 break;
1314 default:
1315 break;
1316 }
1317 break;
1318 default:
1319 break;
1320 }
1321 }
1322
1323 bcmos_free(oam_frame);
1324 bcmolt_msg_free(&data->rx->hdr);
1325}
1326
1327static void epon_oam_dpoe_handle_fw_upgrade_timeout(epon_oam_dpoe_fw_upgrade_state *state)
1328{
1329 EPON_OAM_LOG(ERROR, state->device_id, &state->key, "Firmware upgrade timed out\n");
1330 epon_oam_dpoe_send_ack(state->device_id, &state->key, BCMOLT_EPON_OAM_DPOE_FILE_TRANSFER_ERROR_TIMEOUT);
1331 epon_oam_dpoe_fw_upgrade_state_release(state);
1332}
1333
1334static void epon_oam_handle_os_msg(bcmos_module_id module_id, bcmos_msg *os_msg)
1335{
1336 epon_oam_msg *msg = (epon_oam_msg*)os_msg;
1337
1338 switch (msg->os_msg.type)
1339 {
1340 case BCMOS_MSG_ID_EPON_OAM_PROXY_RX:
1341 bcmolt_user_appl_epon_oam_handle_proxy_rx(&msg->data.proxy_rx);
1342 break;
1343 case BCMOS_MSG_ID_EPON_OAM_TIMEOUT:
1344 epon_oam_dpoe_handle_fw_upgrade_timeout(msg->data.timeout.state);
1345 break;
1346 default:
1347 BCM_LOG(ERROR, epon_oam_log[0], "Unknown OS message %u\n", msg->os_msg.type);
1348 break;
1349 }
1350 bcmos_free(os_msg);
1351}
1352
1353void bcmolt_user_appl_epon_oam_handle_rx(bcmolt_devid device_id,
1354 bcmolt_proxy_rx *rx,
1355 bcmolt_user_appl_epon_oam_handle_rx_cb cb)
1356{
1357 bcmos_errno rc;
1358 const bcmolt_epon_link_frame_captured *cap = (bcmolt_epon_link_frame_captured*)rx;
1359 epon_oam_msg_data msg_data = {};
1360
1361 if (!is_running)
1362 {
1363 return;
1364 }
1365
1366 if ((BCMOLT_OBJ_ID_EPON_LINK != rx->hdr.obj_type) ||
1367 (BCMOLT_EPON_LINK_PROXY_RX_ID_FRAME_CAPTURED != rx->hdr.subgroup) ||
1368 (cap->data.frame.val[12] != 0x88) ||
1369 (cap->data.frame.val[13] != 0x09) ||
1370 (cap->data.frame.val[14] != 0x03))
1371 {
1372 return; /* not OAM frame captured on a link - ignore */
1373 }
1374
1375 msg_data.proxy_rx.device_id = device_id;
1376 msg_data.proxy_rx.cb = cb;
1377 rc = bcmolt_msg_clone((bcmolt_msg**)&msg_data.proxy_rx.rx, &rx->hdr);
1378 if (rc != BCM_ERR_OK)
1379 {
1380 BCM_LOG(ERROR, epon_oam_log[device_id], "Proxy Rx clone failed: %s\n", bcmos_strerror(rc));
1381 return;
1382 }
1383
1384 if (BCM_ERR_OK != epon_oam_send_os_msg(BCMOS_MSG_ID_EPON_OAM_PROXY_RX, &msg_data))
1385 {
1386 bcmolt_msg_free(&msg_data.proxy_rx.rx->hdr);
1387 }
1388}
1389
1390void bcmolt_user_appl_epon_oam_init(void)
1391{
1392 bcmos_module_parm module_params =
1393 {
1394 .qparm =
1395 {
1396 .name = "user_appl_epon_oam_module",
1397 .size = MAX_CONCURRENT_LINKS
1398 }
1399 };
1400 bcmos_task_parm task_params =
1401 {
1402 .name = "user_appl_epon_oam_task",
1403 .priority = BCMOS_TASK_PRIORITY_12,
1404 .core = BCMOS_CPU_CORE_ANY, /* No CPU affinity */
1405 .init_handler = NULL
1406 };
1407
1408 if (is_running)
1409 {
1410 return;
1411 }
1412
1413#ifdef ENABLE_LOG
1414 int i;
1415 char log_name[MAX_DEV_LOG_ID_NAME] = {};
1416 for (i=0; i<BCMTR_MAX_OLTS; i++)
1417 {
1418 snprintf(log_name, sizeof(log_name)-1, "epon_oam%d", i);
1419 epon_oam_log[i] = bcm_dev_log_id_register(log_name, DEV_LOG_LEVEL_INFO, DEV_LOG_ID_TYPE_BOTH);
1420 }
1421#endif
1422 dpoe_fw_upgrade_state = hash_table_create(MAX_CONCURRENT_LINKS,
1423 sizeof(epon_oam_dpoe_fw_upgrade_state),
1424 sizeof(bcmolt_epon_link_key),
1425 "dpoe_fw_upgrade_state");
1426 if (BCM_ERR_OK != bcmos_task_create(&epon_oam_task, &task_params))
1427 {
1428 BCM_LOG(FATAL, epon_oam_log[0], "Failed to create EPON OAM task!\n");
1429 }
1430 if (BCM_ERR_OK != bcmos_module_create(BCMOS_MODULE_ID_USER_APPL_EPON_OAM, &epon_oam_task, &module_params))
1431 {
1432 BCM_LOG(FATAL, epon_oam_log[0], "Failed to create EPON OAM module!\n");
1433 }
1434 is_running = BCMOS_TRUE;
1435}
1436