Shad Ansari | 2f7f9be | 2017-06-07 13:34:53 -0700 | [diff] [blame^] | 1 | /* |
| 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_api.h> |
| 32 | #include <bcmolt_model_types.h> |
| 33 | #include <bcmcli_session.h> |
| 34 | #include <bcmolt_msg_pack.h> |
| 35 | #include <bcm_dev_log.h> |
| 36 | #include <encrypt_oam.h> |
| 37 | #include <oam_defs.h> |
| 38 | #include "bcmolt_epon_hde.h" |
| 39 | |
| 40 | #define HDE_TASK_MSG_Q_SIZE 64 |
| 41 | #define ENC_KEY_LENGTH_KEY 16 |
| 42 | #define HDE_MAX_NUM_LINKS 512 |
| 43 | #define KEY_EXCHANGE_PERIOD 15 |
| 44 | |
| 45 | typedef enum |
| 46 | { |
| 47 | HDE_EVENT_ENABLE_ENCRYPTION, |
| 48 | HDE_EVENT_DISABLE_ENCRYPTION, |
| 49 | HDE_EVENT_FRAME_RX, |
| 50 | HDE_EVENT_OAM_TIMEOUT, |
| 51 | HDE_EVENT__NUM_OF |
| 52 | } hde_event; |
| 53 | |
| 54 | typedef enum |
| 55 | { |
| 56 | HDE_STATE_NOT_ENCRYPTED, |
| 57 | HDE_STATE_ENCRYPTED, |
| 58 | HDE_STATE_WAITING_FOR_OAM_ACK, |
| 59 | HDE_STATE__NUM_OF |
| 60 | } hde_state; |
| 61 | |
| 62 | typedef struct |
| 63 | { |
| 64 | bcmos_msg os_msg; |
| 65 | bcmolt_msg *rx; |
| 66 | hde_key key; |
| 67 | hde_event event; |
| 68 | } hde_task_msg; |
| 69 | |
| 70 | typedef struct |
| 71 | { |
| 72 | hde_key hde_link; |
| 73 | hde_state state; |
| 74 | bcmos_timer oam_timeout_timer; |
| 75 | bcmolt_epon_link_rate link_rate; |
| 76 | bcmolt_epon_llid llid; |
| 77 | bcmos_mac_address corresponding_pon_port_mac; |
| 78 | } hde_link_data; |
| 79 | |
| 80 | static struct |
| 81 | { |
| 82 | bcmos_task task; |
| 83 | dev_log_id log_id[BCMTR_MAX_OLTS]; |
| 84 | hde_link_data *links; |
| 85 | uint16_t num_links; |
| 86 | } hde_data; |
| 87 | |
| 88 | static bcmos_bool is_running = BCMOS_FALSE; |
| 89 | |
| 90 | typedef void (*link_state_handler)(hde_link_data *hde_link, const bcmolt_msg *ind); |
| 91 | |
| 92 | static const char *get_state_string(hde_state state) |
| 93 | { |
| 94 | switch (state) |
| 95 | { |
| 96 | case HDE_STATE_NOT_ENCRYPTED: |
| 97 | return "not encrypted"; |
| 98 | case HDE_STATE_ENCRYPTED: |
| 99 | return "encrypted"; |
| 100 | case HDE_STATE_WAITING_FOR_OAM_ACK: |
| 101 | return "waiting for oam ack"; |
| 102 | default: |
| 103 | return "UNKNOWN STATE!!!"; |
| 104 | } |
| 105 | } |
| 106 | |
| 107 | static bcmos_errno set_new_key(const hde_key *hde_link, bcmolt_encryption_information_container *new_key, bcmolt_epon_key_choice key_choice, bcmolt_epon_encryption_mode mode) |
| 108 | { |
| 109 | bcmolt_epon_link_cfg link_cfg; |
| 110 | bcmolt_epon_encryption_config encryption_config = { }; |
| 111 | |
| 112 | // Up/down format must match even when doing DS only |
| 113 | encryption_config.upstream_encryption_information.format = new_key->format; |
| 114 | |
| 115 | encryption_config.downstream_encryption_information = *new_key; |
| 116 | encryption_config.downstream_key_choice = key_choice; |
| 117 | encryption_config.downstream_mode = mode; |
| 118 | bcmolt_epon_link_key link_key = |
| 119 | { |
| 120 | .epon_ni = hde_link->epon_ni, |
| 121 | .mac_address = hde_link->mac_addr |
| 122 | }; |
| 123 | BCMOLT_CFG_INIT(&link_cfg, epon_link, link_key); |
| 124 | BCMOLT_CFG_PROP_SET(&link_cfg, epon_link, epon_encryption, encryption_config); |
| 125 | return bcmolt_cfg_set(hde_link->device_id, &link_cfg.hdr); |
| 126 | } |
| 127 | |
| 128 | static bcmos_errno set_pon_encryption_if_needed(const hde_key *hde_link) |
| 129 | { |
| 130 | // First check the current state of the PON's encryption mode. |
| 131 | bcmos_errno rc; |
| 132 | bcmolt_epon_ni_cfg pon_cfg; |
| 133 | bcmolt_epon_ni_key pon_key = { .epon_ni = hde_link->epon_ni }; |
| 134 | BCMOLT_CFG_INIT(&pon_cfg, epon_ni, pon_key); |
| 135 | BCMOLT_CFG_PROP_GET(&pon_cfg, epon_ni, encryption_cfg); |
| 136 | rc = bcmolt_cfg_get(hde_link->device_id, &pon_cfg.hdr); |
| 137 | if (rc != BCM_ERR_OK) |
| 138 | { |
| 139 | BCM_LOG(ERROR, hde_data.log_id[hde_link->device_id], "Failure - Cannot query PON encryption mode!.\n"); |
| 140 | return rc; |
| 141 | } |
| 142 | |
| 143 | if (pon_cfg.data.encryption_cfg.downstream_encryption_mode != BCMOLT_EPON_ENCRYPTION_MODE_EPON_ZERO_OVERHEAD_AES) |
| 144 | { |
| 145 | // Encryption mode is not correctly set on the PON, so set it now. |
| 146 | pon_cfg.data.encryption_cfg.downstream_encryption_mode = BCMOLT_EPON_ENCRYPTION_MODE_EPON_ZERO_OVERHEAD_AES; |
| 147 | pon_cfg.data.encryption_cfg.upstream_encryption_mode = BCMOLT_EPON_ENCRYPTION_MODE_NO_ENCRYPTION; |
| 148 | rc = bcmolt_cfg_set(hde_link->device_id, &pon_cfg.hdr); |
| 149 | if (rc != BCM_ERR_OK) |
| 150 | { |
| 151 | BCM_LOG(ERROR, hde_data.log_id[hde_link->device_id], "Failure - Cannot set PON encryption mode!.\n"); |
| 152 | return rc; |
| 153 | } |
| 154 | } |
| 155 | |
| 156 | return BCM_ERR_OK; |
| 157 | } |
| 158 | |
| 159 | static bcmolt_epon_link_rate get_link_rate(const hde_key *hde_link) |
| 160 | { |
| 161 | bcmos_errno rc; |
| 162 | bcmolt_epon_link_cfg link_cfg; |
| 163 | bcmolt_epon_link_key link_key = |
| 164 | { |
| 165 | .epon_ni = hde_link->epon_ni, |
| 166 | .mac_address = hde_link->mac_addr |
| 167 | }; |
| 168 | BCMOLT_CFG_INIT(&link_cfg, epon_link, link_key); |
| 169 | BCMOLT_CFG_PROP_GET(&link_cfg, epon_link, link_rate); |
| 170 | rc = bcmolt_cfg_get(hde_link->device_id, &link_cfg.hdr); |
| 171 | if (rc != BCM_ERR_OK) |
| 172 | { |
| 173 | BCM_LOG( |
| 174 | ERROR, |
| 175 | hde_data.log_id[hde_link->device_id], |
| 176 | "Failure - cannot query link rate for link %02x:%02x:%02x:%02x:%02x:%02x!.\n", |
| 177 | hde_link->mac_addr.u8[0], |
| 178 | hde_link->mac_addr.u8[1], |
| 179 | hde_link->mac_addr.u8[2], |
| 180 | hde_link->mac_addr.u8[3], |
| 181 | hde_link->mac_addr.u8[4], |
| 182 | hde_link->mac_addr.u8[5]); |
| 183 | } |
| 184 | return link_cfg.data.link_rate; |
| 185 | } |
| 186 | |
| 187 | static bcmos_mac_address get_pon_mac(const hde_key *hde_link) |
| 188 | { |
| 189 | bcmos_errno rc; |
| 190 | bcmolt_epon_ni_cfg pon_cfg; |
| 191 | bcmolt_epon_ni_key pon_key = { .epon_ni = hde_link->epon_ni }; |
| 192 | BCMOLT_CFG_INIT(&pon_cfg, epon_ni, pon_key); |
| 193 | BCMOLT_CFG_PROP_GET(&pon_cfg, epon_ni, mac_address); |
| 194 | rc = bcmolt_cfg_get(hde_link->device_id, &pon_cfg.hdr); |
| 195 | if (rc != BCM_ERR_OK) |
| 196 | { |
| 197 | BCM_LOG(ERROR, hde_data.log_id[hde_link->device_id], "Failure - Cannot query PON mac address!.\n"); |
| 198 | } |
| 199 | return pon_cfg.data.mac_address; |
| 200 | } |
| 201 | |
| 202 | static bcmolt_epon_llid get_llid(const hde_key *hde_link) |
| 203 | { |
| 204 | bcmos_errno rc; |
| 205 | bcmolt_epon_link_cfg link_cfg; |
| 206 | bcmolt_epon_link_key link_key = |
| 207 | { |
| 208 | .epon_ni = hde_link->epon_ni, |
| 209 | .mac_address = hde_link->mac_addr |
| 210 | }; |
| 211 | BCMOLT_CFG_INIT(&link_cfg, epon_link, link_key); |
| 212 | BCMOLT_CFG_PROP_GET(&link_cfg, epon_link, llid); |
| 213 | rc = bcmolt_cfg_get(hde_link->device_id, &link_cfg.hdr); |
| 214 | if (rc != BCM_ERR_OK) |
| 215 | { |
| 216 | BCM_LOG( |
| 217 | ERROR, |
| 218 | hde_data.log_id[hde_link->device_id], |
| 219 | "Failure - cannot query LLID for link %02x:%02x:%02x:%02x:%02x:%02x!.\n", |
| 220 | hde_link->mac_addr.u8[0], |
| 221 | hde_link->mac_addr.u8[1], |
| 222 | hde_link->mac_addr.u8[2], |
| 223 | hde_link->mac_addr.u8[3], |
| 224 | hde_link->mac_addr.u8[4], |
| 225 | hde_link->mac_addr.u8[5]); |
| 226 | } |
| 227 | return link_cfg.data.llid; |
| 228 | } |
| 229 | |
| 230 | /* By spec the SCI is the LLID of the link appended to the corresponding epon port mac address */ |
| 231 | static void create_sci(const bcmos_mac_address *epon_port_mac, bcmolt_epon_llid llid, uint8_t *sci) |
| 232 | { |
| 233 | sci[7] = (uint8_t) llid; |
| 234 | sci[6] = (uint8_t) (llid >> 8); |
| 235 | sci[5] = epon_port_mac->u8[5]; |
| 236 | sci[4] = epon_port_mac->u8[4]; |
| 237 | sci[3] = epon_port_mac->u8[3]; |
| 238 | sci[2] = epon_port_mac->u8[2]; |
| 239 | sci[1] = epon_port_mac->u8[1]; |
| 240 | sci[0] = epon_port_mac->u8[0]; |
| 241 | } |
| 242 | |
| 243 | static void handle_not_encrypted_enable_encryption(hde_link_data *hde_link, const bcmolt_msg *ind) |
| 244 | { |
| 245 | dpoe_encrypt_mode mode = DPOE_ENCRYPT_MODE_NONE; |
| 246 | // Retreive useful link info and store it to save messages later. |
| 247 | hde_link->link_rate = get_link_rate(&hde_link->hde_link); |
| 248 | hde_link->corresponding_pon_port_mac = get_pon_mac(&hde_link->hde_link); |
| 249 | hde_link->llid = get_llid(&hde_link->hde_link); |
| 250 | |
| 251 | if (hde_link->link_rate == BCMOLT_EPON_LINK_RATE_TEN_TEN || hde_link->link_rate == BCMOLT_EPON_LINK_RATE_TEN_ONE) |
| 252 | { |
| 253 | mode = DPOE_ENCRYPT_MODE_10DOWN; |
| 254 | } |
| 255 | else if (hde_link->link_rate == BCMOLT_EPON_LINK_RATE_ONE_ONE) |
| 256 | { |
| 257 | mode = DPOE_ENCRYPT_MODE_1DOWN; |
| 258 | } |
| 259 | else |
| 260 | { |
| 261 | BCM_LOG(ERROR, hde_data.log_id[hde_link->hde_link.device_id], "Failure - UNKNOWN LINK RATE!!!.\n"); |
| 262 | } |
| 263 | |
| 264 | dpoe_encrypt_oam_set_request_send( |
| 265 | &hde_link->hde_link, |
| 266 | KEY_EXCHANGE_PERIOD, |
| 267 | mode, |
| 268 | hde_link->corresponding_pon_port_mac); |
| 269 | |
| 270 | bcmos_timer_start(&hde_link->oam_timeout_timer, HDE_ENABLE_OAM_WAIT_US + OAM_TIMEOUT_GRACE_PERIOD_US); |
| 271 | |
| 272 | hde_link->state = HDE_STATE_WAITING_FOR_OAM_ACK; |
| 273 | } |
| 274 | |
| 275 | static void handle_encrypted_disable_encryption(hde_link_data *hde_link, const bcmolt_msg *ind) |
| 276 | { |
| 277 | bcmolt_encryption_information_container empty_key = { }; |
| 278 | bcmos_errno rc; |
| 279 | |
| 280 | // Turn off encryption on the embedded side. |
| 281 | rc = set_new_key(&hde_link->hde_link, &empty_key, BCMOLT_EPON_KEY_CHOICE_KEY_0, BCMOLT_EPON_ENCRYPTION_MODE_NO_ENCRYPTION); |
| 282 | if (rc != BCM_ERR_OK) |
| 283 | { |
| 284 | BCM_LOG(ERROR, hde_data.log_id[hde_link->hde_link.device_id], |
| 285 | "Failure - Cannot communicate with the embedded!.\n"); |
| 286 | } |
| 287 | |
| 288 | // Send the disable OAM to the link. Don't bother waiting for a response. |
| 289 | dpoe_encrypt_oam_set_request_send(&hde_link->hde_link, 0, DPOE_ENCRYPT_MODE_NONE, get_pon_mac(&hde_link->hde_link)); |
| 290 | |
| 291 | hde_link->state = HDE_STATE_NOT_ENCRYPTED; |
| 292 | } |
| 293 | |
| 294 | static void handle_encrypted_frame_rx(hde_link_data *hde_link, const bcmolt_msg *ind) |
| 295 | { |
| 296 | const bcmolt_epon_link_frame_captured *frame_captured = (const bcmolt_epon_link_frame_captured*) ind; |
| 297 | uint8_t new_key[16]; |
| 298 | bcmolt_epon_key_choice key_choice; |
| 299 | bcmos_errno rc; |
| 300 | bcmolt_encryption_information_container key_for_embedded; |
| 301 | rc = dpoe_encrypt_oam_parse_new_key(&frame_captured->data.frame, new_key, &key_choice); |
| 302 | if (rc != BCM_ERR_OK) |
| 303 | { |
| 304 | // Not a DPoE new key, ignore it |
| 305 | return; |
| 306 | } |
| 307 | |
| 308 | if (hde_link->link_rate == BCMOLT_EPON_LINK_RATE_TEN_TEN || hde_link->link_rate == BCMOLT_EPON_LINK_RATE_TEN_ONE) |
| 309 | { |
| 310 | uint8_t sci[8]; |
| 311 | create_sci(&hde_link->corresponding_pon_port_mac, hde_link->llid, sci); |
| 312 | key_for_embedded.format = BCMOLT_EPON_ENCRYPTION_INFORMATION_FORMAT_CTR; |
| 313 | memcpy(key_for_embedded.u.ctr.key, new_key, sizeof(new_key)); |
| 314 | memcpy(key_for_embedded.u.ctr.sci, sci, sizeof(sci)); |
| 315 | } |
| 316 | else if (hde_link->link_rate == BCMOLT_EPON_LINK_RATE_ONE_ONE) |
| 317 | { |
| 318 | key_for_embedded.format = BCMOLT_EPON_ENCRYPTION_INFORMATION_FORMAT_CFB; |
| 319 | memcpy(key_for_embedded.u.cfb.key, new_key, sizeof(new_key)); |
| 320 | } |
| 321 | else |
| 322 | { |
| 323 | BCM_LOG(ERROR, hde_data.log_id[hde_link->hde_link.device_id], "Failure - UNKNOWN LINK RATE!!!.\n"); |
| 324 | } |
| 325 | |
| 326 | rc = set_new_key(&hde_link->hde_link, &key_for_embedded, key_choice, BCMOLT_EPON_ENCRYPTION_MODE_EPON_ZERO_OVERHEAD_AES); |
| 327 | if (rc != BCM_ERR_OK) |
| 328 | { |
| 329 | BCM_LOG(ERROR, hde_data.log_id[hde_link->hde_link.device_id], |
| 330 | "Failure - Cannot communicate with the embedded!.\n"); |
| 331 | } |
| 332 | } |
| 333 | |
| 334 | static void handle_waiting_for_oam_ack_oam_timeout(hde_link_data *hde_link, const bcmolt_msg *ind) |
| 335 | { |
| 336 | BCM_LOG(ERROR, hde_data.log_id[hde_link->hde_link.device_id], "Failure - No response to initial OAM.\n"); |
| 337 | hde_link->state = HDE_STATE_NOT_ENCRYPTED; |
| 338 | } |
| 339 | |
| 340 | static void handle_waiting_for_oam_ack_frame_rx(hde_link_data *hde_link, const bcmolt_msg *ind) |
| 341 | { |
| 342 | const bcmolt_epon_link_frame_captured *frame_captured = (const bcmolt_epon_link_frame_captured*) ind; |
| 343 | uint8_t encrypt_mode_response; |
| 344 | uint8_t key_expiry_response; |
| 345 | bcmos_errno rc; |
| 346 | |
| 347 | rc = dpoe_encrypt_oam_parse_set_response(&frame_captured->data.frame, &encrypt_mode_response, &key_expiry_response); |
| 348 | if (rc != BCM_ERR_OK) |
| 349 | { |
| 350 | // Not a encryption set reponse, ignore it |
| 351 | return; |
| 352 | } |
| 353 | |
| 354 | /* 0 represents 'no error'. */ |
| 355 | if ((encrypt_mode_response != 0) || (key_expiry_response != 0)) |
| 356 | { |
| 357 | BCM_LOG(ERROR, hde_data.log_id[hde_link->hde_link.device_id], |
| 358 | "Failure - The link refused one of the requested TLVs.\n"); |
| 359 | hde_link->state = HDE_STATE_NOT_ENCRYPTED; |
| 360 | return; |
| 361 | } |
| 362 | |
| 363 | // We have an appropriate response, so move on normally. |
| 364 | bcmos_timer_stop(&hde_link->oam_timeout_timer); |
| 365 | hde_link->state = HDE_STATE_ENCRYPTED; |
| 366 | } |
| 367 | |
| 368 | static void handle_waiting_for_oam_ack_disable_encryption(hde_link_data *hde_link, const bcmolt_msg *ind) |
| 369 | { |
| 370 | hde_link->state = HDE_STATE_NOT_ENCRYPTED; |
| 371 | } |
| 372 | |
| 373 | static void handle_ignore(hde_link_data *hde_link, const bcmolt_msg *ind) |
| 374 | { |
| 375 | // Literally do nothing |
| 376 | } |
| 377 | |
| 378 | static void handle_error(hde_link_data *hde_link, const bcmolt_msg *ind) |
| 379 | { |
| 380 | BCM_LOG(ERROR, hde_data.log_id[hde_link->hde_link.device_id], "Unexpected event in state %s\n", |
| 381 | get_state_string(hde_link->state)); |
| 382 | } |
| 383 | |
| 384 | static link_state_handler link_state_machine[HDE_STATE__NUM_OF][HDE_EVENT__NUM_OF] = |
| 385 | { |
| 386 | [HDE_STATE_NOT_ENCRYPTED] = |
| 387 | { |
| 388 | [HDE_EVENT_ENABLE_ENCRYPTION] = handle_not_encrypted_enable_encryption, |
| 389 | [HDE_EVENT_DISABLE_ENCRYPTION] = handle_error, |
| 390 | [HDE_EVENT_FRAME_RX] = handle_ignore, |
| 391 | [HDE_EVENT_OAM_TIMEOUT] = handle_ignore, |
| 392 | }, |
| 393 | [HDE_STATE_ENCRYPTED] = |
| 394 | { |
| 395 | [HDE_EVENT_ENABLE_ENCRYPTION] = handle_error, |
| 396 | [HDE_EVENT_DISABLE_ENCRYPTION] = handle_encrypted_disable_encryption, |
| 397 | [HDE_EVENT_FRAME_RX] = handle_encrypted_frame_rx, |
| 398 | [HDE_EVENT_OAM_TIMEOUT] = handle_ignore, |
| 399 | }, |
| 400 | [HDE_STATE_WAITING_FOR_OAM_ACK] = |
| 401 | { |
| 402 | [HDE_EVENT_ENABLE_ENCRYPTION] = handle_error, |
| 403 | [HDE_EVENT_DISABLE_ENCRYPTION] = handle_waiting_for_oam_ack_disable_encryption, |
| 404 | [HDE_EVENT_FRAME_RX] = handle_waiting_for_oam_ack_frame_rx, |
| 405 | [HDE_EVENT_OAM_TIMEOUT] = handle_waiting_for_oam_ack_oam_timeout, |
| 406 | } |
| 407 | }; |
| 408 | |
| 409 | static int32_t find_table_index(const hde_key *hde_link) |
| 410 | { |
| 411 | uint16_t i; |
| 412 | for (i = 0; i < hde_data.num_links; ++i) |
| 413 | { |
| 414 | if (memcmp(hde_link, &hde_data.links[i], sizeof(*hde_link)) == 0) |
| 415 | { |
| 416 | return i; |
| 417 | } |
| 418 | } |
| 419 | return -1; |
| 420 | } |
| 421 | |
| 422 | static void remove_link_from_table(int32_t link_index) |
| 423 | { |
| 424 | int32_t i; |
| 425 | for (i = link_index; i < hde_data.num_links - 1; ++i) |
| 426 | { |
| 427 | /* Backwards copy all data expect for the timer handle */ |
| 428 | hde_data.links[i].hde_link = hde_data.links[i + 1].hde_link; |
| 429 | hde_data.links[i].link_rate = hde_data.links[i + 1].link_rate; |
| 430 | hde_data.links[i].llid = hde_data.links[i + 1].llid; |
| 431 | hde_data.links[i].state = hde_data.links[i + 1].state; |
| 432 | } |
| 433 | /* also clear the state of the now empty link */ |
| 434 | hde_data.links[hde_data.num_links - 1].state = HDE_STATE_NOT_ENCRYPTED; |
| 435 | hde_data.num_links--; |
| 436 | } |
| 437 | |
| 438 | static void run_state_machine(int32_t link_index, const hde_task_msg *task_msg) |
| 439 | { |
| 440 | if (link_index < 0) // We don't know of this link yet. |
| 441 | { |
| 442 | if (hde_data.num_links == HDE_MAX_NUM_LINKS) |
| 443 | { |
| 444 | BCM_LOG(ERROR, hde_data.log_id[task_msg->key.device_id], "Failure - Cannot add any more links!.\n"); |
| 445 | return; |
| 446 | } |
| 447 | |
| 448 | link_index = hde_data.num_links; |
| 449 | hde_data.links[link_index].hde_link = task_msg->key; |
| 450 | link_state_machine[hde_data.links[link_index].state][task_msg->event](&hde_data.links[link_index], task_msg->rx); |
| 451 | |
| 452 | if (hde_data.links[link_index].state != HDE_STATE_NOT_ENCRYPTED) |
| 453 | { |
| 454 | // This link did not end in the state 'not encrypted', so we need to start tracking him. |
| 455 | ++hde_data.num_links; |
| 456 | } |
| 457 | } |
| 458 | else // We already know of this link. |
| 459 | { |
| 460 | link_state_machine[hde_data.links[link_index].state][task_msg->event](&hde_data.links[link_index], task_msg->rx); |
| 461 | |
| 462 | if (hde_data.links[link_index].state == HDE_STATE_NOT_ENCRYPTED) |
| 463 | { |
| 464 | // The link has is no longer encrypted so lets forget about him. |
| 465 | remove_link_from_table(link_index); |
| 466 | } |
| 467 | } |
| 468 | } |
| 469 | |
| 470 | static void hde_handle_event(bcmos_module_id module_id, bcmos_msg *os_msg) |
| 471 | { |
| 472 | hde_task_msg *task_msg = (hde_task_msg *) os_msg; |
| 473 | |
| 474 | int32_t link_index; |
| 475 | |
| 476 | link_index = find_table_index(&task_msg->key); |
| 477 | run_state_machine(link_index, task_msg); |
| 478 | |
| 479 | if (task_msg->rx != NULL) |
| 480 | { |
| 481 | bcmolt_msg_free(task_msg->rx); |
| 482 | } |
| 483 | bcmos_free(task_msg); |
| 484 | } |
| 485 | |
| 486 | static bcmos_timer_rc oam_response_timeout(bcmos_timer *timer, long data) |
| 487 | { |
| 488 | hde_task_msg *task_msg = bcmos_calloc(sizeof(*task_msg)); |
| 489 | |
| 490 | BUG_UNLESS(task_msg); |
| 491 | |
| 492 | task_msg->key = hde_data.links[data].hde_link; |
| 493 | task_msg->event = HDE_EVENT_OAM_TIMEOUT; |
| 494 | task_msg->os_msg.handler = hde_handle_event; |
| 495 | |
| 496 | bcmos_msg_send_to_module(BCMOS_MODULE_ID_USER_APPL_EPON_HDE, &task_msg->os_msg, BCMOS_MSG_SEND_AUTO_FREE); |
| 497 | return BCMOS_TIMER_OK; |
| 498 | } |
| 499 | |
| 500 | static bcmos_errno hde_set_encryption(hde_key* key, bcmos_bool enabled) |
| 501 | { |
| 502 | bcmos_errno rc = BCM_ERR_OK; |
| 503 | |
| 504 | hde_task_msg *task_msg = bcmos_calloc(sizeof(*task_msg)); |
| 505 | |
| 506 | BUG_UNLESS(task_msg); |
| 507 | |
| 508 | task_msg->key = *key; |
| 509 | task_msg->event = enabled ? HDE_EVENT_ENABLE_ENCRYPTION : HDE_EVENT_DISABLE_ENCRYPTION; |
| 510 | task_msg->os_msg.handler = hde_handle_event; |
| 511 | |
| 512 | rc = bcmos_msg_send_to_module(BCMOS_MODULE_ID_USER_APPL_EPON_HDE, &task_msg->os_msg, BCMOS_MSG_SEND_AUTO_FREE); |
| 513 | BUG_ON(rc != BCM_ERR_OK); |
| 514 | return rc; |
| 515 | } |
| 516 | |
| 517 | static bcmos_errno hde_cli_enable(bcmcli_session *session, const bcmcli_cmd_parm parm[], uint16_t n_parms) |
| 518 | { |
| 519 | bcmos_errno rc = BCM_ERR_OK; |
| 520 | hde_key key = |
| 521 | { |
| 522 | .device_id = current_device, |
| 523 | .epon_ni = (bcmolt_epon_ni)(bcmcli_find_named_parm(session, "epon_ni")->value.number), |
| 524 | .mac_addr = (bcmos_mac_address)(bcmcli_find_named_parm(session, "mac_address")->value.mac) |
| 525 | }; |
| 526 | |
| 527 | rc = set_pon_encryption_if_needed(&key); |
| 528 | if (rc != BCM_ERR_OK) |
| 529 | { |
| 530 | return rc; |
| 531 | } |
| 532 | return hde_set_encryption(&key, BCMOS_TRUE); |
| 533 | } |
| 534 | |
| 535 | static bcmos_errno hde_cli_disable(bcmcli_session *session, const bcmcli_cmd_parm parm[], uint16_t n_parms) |
| 536 | { |
| 537 | hde_key key = |
| 538 | { |
| 539 | .device_id = current_device, |
| 540 | .epon_ni = (bcmolt_epon_ni)(bcmcli_find_named_parm(session, "epon_ni")->value.number), |
| 541 | .mac_addr = (bcmos_mac_address)(bcmcli_find_named_parm(session, "mac_address")->value.mac) |
| 542 | }; |
| 543 | |
| 544 | return hde_set_encryption(&key, BCMOS_FALSE); |
| 545 | } |
| 546 | |
| 547 | // public indication handler interface -- called in transport layer context |
| 548 | bcmos_errno bcmolt_epon_hde_process_rx(bcmolt_devid device_id, uint8_t instance, bcmolt_proxy_rx *rx) |
| 549 | { |
| 550 | bcmos_errno rc = BCM_ERR_OK; |
| 551 | bcmolt_epon_link_frame_captured* actual_rx; |
| 552 | hde_task_msg *task_msg; |
| 553 | hde_key key; |
| 554 | |
| 555 | if (!is_running) |
| 556 | { |
| 557 | return BCM_ERR_OK; |
| 558 | } |
| 559 | |
| 560 | // We only look at message targetting epon links. |
| 561 | if (rx->hdr.obj_type != BCMOLT_OBJ_ID_EPON_LINK) |
| 562 | { |
| 563 | // Not an error, we just don't care about this object. |
| 564 | return BCM_ERR_OK; |
| 565 | } |
| 566 | |
| 567 | // This is the only kind of proxy RX currently supported. |
| 568 | if (rx->hdr.subgroup != BCMOLT_EPON_LINK_PROXY_RX_ID_FRAME_CAPTURED) |
| 569 | { |
| 570 | return BCM_ERR_OK; |
| 571 | } |
| 572 | |
| 573 | // This is safe due to the above subgroup check. |
| 574 | actual_rx = (bcmolt_epon_link_frame_captured*) rx; |
| 575 | key.device_id = device_id; |
| 576 | key.epon_ni = instance; |
| 577 | key.mac_addr = actual_rx->key.mac_address; |
| 578 | |
| 579 | task_msg = bcmos_calloc(sizeof(*task_msg)); |
| 580 | if (task_msg == NULL) |
| 581 | { |
| 582 | rc = BCM_ERR_NOMEM; |
| 583 | } |
| 584 | else |
| 585 | { |
| 586 | bcmolt_msg *rx_clone = NULL; |
| 587 | rc = bcmolt_msg_clone(&rx_clone, &rx->hdr); |
| 588 | if (rc != BCM_ERR_OK) |
| 589 | { |
| 590 | bcmos_free(task_msg); |
| 591 | return rc; |
| 592 | } |
| 593 | actual_rx = (bcmolt_epon_link_frame_captured*) rx_clone; |
| 594 | |
| 595 | task_msg->rx = rx_clone; |
| 596 | task_msg->key = key; |
| 597 | task_msg->event = HDE_EVENT_FRAME_RX; |
| 598 | task_msg->os_msg.handler = hde_handle_event; |
| 599 | rc = bcmos_msg_send_to_module(BCMOS_MODULE_ID_USER_APPL_EPON_HDE, &task_msg->os_msg, BCMOS_MSG_SEND_AUTO_FREE); |
| 600 | if (rc != BCM_ERR_OK) |
| 601 | { |
| 602 | BCM_LOG(ERROR, hde_data.log_id[device_id], "Message send failed!\n"); |
| 603 | bcmolt_msg_free(rx_clone); |
| 604 | } |
| 605 | } |
| 606 | |
| 607 | return rc; |
| 608 | } |
| 609 | |
| 610 | void bcmolt_epon_hde_appl_cli_init(bcmcli_entry *top_dir) |
| 611 | { |
| 612 | static const char *dir_name = "hde"; |
| 613 | |
| 614 | if (bcmcli_dir_find(top_dir, dir_name)) |
| 615 | { |
| 616 | return; |
| 617 | } |
| 618 | |
| 619 | bcmcli_entry *dir = bcmcli_dir_add(top_dir, dir_name, "EPON OAM negotiation commands", BCMCLI_ACCESS_ADMIN, NULL); |
| 620 | BUG_ON(dir == NULL); |
| 621 | |
| 622 | BCMCLI_MAKE_CMD( |
| 623 | dir, |
| 624 | "enable", |
| 625 | "Enable encryption for an EPON link", |
| 626 | hde_cli_enable, |
| 627 | BCMCLI_MAKE_PARM("epon_ni", "EPON NI", BCMCLI_PARM_NUMBER, 0), |
| 628 | BCMCLI_MAKE_PARM("mac_address", "MAC address", BCMCLI_PARM_MAC, 0)); |
| 629 | |
| 630 | BCMCLI_MAKE_CMD( |
| 631 | dir, |
| 632 | "disable", |
| 633 | "Disable encryption for an EPON link", |
| 634 | hde_cli_disable, |
| 635 | BCMCLI_MAKE_PARM("epon_ni", "EPON NI", BCMCLI_PARM_NUMBER, 0), |
| 636 | BCMCLI_MAKE_PARM("mac_address", "MAC address", BCMCLI_PARM_MAC, 0)); |
| 637 | } |
| 638 | |
| 639 | void bcmolt_epon_hde_appl_init(void) |
| 640 | { |
| 641 | bcmos_errno rc = BCM_ERR_OK; |
| 642 | uint32_t i; |
| 643 | |
| 644 | bcmos_task_parm task_params = |
| 645 | { |
| 646 | .name = "user_appl_hde", |
| 647 | .priority = TASK_PRIORITY_USER_APPL_EPON_HDE, |
| 648 | .core = BCMOS_CPU_CORE_ANY, /* No CPU affinity */ |
| 649 | .init_handler = NULL |
| 650 | }; |
| 651 | |
| 652 | bcmos_timer_parm timer_parm = |
| 653 | { |
| 654 | .name = "oam_timeout_timer", |
| 655 | .owner = BCMOS_MODULE_ID_NONE, |
| 656 | .periodic = BCMOS_FALSE, |
| 657 | .handler = oam_response_timeout |
| 658 | }; |
| 659 | |
| 660 | if (is_running) |
| 661 | { |
| 662 | return; |
| 663 | } |
| 664 | |
| 665 | is_running = BCMOS_TRUE; |
| 666 | |
| 667 | for (i=0; i<BCMTR_MAX_OLTS; i++) |
| 668 | { |
| 669 | char log_name[MAX_DEV_LOG_ID_NAME]; |
| 670 | snprintf(log_name, sizeof(log_name)-1, "user_appl_hde_%d", i); |
| 671 | hde_data.log_id[i] = bcm_dev_log_id_register(log_name, DEV_LOG_LEVEL_ERROR, DEV_LOG_ID_TYPE_BOTH); |
| 672 | } |
| 673 | |
| 674 | hde_data.links = bcmos_calloc(HDE_MAX_NUM_LINKS * sizeof(hde_data.links[0])); |
| 675 | BUG_ON(hde_data.links == NULL); |
| 676 | |
| 677 | rc = bcmos_task_create(&hde_data.task, &task_params); |
| 678 | BUG_ON(rc != BCM_ERR_OK); |
| 679 | |
| 680 | bcmos_module_parm module_params = |
| 681 | { |
| 682 | .qparm = { .name = "user_appl_hde", .size = HDE_TASK_MSG_Q_SIZE } |
| 683 | }; |
| 684 | rc = bcmos_module_create(BCMOS_MODULE_ID_USER_APPL_EPON_HDE, &hde_data.task, &module_params); |
| 685 | BUG_ON(rc != BCM_ERR_OK); |
| 686 | |
| 687 | for (i = 0; i < HDE_MAX_NUM_LINKS; ++i) |
| 688 | { |
| 689 | timer_parm.data = i; |
| 690 | rc = bcmos_timer_create(&hde_data.links[i].oam_timeout_timer, &timer_parm); |
| 691 | BUG_ON(rc != BCM_ERR_OK); |
| 692 | } |
| 693 | } |