blob: 999eb2367f2aef38ec1449cc11d2842f6292875b [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/** @file mka.c
31 * @brief Publicly accessible APIs provided to process MKA request/responses.
32 *
33 * This file contains all of the public/private APIs used to process MKA frames.
34 *
35 * MKA Exchange Sequence :
36 *
37 * 1. If bidirectional encryption is enabled, the OLT will generate an MKPDU
38 * containing the basic parameter set and empty live and potential peer
39 * lists.
40 * 2. When the ONU receives this, it will add the OLT to its potential peers
41 * list.
42 * 3. Having discovered a new potential peer, the ONU will transmit an MKPDU
43 * containing the basic parameter set, and empty live peers list, and a
44 * potential peer list containing the OLT.
45 * 4. When the OLT receives this, it will add the ONU to its live peers list.
46 * 5. Having added a new live peer, the OLT will generate a new SAK and install
47 * it for receive (using the ONUs SCI).
48 * 6. The OLT then transmits an MKPDU containing the basic parameter set, a
49 * live peer list containing the ONU, an empty potential peer list, a
50 * distributed SAK, and a SAK usage parameter set indicating that the new
51 * SAK has been installed for receive.
52 * 7. When the ONU receives this, it will:
53 * a. Add the OLT to its live peers list
54 * b. Install the new SAK for receive (using the OLTs SCI)
55 * c. Because the OLT reported the SAK in use for receive, the ONU will
56 * install the SAK for transmit (using the ONUs SCI).
57 * 8. The ONU will then transmit an MKPDU containing the basic parameter set,
58 * a live peers list containing the OLT, an empty potential peer list,
59 * and a SAK usage parameter set indicating that the SAK has been installed
60 * for receive and transmit.
61 * 9. When the OLT receives this, it will see that the ONU has installed the
62 * SAK for receive and will install the SAK for transmit
63 * (using the OLTs SCI).
64 * 10. The OLT will then transmit an MKPDU containing the basic parameter set,
65 * a live peer list containing the ONU, an empty potential peer list and
66 * a SAK usage parameter set indicating the SAK has been installed for
67 * receive and transmit. (I¡®m not sure if this step is necessary)
68 * 11. This message will produce no state change at the ONU, so it will not
69 * respond immediately. (both the ONU and OLT will need to start a 2 second
70 * timer every time an MKPDU is transmitted ? if they have not transmitted
71 * an MKPDU due to a state change when the timer expires, they will
72 * transmit an MKPDU containing the basic parameter set and live and
73 * potential peer lists. If either side does not receive an MKPDU from
74 * the other for 6 seconds they must remove them from their peer lists.)
75 * 12. When the OLT determines that a new SAK is needed this protocol will
76 * repeat steps 5-11. (modifications to the peer lists, such as 7a, should
77 * not be required)
78 *
79 * @defgroup mka MKA
80 * @ingroup cmCtrl
81 *
82 */
83
84#include "mka.h"
85#include "dpoe_sec_util.h"
86#include "dpoe_sec_fsm.h"
87
88/* The destination multicast MAC address for MKA packets. */
89static const bcmos_mac_address mka_dst_mac_addr = { .u8 = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 } };
90
91#if 0
92static const char *mka_state_names[MKA_STATE__COUNT] =
93{
94 "Initial",
95 "WaitingInitialPeerResp",
96 "SakSent",
97 "MkaDone"
98};
99#endif
100
101#define MKA_VERSION 1
102#define MKA_SERVER_PRIORITY 0x30
103#define MKA_INIT_RETRY_CNT 3
104#define MKA_BASIC_PARAM_SET_LEN 44 /* 48 - header len (4 byte) */
105#define MKA_BASIC_PARAM_SET_OPT 0x60 /* KeyServer:0, MACsecDesired:1, MACsec Capability:2 & high 4 bits of
106 Parameter set body length (0) */
107
108#define MKA_ALGORITHM_AGILITY 0x0080c201
109#define MKA_MN_LEN 4 /* Message Number */
110#define MKA_KN_LEN 4 /* Key Number */
111#define MKA_PDU_MAX_FRAME_LEN 300
112#define MKA_HELLO_TIME 2000 /* Ms, 2 seconds */
113#define MKA_MAX_HELLO_RETRIES 3 /* Max Hello retries */
114#define MKA_OLT_INIT_FRAME_LEN 76 /* basic param set(48) + null live peer list (4) + null potential peer list (4) +
115 Icv Indicator (4) + ICV(16) */
116#define MKA_ONE_PEER_LEN 16 /* one live peer len */
117#define MKA_DISTRIBUTED_SAK_LEN 32
118#define MKA_ICV_LEN 16
119#define MKA_PDU_MIN_LENGTH 32
120#define MKA_KEY_WRAPPED_SAK_LEN 24
121#define MKA_SAK_USE_PARAM_BODY_LEN 40
122#define MKA_SAK_USE_PARAM_LEM 44
123#define MKA_MAX_ACCEPTABLE_PN 0xC0000000
124
125#define MKA_SAK_USE_PARAM_AN_SHIFT 6
126#define MKA_SAK_USE_PARAM_LK_TX_SHIFT 5
127#define MKA_SAK_USE_PARAM_LK_RX_SHIFT 4
128#define MKA_SAK_USE_PARAM_OLD_KEY_AN_MASK 3
129#define MKA_SAK_USE_PARAM_OLD_KEY_AN_SFT 2
130#define MKA_SAK_USE_PARAM_OLD_KEY_TX_RX 3
131#define MKA_SAK_USE_PARAM_SECOND_OPT_BYTE 0xC0
132
133#define MKA_KEY_LEN 16 /* common key size */
134
135#define MKA_KEK_LABEL_LEN 12 /* label length */
136#define MKA_KEK_CONTEXT_LEN 16
137
138#define MKA_SAK_KEY_WRAPPED_LEN 24
139
140#define MKA_ICK_LABEL_LEN 12 /* label length */
141#define MKA_ICK_CONTEXT_LEN 16
142
143#define MKA_CKN_LABEL_LEN 16 /* label length */
144#define MKA_CKN_CONTEXT_LEN (SIZE_OF_EAP_SESSION_ID + (BCMOS_ETH_ALEN * 2)) /* 77 */
145
146#define MKA_CAK_LABEL_LEN 16 /* label length */
147#define MKA_CAK_CONTEXT_LEN 12 /* context length */
148
149/* MKPDU Parameter set type */
150typedef enum
151{
152 MKPDU_PARAM_SET_LIVE_PEER_LIST = 1,
153 MKPDU_PARAM_SET_POTENTIAL_PEER_LIST = 2,
154 MKPDU_PARAM_SET_MACSEC_SAK_USE = 3,
155 MKPDU_PARAM_SET_DIST_SAK = 4,
156 MKPDU_PARAM_SET_DIST_CAK = 5,
157 MKPDU_PARAM_SET_KMD = 6,
158 MKPDU_PARAM_SET_ANNOUNCEMENT = 7,
159 MKPDU_PARAM_SET_ICV_INDICATOR = 255,
160} mkpdu_param_set_type;
161
162typedef enum
163{
164 MKA_MSG_TIMEOUT,
165 MKA_MSG_DATA_IND
166} mka_msg_type;
167
168typedef struct
169{
170 mka_msg_type type;
171 eapol_msg_hdr *msg;
172 bcmolt_buf *buf;
173} mka_event;
174
175/* Calculate Key Encryption Key */
176static void _mka_calc_kek(uint8_t *kek, uint8_t *cak, uint8_t *ckn)
177{
178 char kek_label[MKA_KEK_LABEL_LEN + 1] = "IEEE8021 KEK";
179
180 /* Parameter checks. */
181 BUG_ON(kek == NULL);
182 BUG_ON(cak == NULL);
183 BUG_ON(ckn == NULL);
184
185 dpoe_sec_aes_cmac_kdf(cak, kek_label, ckn, MKA_KEK_CONTEXT_LEN, kek);
186}
187
188/* Calculate Integrity Check value Key */
189static void _mka_calc_ick(uint8_t *ick, uint8_t *cak, uint8_t *ckn)
190{
191 char ick_label[MKA_ICK_LABEL_LEN + 1] = "IEEE8021 ICK";
192
193 /* Parameter checks. */
194 BUG_ON(ick == NULL);
195 BUG_ON(cak == NULL);
196 BUG_ON(ckn == NULL);
197
198 dpoe_sec_aes_cmac_kdf(cak, ick_label, ckn, MKA_ICK_CONTEXT_LEN, ick);
199}
200
201/* calculate Integrity Check Value */
202static void _mka_calc_icv(uint8_t *icv, uint8_t *ick, uint8_t *msdu, uint16_t msdu_len)
203{
204 /* Parameter checks. */
205 BUG_ON(icv == NULL);
206 BUG_ON(ick == NULL);
207 BUG_ON(msdu == NULL);
208
209 dpoe_sec_aes_cmac(ick, msdu, msdu_len, icv);
210}
211
212/* Calculate Secure Connectivity Association Key Name */
213static void _mka_calc_ckn(dpoe_sec_link_rec *link_rec, uint8_t eap_sess_id_len)
214{
215 char ckn_label[MKA_CKN_LABEL_LEN + 1] = "IEEE8021 EAP CKN";
216 uint8_t ckn_context[MKA_CKN_CONTEXT_LEN];
217
218 /* Parameter checks. */
219 BUG_ON(link_rec == NULL);
220 BUG_ON(link_rec->mka_ctrl.mka_info == NULL);
221 BUG_ON(link_rec->mka_ctrl.mka_info->ckn == NULL);
222 BUG_ON(link_rec->auth_ctrl.trans_data.master_session_key == NULL);
223 BUG_ON(link_rec->auth_ctrl.trans_data.session_id == NULL);
224
225 memcpy(&ckn_context[0], link_rec->auth_ctrl.trans_data.session_id, eap_sess_id_len);
226 memcpy(&ckn_context[eap_sess_id_len], link_rec->mka_ctrl.mka_info->lesser_mac.u8, BCMOS_ETH_ALEN);
227 memcpy(&ckn_context[eap_sess_id_len + BCMOS_ETH_ALEN], link_rec->mka_ctrl.mka_info->greater_mac.u8, BCMOS_ETH_ALEN);
228 dpoe_sec_aes_cmac_kdf(link_rec->auth_ctrl.trans_data.master_session_key, ckn_label, ckn_context, MKA_CKN_CONTEXT_LEN, link_rec->mka_ctrl.mka_info->ckn);
229}
230
231/* Calculate Secure Connectivity Association Key */
232static void _mka_calc_cak(dpoe_sec_link_rec *link_rec)
233{
234 char cak_label[MKA_CAK_LABEL_LEN + 1] = "IEEE8021 EAP CAK";
235 uint8_t cak_context[MKA_CAK_CONTEXT_LEN];
236
237 /* Parameter checks. */
238 BUG_ON(link_rec == NULL);
239 BUG_ON(link_rec->mka_ctrl.mka_info == NULL);
240 BUG_ON(link_rec->mka_ctrl.mka_info->cak == NULL);
241 BUG_ON(link_rec->auth_ctrl.trans_data.master_session_key == NULL);
242
243 memcpy(&cak_context[0], link_rec->mka_ctrl.mka_info->lesser_mac.u8, BCMOS_ETH_ALEN);
244 memcpy(&cak_context[BCMOS_ETH_ALEN], link_rec->mka_ctrl.mka_info->greater_mac.u8, BCMOS_ETH_ALEN);
245 dpoe_sec_aes_cmac_kdf(link_rec->auth_ctrl.trans_data.master_session_key, cak_label, cak_context, MKA_CAK_CONTEXT_LEN, link_rec->mka_ctrl.mka_info->cak);
246}
247
248/* Get OLT port Mac and link Mac & compare. This is needed for calculating CAK */
249static void _mka_get_olt_and_link_mac(dpoe_sec_link_rec *link_rec)
250{
251 /* Parameter checks. */
252 BUG_ON(link_rec == NULL);
253 BUG_ON(link_rec->mka_ctrl.mka_info == NULL);
254
255 /* compare OLT and Link MAC addresses */
256 if (memcmp(link_rec->ni_mac.u8, link_rec->key.mac_address.u8, sizeof(BCMOS_ETH_ALEN)) >= 0)
257 {
258 link_rec->mka_ctrl.mka_info->lesser_mac = link_rec->key.mac_address;
259 link_rec->mka_ctrl.mka_info->greater_mac = link_rec->ni_mac;
260 }
261 else
262 {
263 link_rec->mka_ctrl.mka_info->lesser_mac = link_rec->ni_mac;
264 link_rec->mka_ctrl.mka_info->greater_mac = link_rec->key.mac_address;
265 }
266}
267
268/* Initialize link MKA info structure */
269static void _mka_init_link_info(dpoe_sec_link_rec *link_rec)
270{
271 /* Parameter checks. */
272 BUG_ON(link_rec == NULL);
273 BUG_ON(link_rec->mka_ctrl.mka_info == NULL);
274
275 /* initialize all local values */
276 memset(link_rec->mka_ctrl.mka_info, 0, sizeof(*link_rec->mka_ctrl.mka_info));
277 dpoe_sec_generate_n_byte_random_number(link_rec->mka_ctrl.mka_info->olt_member_id, MKA_MI_LEN);
278 link_rec->mka_ctrl.mka_info->curr_msg_num = 1; /* start from 1 */
279 link_rec->mka_ctrl.mka_info->key_number = 1; /* start from 1 */
280 _mka_get_olt_and_link_mac(link_rec);
281 _mka_calc_cak(link_rec);
282 _mka_calc_ckn(link_rec, SIZE_OF_EAP_SESSION_ID);
283 _mka_calc_ick(link_rec->mka_ctrl.mka_info->ick, link_rec->mka_ctrl.mka_info->cak, link_rec->mka_ctrl.mka_info->ckn);
284 _mka_calc_kek(link_rec->mka_ctrl.mka_info->kek, link_rec->mka_ctrl.mka_info->cak, link_rec->mka_ctrl.mka_info->ckn);
285}
286
287static void _mka_clear_link_info(dpoe_sec_link_rec *link_rec)
288{
289 /* Parameter checks. */
290 BUG_ON(link_rec->mka_ctrl.mka_info == NULL);
291
292 memset(link_rec->mka_ctrl.mka_info, 0, sizeof(*link_rec->mka_ctrl.mka_info));
293}
294
295/* Build EAPOL header for MKPDU */
296static bcmos_bool _mka_build_eapol_header(dpoe_sec_link_rec *link_rec, bcmolt_buf *out_buf, uint16_t length)
297{
298 /* Parameter checks. */
299 BUG_ON(link_rec == NULL);
300 BUG_ON(out_buf == NULL);
301
302 return
303 bcmolt_buf_write_mac_address(out_buf, mka_dst_mac_addr) &&
304 bcmolt_buf_write_mac_address(out_buf, link_rec->ni_mac) &&
305 bcmolt_buf_write_u16_be(out_buf, ETHERTYPE_EAPOL) &&
306 bcmolt_buf_write_u8(out_buf, EAPOL_PROTOCOL_VERSION_DPOE) &&
307 bcmolt_buf_write_u8(out_buf, EAPOL_TYPE_MKA) &&
308 bcmolt_buf_write_u16_be(out_buf, length);
309}
310
311/* Build Basic parameter set. This parameter set is required for every MKPDU */
312static bcmos_bool _mka_build_basic_parameter_set(dpoe_sec_link_rec *link_rec, bcmolt_buf *out_buf)
313{
314 /* Parameter checks. */
315 BUG_ON(link_rec == NULL);
316 BUG_ON(out_buf == NULL);
317 BUG_ON(link_rec->mka_ctrl.mka_info == NULL);
318
319 return
320 bcmolt_buf_write_u8(out_buf, MKA_VERSION) && /* Version Number, 802.1X Pg.98 */
321 bcmolt_buf_write_u8(out_buf, MKA_SERVER_PRIORITY) && /* Key Server Priority */
322 bcmolt_buf_write_u8(out_buf, MKA_BASIC_PARAM_SET_OPT) &&
323 bcmolt_buf_write_u8(out_buf, MKA_BASIC_PARAM_SET_LEN) &&
324 bcmolt_buf_write_mac_address(out_buf, link_rec->ni_mac) && /* 6 byte of SCI */
325 bcmolt_buf_write_u16_be(out_buf, link_rec->llid) && /* lower 2 byte SCI */
326 bcmolt_buf_write(out_buf, link_rec->mka_ctrl.mka_info->olt_member_id, MKA_MI_LEN) &&
327 bcmolt_buf_write_u32_be(out_buf, link_rec->mka_ctrl.mka_info->curr_msg_num++) && /* Important !! */
328 bcmolt_buf_write_u32_be(out_buf, MKA_ALGORITHM_AGILITY) &&
329 bcmolt_buf_write(out_buf, link_rec->mka_ctrl.mka_info->ckn, MKA_CKN_LEN / 8); /* CAK Name(CKN) */
330}
331
332/* Build an empty Live Peer or Potential Peer list parameter set */
333static bcmos_bool _mka_build_empty_peer_list(bcmolt_buf *out_buf, uint8_t type)
334{
335 /* Parameter checks. */
336 BUG_ON(out_buf == NULL);
337
338 return
339 bcmolt_buf_write_u8(out_buf, type) && /* Parameter set type */
340 bcmolt_buf_write_u8(out_buf, 0) &&
341 bcmolt_buf_write_u8(out_buf, 0) && /* options & 4 bit length */
342 bcmolt_buf_write_u8(out_buf, 0); /* Parameter set body length. */
343}
344
345/* Build Live Peer List or Potential Peer List parameter set */
346static bcmos_bool _mka_build_peer_list(
347 bcmolt_buf *out_buf,
348 uint8_t type,
349 const uint8_t *member_id,
350 uint32_t message_num)
351{
352 /* Parameter checks. */
353 BUG_ON(out_buf == NULL);
354 BUG_ON(member_id == NULL);
355
356 return
357 bcmolt_buf_write_u8(out_buf, type) && /* Parameter set type */
358 bcmolt_buf_write_u8(out_buf, 0) &&
359 bcmolt_buf_write_u8(out_buf, 0) && /* options & 4 bit length */
360 bcmolt_buf_write_u8(out_buf, MKA_MI_LEN + sizeof(uint32_t)) && /* Parameter set body length. */
361 bcmolt_buf_write(out_buf, member_id, MKA_MI_LEN) &&
362 bcmolt_buf_write_u32_be(out_buf, message_num);
363}
364
365/* Build ICV Indicator parameter set */
366static bcmos_bool _mka_build_icv_indicator(bcmolt_buf *out_buf)
367{
368 /* Parameter checks. */
369 BUG_ON(out_buf == NULL);
370
371 return
372 bcmolt_buf_write_u8(out_buf, MKPDU_PARAM_SET_ICV_INDICATOR) &&
373 bcmolt_buf_write_u8(out_buf, 0) &&
374 bcmolt_buf_write_u8(out_buf, 0) && /* options & 4 bit length */
375 bcmolt_buf_write_u8(out_buf, MKA_ICV_LEN); /* Parameter set body length. */
376}
377
378/* Build Distributed SAK parameter set (GCM-AES-128) */
379static bcmos_bool _mka_build_distributed_sak(
380 const dpoe_sec_link_rec *link_rec,
381 bcmolt_buf *out_buf,
382 const uint8_t *key_wrapped_sak)
383{
384 uint8_t option;
385
386 /* Parameter checks. */
387 BUG_ON(link_rec == NULL);
388 BUG_ON(link_rec->mka_ctrl.mka_info == NULL);
389 BUG_ON(out_buf == NULL);
390 BUG_ON(key_wrapped_sak == NULL);
391
392 /* need Distributed AN & Confidentiality Offset (bit 5,4. use 0) */
393 option = link_rec->mka_ctrl.mka_info->association_number;
394
395 option <<= MKA_SAK_USE_PARAM_AN_SHIFT; /* move to bit 7,6 */
396
397 /* key number & AN will be increased from the caller */
398 if (!bcmolt_buf_write_u8(out_buf, MKPDU_PARAM_SET_DIST_SAK) ||
399 !bcmolt_buf_write_u8(out_buf, option) ||
400 !bcmolt_buf_write_u8(out_buf, 0) || /* options & 4 bit length */
401 !bcmolt_buf_write_u8(out_buf, MKA_KEY_WRAPPED_SAK_LEN + MKA_KN_LEN) ||
402 !bcmolt_buf_write_u32_be(out_buf, link_rec->mka_ctrl.mka_info->key_number) ||
403 !bcmolt_buf_write(out_buf, key_wrapped_sak, MKA_KEY_WRAPPED_SAK_LEN))
404 {
405 return BCMOS_FALSE;
406 }
407 return BCMOS_TRUE;
408}
409
410/* Build MACsec SAK Use paramater set */
411static bcmos_bool _mka_build_sak_use_param(
412 const dpoe_sec_link_rec *link_rec,
413 bcmolt_buf *out_buf,
414 bcmos_bool set_tx,
415 bcmos_bool set_rx)
416{
417 uint8_t option1 = 0;
418 uint8_t option2 = 0;
419 uint8_t tmp = 0;
420 uint32_t old_kn;
421
422 /* Parameter checks. */
423 BUG_ON(link_rec == NULL);
424 BUG_ON(link_rec->mka_ctrl.mka_info == NULL);
425 BUG_ON(out_buf == NULL);
426
427 /* option 1: Latest Key AN(7:6), Latest Key Tx(5), Latest Key Rx(4) Old Key AN(3:2), Old Key Tx(1), Old Key Rx(0) */
428 option1 = link_rec->mka_ctrl.mka_info->association_number;
429 option1 <<= MKA_SAK_USE_PARAM_AN_SHIFT; /* move to bit 7,6 (AN) */
430
431 if (set_tx)
432 {
433 tmp = 1 << MKA_SAK_USE_PARAM_LK_TX_SHIFT; /* Latest Key TX */
434 }
435 if (set_rx)
436 {
437 tmp = tmp | (1 << MKA_SAK_USE_PARAM_LK_RX_SHIFT); /* Latest Key Rx */
438 }
439
440 /* for first frame, all 0 is used for old key info */
441 if (link_rec->mka_ctrl.mka_info->refresh_cnt != 0)
442 {
443 /* for OLD AN, tx, rx bits */
444 tmp = tmp | ((link_rec->mka_ctrl.mka_info->association_number & MKA_SAK_USE_PARAM_OLD_KEY_AN_MASK) << MKA_SAK_USE_PARAM_OLD_KEY_AN_SFT);
445 tmp = tmp | MKA_SAK_USE_PARAM_OLD_KEY_TX_RX; /* should have been tx & rx */
446 }
447 option1 |= tmp;
448
449 /* option 2: only set bit 7,6(plain tx & plain rx). all other bits including 4 bits length field should be 0 */
450 option2 = MKA_SAK_USE_PARAM_SECOND_OPT_BYTE;
451
452 /* need to decrement key number for old key (because key numer may be already incremented) */
453 if (link_rec->mka_ctrl.mka_info->key_number == 1) /* initial number */
454 {
455 old_kn = 1;
456 }
457 else
458 {
459 old_kn = link_rec->mka_ctrl.mka_info->key_number - 1;
460 }
461
462 if (!bcmolt_buf_write_u8(out_buf, MKPDU_PARAM_SET_MACSEC_SAK_USE) ||
463 !bcmolt_buf_write_u8(out_buf, option1) ||
464 !bcmolt_buf_write_u8(out_buf, option2) ||
465 !bcmolt_buf_write_u8(out_buf, MKA_SAK_USE_PARAM_BODY_LEN) ||
466 !bcmolt_buf_write(out_buf, link_rec->mka_ctrl.mka_info->olt_member_id, MKA_MI_LEN) ||
467 !bcmolt_buf_write_u32_be(out_buf, link_rec->mka_ctrl.mka_info->key_number) ||
468 !bcmolt_buf_write_u32_be(out_buf, 1) || /* Lowest acceptable PN, start from 1 */
469 !bcmolt_buf_write(out_buf, link_rec->mka_ctrl.mka_info->olt_member_id, MKA_MI_LEN) ||
470 !bcmolt_buf_write_u32_be(out_buf, old_kn) ||
471 !bcmolt_buf_write_u32_be(out_buf, 1))
472 {
473 return BCMOS_FALSE;
474 }
475
476 return BCMOS_TRUE;
477}
478
479/* Calculate ICV and attach it at the end of MKPDU */
480static bcmos_bool _mka_calc_and_attach_icv(mka_link_info *mka_info, bcmolt_buf *out_buf)
481{
482 uint8_t ick[MKA_KEY_LEN];
483 uint8_t icv[MKA_KEY_LEN];
484
485 /* Parameter checks. */
486 BUG_ON(mka_info == NULL);
487 BUG_ON(out_buf == NULL);
488
489 _mka_calc_ick(ick, mka_info->cak, mka_info->ckn);
490
491 /* ICV will be calculated from DA to end of ICV indicator */
492 _mka_calc_icv(icv, ick, out_buf->start, (uint16_t)bcmolt_buf_get_used(out_buf));
493
494 return bcmolt_buf_write(out_buf, icv, MKA_KEY_LEN);
495}
496
497/* Send the first MKA frame to ONU */
498static bcmos_bool _mka_send_init_frame(dpoe_sec_link_rec *link_rec)
499{
500 bcmolt_buf out_buf;
501 uint8_t frame[MKA_PDU_MAX_FRAME_LEN];
502 bcmos_bool ret = BCMOS_FALSE;
503
504 /* Parameter checks. */
505 BUG_ON(link_rec == NULL);
506 BUG_ON(link_rec->mka_ctrl.mka_info == NULL);
507
508 bcmolt_buf_init(&out_buf, MKA_PDU_MAX_FRAME_LEN, frame, BCMOLT_BUF_ENDIAN_FIXED);
509 /* construct frame */
510 if (!_mka_build_eapol_header(link_rec, &out_buf, MKA_OLT_INIT_FRAME_LEN) ||
511 !_mka_build_basic_parameter_set(link_rec, &out_buf) ||
512 !_mka_build_empty_peer_list(&out_buf, MKPDU_PARAM_SET_LIVE_PEER_LIST) ||
513 !_mka_build_empty_peer_list(&out_buf, MKPDU_PARAM_SET_POTENTIAL_PEER_LIST) ||
514 !_mka_build_icv_indicator(&out_buf) ||
515 !_mka_calc_and_attach_icv(link_rec->mka_ctrl.mka_info, &out_buf)) /* last important step. Calc & attach ICV */
516 {
517 return ret;
518 }
519
520 if (BCM_ERR_OK == dpoe_sec_send_eapol(link_rec->device, &link_rec->key, frame, bcmolt_buf_get_used(&out_buf)))
521 {
522 bcmos_timer_start(&link_rec->mka_ctrl.mka_fsm_info->rx_timer, MKA_LIFE_TIME * 1000);
523 bcmos_timer_start(&link_rec->mka_ctrl.mka_fsm_info->tx_timer, MKA_HELLO_TIME * 1000);
524 ret = BCMOS_TRUE;
525 }
526
527 return ret;
528}
529
530/* Generate a SAK using RNG */
531void mka_generate_sak(dpoe_sec_link_rec *link_rec, bcmos_bool initial)
532{
533 /* Parameter checks. */
534 BUG_ON(link_rec == NULL);
535 BUG_ON(link_rec->mka_ctrl.mka_info == NULL);
536
537 /* Generate SAK */
538 if (initial)
539 {
540 _mka_calc_kek(link_rec->mka_ctrl.mka_info->kek, link_rec->mka_ctrl.mka_info->cak, link_rec->mka_ctrl.mka_info->ckn);
541 dpoe_sec_generate_n_byte_random_number(link_rec->mka_ctrl.mka_info->sak, MKA_KEY_LEN);
542 }
543 else
544 {
545 dpoe_sec_generate_n_byte_random_number(link_rec->mka_ctrl.mka_info->new_sak, MKA_KEY_LEN);
546 }
547}
548
549/* Send the SAK to the ONU */
550bcmos_errno mka_send_sak(dpoe_sec_link_rec *link_rec, uint8_t *sak)
551{
552 bcmolt_buf out_buf;
553 uint8_t frame[MKA_PDU_MAX_FRAME_LEN];
554 uint8_t key_wrapped_sak[MKA_KEY_LEN * 2] = {};
555 bcmos_errno rc = BCM_ERR_COMM_FAIL;
556 dpoe_sec_aes_key aes_key;
557
558 /* Parameter checks. */
559 BUG_ON(link_rec == NULL);
560 BUG_ON(link_rec->mka_ctrl.mka_info == NULL);
561
562 bcmolt_buf_init(&out_buf, MKA_PDU_MAX_FRAME_LEN, frame, BCMOLT_BUF_ENDIAN_FIXED);
563 /* key wrap sak using kek */
564 dpoe_sec_aes_set_encrypt_key(link_rec->mka_ctrl.mka_info->kek, MKA_KEK_LEN, &aes_key);
565 dpoe_sec_aes_wrap_key(&aes_key, key_wrapped_sak, sak, MKA_SAK_LEN);
566
567 /* construct frame */
568 if (!_mka_build_eapol_header(
569 link_rec,
570 &out_buf,
571 MKA_OLT_INIT_FRAME_LEN + MKA_ONE_PEER_LEN + MKA_DISTRIBUTED_SAK_LEN + MKA_SAK_USE_PARAM_LEM) ||
572 !_mka_build_basic_parameter_set(link_rec, &out_buf) ||
573 !_mka_build_peer_list(
574 &out_buf,
575 MKPDU_PARAM_SET_LIVE_PEER_LIST,
576 link_rec->mka_ctrl.mka_info->link_memeber_id,
577 link_rec->mka_ctrl.mka_info->link_msg_num) ||
578 !_mka_build_empty_peer_list(&out_buf, MKPDU_PARAM_SET_POTENTIAL_PEER_LIST) ||
579 !_mka_build_distributed_sak(link_rec, &out_buf, key_wrapped_sak) ||
580 !_mka_build_sak_use_param(link_rec, &out_buf, BCMOS_FALSE, BCMOS_TRUE) || /* set RX only */
581 !_mka_build_icv_indicator(&out_buf))
582 {
583 return BCM_ERR_OVERFLOW;
584 }
585
586 /* last important step. Calc & attach ICV */
587 _mka_calc_and_attach_icv(link_rec->mka_ctrl.mka_info, &out_buf);
588
589 if (BCM_ERR_OK == dpoe_sec_send_eapol(link_rec->device, &link_rec->key, frame, bcmolt_buf_get_used(&out_buf)))
590 {
591 bcmos_timer_start(&link_rec->mka_ctrl.mka_fsm_info->tx_timer, MKA_HELLO_TIME * 1000);
592 rc = BCM_ERR_OK;
593 }
594
595 return rc;
596}
597
598/* Received SAK response. Send confirm frame to ONU */
599static bcmos_bool _mka_send_sak_confirm_frame(dpoe_sec_link_rec *link_rec)
600{
601 bcmolt_buf out_buf;
602 uint8_t frame[MKA_PDU_MAX_FRAME_LEN];
603
604 /* Parameter checks. */
605 BUG_ON(link_rec == NULL);
606 BUG_ON(link_rec->mka_ctrl.mka_info == NULL);
607
608 bcmolt_buf_init(&out_buf, MKA_PDU_MAX_FRAME_LEN, frame, BCMOLT_BUF_ENDIAN_FIXED);
609 if (!_mka_build_eapol_header(link_rec, &out_buf, MKA_OLT_INIT_FRAME_LEN + MKA_ONE_PEER_LEN + MKA_SAK_USE_PARAM_LEM) ||
610 !_mka_build_basic_parameter_set(link_rec, &out_buf) ||
611 !_mka_build_peer_list(
612 &out_buf, MKPDU_PARAM_SET_LIVE_PEER_LIST,
613 link_rec->mka_ctrl.mka_info->link_memeber_id,
614 link_rec->mka_ctrl.mka_info->link_msg_num) ||
615 !_mka_build_empty_peer_list(&out_buf, MKPDU_PARAM_SET_POTENTIAL_PEER_LIST) ||
616 !_mka_build_sak_use_param(link_rec, &out_buf, BCMOS_TRUE, BCMOS_TRUE) ||
617 !_mka_build_icv_indicator(&out_buf))
618 {
619 return BCMOS_FALSE;
620 }
621
622 /* last important step. Calc & attach ICV */
623 _mka_calc_and_attach_icv(link_rec->mka_ctrl.mka_info, &out_buf);
624
625 return BCM_ERR_OK == dpoe_sec_send_eapol(link_rec->device, &link_rec->key, frame, bcmolt_buf_get_used(&out_buf));
626}
627
628/* send keep-alive frame every 2 seconds */
629static bcmos_bool _mka_send_keepalive_frame(dpoe_sec_link_rec *link_rec)
630{
631 bcmolt_buf out_buf;
632 uint8_t frame[MKA_PDU_MAX_FRAME_LEN];
633
634 /* Parameter checks. */
635 BUG_ON(link_rec == NULL);
636 BUG_ON(link_rec->mka_ctrl.mka_info == NULL);
637
638 bcmolt_buf_init(&out_buf, MKA_PDU_MAX_FRAME_LEN, frame, BCMOLT_BUF_ENDIAN_FIXED);
639 if (!_mka_build_eapol_header(link_rec, &out_buf, MKA_OLT_INIT_FRAME_LEN + MKA_ONE_PEER_LEN) ||
640 !_mka_build_basic_parameter_set(link_rec, &out_buf) ||
641 !_mka_build_peer_list(
642 &out_buf,
643 MKPDU_PARAM_SET_LIVE_PEER_LIST,
644 link_rec->mka_ctrl.mka_info->link_memeber_id,
645 link_rec->mka_ctrl.mka_info->link_msg_num) ||
646 !_mka_build_empty_peer_list(&out_buf, MKPDU_PARAM_SET_POTENTIAL_PEER_LIST) ||
647 !_mka_build_icv_indicator(&out_buf))
648 {
649 return BCMOS_FALSE;
650 }
651
652 /* last important step. Calc & attach ICV */
653 _mka_calc_and_attach_icv(link_rec->mka_ctrl.mka_info, &out_buf);
654
655 return BCM_ERR_OK == dpoe_sec_send_eapol(link_rec->device, &link_rec->key, frame, bcmolt_buf_get_used(&out_buf));
656}
657
658/* Entry point for MKA process. It is called to start the MKA exchange with the ONU that owns the specified link. */
659bcmos_errno mka_start(dpoe_sec_link_rec *link_rec)
660{
661 bcmos_errno rc;
662
663 /* Parameter checks. */
664 BUG_ON(link_rec == NULL);
665 BUG_ON(link_rec->mka_ctrl.mka_info == NULL);
666
667 /* initialize link MKA info */
668 _mka_init_link_info(link_rec);
669
670 /* send initial frame (basic param + empty live & potential peer list */
671 if (_mka_send_init_frame(link_rec))
672 {
673 rc = BCM_ERR_OK;
674 }
675 else
676 {
677 rc = BCM_ERR_COMM_FAIL;
678 }
679
680 return rc;
681}
682
683/* Calculate the ICV over the message and compare with the ICV in the message. */
684static bcmos_errno _mka_compare_icv(mka_link_info *info, const mka_event *msg, uint8_t *rx_icv)
685{
686 uint16_t len = 0;
687 uint8_t icv[MKA_ICV_LEN];
688
689 /* Parameter checks. */
690 BUG_ON(info == NULL);
691 BUG_ON(msg == NULL);
692
693 /* If the ICV pointer is NULL, then there was no ICV in the received MKA packet. Just return an error. */
694 if (rx_icv == NULL)
695 {
696 return BCM_ERR_PARM;
697 }
698
699 /* Calculate the length of the buffer over which to calculate the ICV. */
700 len = (EAPOL_MSG_HDR_SIZE + msg->msg->eapol_length) - MKA_ICV_LEN;
701
702 _mka_calc_icv(icv, info->ick, msg->buf->start, len);
703
704 if (memcmp(icv, rx_icv, sizeof(icv)) != 0)
705 {
706 return BCM_ERR_ONU_ERR_RESP;
707 }
708
709 return BCM_ERR_OK;
710}
711
712/* Parse the Basic Parameter Set in MKA PDUs */
713static bcmos_errno _mka_parse_basic_param_set(
714 dpoe_sec_link_rec *link_rec,
715 bcmolt_buf *buf,
716 uint16_t *bytes_read,
717 uint16_t body_len,
718 uint8_t *sci,
719 uint8_t *member_id,
720 uint32_t *msg_num)
721{
722 /* Parameter checks. */
723 BUG_ON(link_rec == NULL);
724 BUG_ON(buf == NULL);
725 BUG_ON(bytes_read == NULL);
726
727 /* Read the ONU SCI */
728 if (!bcmolt_buf_read(buf, sci, MKA_SCI_LEN))
729 {
730 return BCM_ERR_PARSE;
731 }
732
733 /* Read the Member ID */
734 if (!bcmolt_buf_read(buf, member_id, MKA_MI_LEN))
735 {
736 return BCM_ERR_PARSE;
737 }
738
739 /* Read the ONU message number. */
740 if (!bcmolt_buf_read_u32_be(buf, msg_num))
741 {
742 return BCM_ERR_PARSE;
743 }
744
745 /* The SCI, MI, and MN were read from the packet. */
746 *bytes_read = MKA_SCI_LEN + MKA_MI_LEN + MKA_MN_LEN;
747
748 /* Skip the rest */
749 if (!bcmolt_buf_skip(buf, body_len - *bytes_read))
750 {
751 return BCM_ERR_PARSE;
752 }
753
754 return BCM_ERR_OK;
755}
756
757static bcmos_errno _mka_waiting_initial_response_data_ind(mka_event *msg, dpoe_sec_link_rec *link_rec)
758{
759 bcmos_errno rc = BCM_ERR_PARSE;
760 uint8_t *icv_ptr;
761 uint8_t param_set_type;
762 uint16_t body_len;
763 bcmos_bool basic_param_set_exist = BCMOS_FALSE;
764 bcmos_bool live_peer_list_exist = BCMOS_FALSE;
765 bcmos_bool potential_peer_list_exist = BCMOS_FALSE;
766 uint16_t bytes_read;
767
768 /* Validate the msg pointer. */
769 BUG_ON(msg->buf == NULL);
770 BUG_ON(msg->msg == NULL);
771
772 /* mark ICV field offset */
773 icv_ptr = msg->buf->curr + (msg->msg->eapol_length - MKA_ICV_LEN);
774
775 /* Validate the Integrity Check Value before continuing to process the packet. */
776 rc = _mka_compare_icv(link_rec->mka_ctrl.mka_info, msg, icv_ptr);
777 BCMOS_CHECK_RETURN_ERROR(BCM_ERR_OK != rc, rc);
778
779 while (bcmolt_buf_get_remaining_size(msg->buf) > 0)
780 {
781 /* Don't parse past the ICV Parameter Set */
782 if (bcmolt_buf_snap_get(msg->buf) >= icv_ptr)
783 {
784 break;
785 }
786
787 /* Read what should be the Basic Parameter Set header. */
788 if (!bcmolt_buf_read_u8(msg->buf, &param_set_type) ||
789 !bcmolt_buf_skip(msg->buf, 1) ||
790 !bcmolt_buf_read_u16_be(msg->buf, &body_len))
791 {
792 break;
793 }
794
795 /* The body length is really 12-bits. */
796 body_len &= 0x0fff;
797
798 if (param_set_type == MKPDU_PARAM_SET_LIVE_PEER_LIST)
799 {
800 /* need to find out whether it is Basic parameter set OR Live Peer List */
801 if (body_len >= MKA_BASIC_PARAM_SET_LEN)
802 {
803 rc = _mka_parse_basic_param_set(
804 link_rec,
805 msg->buf,
806 &bytes_read,
807 body_len,
808 link_rec->mka_ctrl.mka_info->onu_sci,
809 link_rec->mka_ctrl.mka_info->link_memeber_id,
810 &link_rec->mka_ctrl.mka_info->link_msg_num);
811 if (rc != BCM_ERR_OK)
812 {
813 DPOE_SEC_LINK_LOG(ERROR, link_rec, "parse basic param set failed!\n");
814 break;
815 }
816
817 /* Mark that the Basic Parameter Set was found. */
818 basic_param_set_exist = BCMOS_TRUE;
819 }
820 else
821 {
822 /* Live Peer List. skip */
823 if (!bcmolt_buf_skip(msg->buf, body_len))
824 {
825 DPOE_SEC_LINK_LOG(ERROR, link_rec, "parse live peer list failed!\n");
826 rc = BCM_ERR_PARSE;
827 break;
828 }
829
830 /* Mark that the Live Peer List Parameter Set was found. */
831 live_peer_list_exist = BCMOS_TRUE;
832 }
833 }
834 else if (param_set_type == MKPDU_PARAM_SET_POTENTIAL_PEER_LIST)
835 {
836 uint8_t mi[MKA_MI_LEN];
837
838 if (!bcmolt_buf_read(msg->buf, mi, sizeof(mi)))
839 {
840 DPOE_SEC_LINK_LOG(ERROR, link_rec, "parse potential peer list failed!\n");
841 rc = BCM_ERR_PARSE;
842 break;
843 }
844
845 /* Verify that the OLT member ID in the Potential Peer List Parameter Set matches the expected OLT member
846 ID. */
847 if (memcmp(mi, link_rec->mka_ctrl.mka_info->olt_member_id, MKA_MI_LEN) != 0)
848 {
849 DPOE_SEC_LINK_LOG(ERROR, link_rec, "wrong member ID!\n");
850 rc = BCM_ERR_ONU_ERR_RESP;
851 break;
852 }
853
854 /* Skip the remaining bytes. */
855 if (!bcmolt_buf_skip(msg->buf, body_len - MKA_MI_LEN))
856 {
857 DPOE_SEC_LINK_LOG(ERROR, link_rec, "buffer overflow!\n");
858 rc = BCM_ERR_PARSE;
859 break;
860 }
861
862 /* Mark that the Potential Peer List Parameter Set was found. */
863 potential_peer_list_exist = BCMOS_TRUE;
864 }
865 else
866 {
867 /* Skip other Parameter Set data. */
868 if (!bcmolt_buf_skip(msg->buf, body_len))
869 {
870 DPOE_SEC_LINK_LOG(ERROR, link_rec, "buffer overflow!\n");
871 rc = BCM_ERR_PARSE;
872 break;
873 }
874 }
875 }
876
877 if ((rc == BCM_ERR_OK) &&
878 basic_param_set_exist &&
879 live_peer_list_exist &&
880 potential_peer_list_exist &&
881 (link_rec->mka_ctrl.mka_info->peer_state != MKA_PEER_STATE_LIVE))
882 {
883 /* proceed to next state */
884 link_rec->mka_ctrl.mka_info->peer_state = MKA_PEER_STATE_LIVE;
885 }
886 else
887 {
888 rc = BCM_ERR_ONU_ERR_RESP;
889 }
890
891 return rc;
892}
893
894/* Handler for initial response from the ONU */
895static bcmos_errno _mka_waiting_initial_response(mka_event *msg, dpoe_sec_link_rec *link_rec)
896{
897 bcmos_errno rc = BCM_ERR_OK;
898
899 /* Parameter checks. */
900 BUG_ON(msg == NULL);
901 BUG_ON(link_rec == NULL);
902 BUG_ON(link_rec->mka_ctrl.mka_info == NULL);
903
904 switch (msg->type)
905 {
906 case MKA_MSG_TIMEOUT:
907 /* retry 3 times */
908 if (link_rec->mka_ctrl.mka_info->retry_cnt < MKA_INIT_RETRY_CNT)
909 {
910 link_rec->mka_ctrl.mka_info->retry_cnt++;
911 (void)_mka_send_init_frame(link_rec);
912 }
913 else
914 {
915 _mka_clear_link_info(link_rec);
916 rc = BCM_ERR_TIMEOUT;
917 }
918 break;
919
920 case MKA_MSG_DATA_IND:
921 rc = _mka_waiting_initial_response_data_ind(msg, link_rec);
922 break;
923
924 default:
925 rc = BCM_ERR_ONU_ERR_RESP;
926 break;
927 }
928
929 return rc;
930}
931
932static bcmos_errno _mka_initial_sak_sent_data_ind(mka_event *msg, dpoe_sec_link_rec *link_rec)
933{
934 bcmos_errno rc = BCM_ERR_PARSE;
935 uint8_t *icv_ptr;
936 uint8_t param_set_type;
937 uint8_t ks_priority;
938 uint16_t body_len;
939 bcmos_bool basic_param_ok = BCMOS_FALSE;
940 bcmos_bool live_peer_list_ok = BCMOS_FALSE;
941 bcmos_bool potential_peer_list_ok = BCMOS_FALSE;
942 bcmos_bool sak_use_param_ok = BCMOS_FALSE;
943 uint16_t bytes_read;
944
945 /* Validate the msg pointer. */
946 BUG_ON(msg->msg == NULL);
947 BUG_ON(msg->buf == NULL);
948
949 /* mark ICV field offset */
950 icv_ptr = msg->buf->curr + (msg->msg->eapol_length - MKA_ICV_LEN);
951
952 /* Validate the Integrity Check Value before continuing to process the packet. */
953 rc = _mka_compare_icv(link_rec->mka_ctrl.mka_info, msg, icv_ptr);
954 BCMOS_CHECK_RETURN_ERROR(BCM_ERR_OK != rc, rc);
955
956 while (bcmolt_buf_get_remaining_size(msg->buf) > 0)
957 {
958 /* Don't parse past the ICV Parameter Set */
959 if (bcmolt_buf_snap_get(msg->buf) >= icv_ptr)
960 {
961 break;
962 }
963
964 /* Read what should be the Basic Parameter Set header. */
965 if (!bcmolt_buf_read_u8(msg->buf, &param_set_type) ||
966 !bcmolt_buf_read_u8(msg->buf, &ks_priority) ||
967 !bcmolt_buf_read_u16_be(msg->buf, &body_len))
968 {
969 rc = BCM_ERR_PARSE;
970 break;
971 }
972
973 /* The body length is really 12-bits. */
974 body_len &= 0x0fff;
975
976 if (param_set_type == MKPDU_PARAM_SET_LIVE_PEER_LIST)
977 {
978 /* need to find out whether it is Basic parameter set OR Live Peer List */
979 if (body_len >= MKA_BASIC_PARAM_SET_LEN)
980 {
981 /* in our environment, ONU can not have more than one live peer. So, just seeing param set body len
982 should be good enough. */
983 uint32_t link_mn;
984 uint8_t sci[MKA_SCI_LEN];
985 uint8_t mi[MKA_MI_LEN];
986
987 rc = _mka_parse_basic_param_set(link_rec, msg->buf, &bytes_read, body_len, sci, mi, &link_mn);
988 if (rc != BCM_ERR_OK)
989 {
990 break;
991 }
992
993 /* Verify that ONU SCI is what's expected. */
994 if (memcmp(link_rec->mka_ctrl.mka_info->onu_sci, sci, MKA_SCI_LEN) != 0)
995 {
996 rc = BCM_ERR_ONU_ERR_RESP;
997 break;
998 }
999
1000 /* Verify that ONU MI is what's expected. */
1001 if (memcmp(link_rec->mka_ctrl.mka_info->link_memeber_id, mi, MKA_MI_LEN) != 0)
1002 {
1003 rc = BCM_ERR_ONU_ERR_RESP;
1004 break;
1005 }
1006
1007 /* Verify that the MN is what's expected. */
1008 if (link_rec->mka_ctrl.mka_info->link_msg_num < link_mn)
1009 {
1010 /* correct MN! */
1011 link_rec->mka_ctrl.mka_info->link_msg_num = link_mn;
1012 basic_param_ok = BCMOS_TRUE;
1013 }
1014 }
1015 else
1016 {
1017 /* Live Peer List. skip */
1018 if (!bcmolt_buf_skip(msg->buf, body_len))
1019 {
1020 rc = BCM_ERR_PARSE;
1021 break;
1022 }
1023
1024 /* Mark that the Live Peer List Parameter Set was found. */
1025 live_peer_list_ok = BCMOS_TRUE;
1026 }
1027 }
1028 else if (param_set_type == MKPDU_PARAM_SET_POTENTIAL_PEER_LIST)
1029 {
1030 /* Skip Potential Peer List Parameter Set. */
1031 if (!bcmolt_buf_skip(msg->buf, body_len))
1032 {
1033 rc = BCM_ERR_PARSE;
1034 break;
1035 }
1036
1037 /* Mark that the Potential Peer List Parameter Set was found. */
1038 potential_peer_list_ok = BCMOS_TRUE;
1039 }
1040 else if (param_set_type == MKPDU_PARAM_SET_MACSEC_SAK_USE)
1041 {
1042 /* check only Latest key tx & rx bits (bit 4 & 5) */
1043 if ((ks_priority & 0x30) == 0x30)
1044 {
1045 sak_use_param_ok = BCMOS_TRUE;
1046 }
1047
1048 /* Skip the MKA SAK Use Parameter Set. */
1049 if (!bcmolt_buf_skip(msg->buf, body_len))
1050 {
1051 rc = BCM_ERR_PARSE;
1052 break;
1053 }
1054 }
1055 else
1056 {
1057 /* Skip all other Parameter Set data. */
1058 if (!bcmolt_buf_skip(msg->buf, body_len))
1059 {
1060 rc = BCM_ERR_PARSE;
1061 break;
1062 }
1063 }
1064 }
1065
1066 /* Everything looks good so far? */
1067 if ((rc == BCM_ERR_OK) &&
1068 basic_param_ok &&
1069 live_peer_list_ok &&
1070 potential_peer_list_ok &&
1071 sak_use_param_ok)
1072 {
1073 DPOE_SEC_LINK_LOG(DEBUG, link_rec, "Got good MKA SAK response\n");
1074 }
1075
1076 return rc;
1077}
1078
1079/* Response frame handler for the first SAK from the OLT */
1080static bcmos_errno _mka_initial_sak_sent(mka_event *msg, dpoe_sec_link_rec *link_rec)
1081{
1082 bcmos_errno rc = BCM_ERR_OK;
1083
1084 /* Parameter checks. */
1085 BUG_ON(msg == NULL);
1086 BUG_ON(link_rec == NULL);
1087 BUG_ON(link_rec->mka_ctrl.mka_info == NULL);
1088
1089 switch (msg->type)
1090 {
1091 case MKA_MSG_TIMEOUT:
1092 _mka_clear_link_info(link_rec);
1093 rc = BCM_ERR_TIMEOUT;
1094 break;
1095
1096 case MKA_MSG_DATA_IND:
1097 rc = _mka_initial_sak_sent_data_ind(msg, link_rec);
1098 break;
1099
1100 default:
1101 rc = BCM_ERR_ONU_ERR_RESP;
1102 break;
1103 }
1104
1105 return rc;
1106}
1107
1108static bcmos_errno _mka_sak_done_data_ind(mka_event *msg, dpoe_sec_link_rec *link_rec)
1109{
1110 bcmos_errno rc = BCM_ERR_PARSE;
1111 uint8_t *icv_ptr;
1112 uint8_t param_set_type;
1113 uint16_t body_len;
1114 uint8_t ks_priority;
1115 uint16_t bytes_read;
1116
1117 /* Validate the msg pointer. */
1118 BUG_ON(msg->msg == NULL);
1119 BUG_ON(msg->buf == NULL);
1120
1121 /* mark ICV field offset */
1122 icv_ptr = msg->buf->curr + (msg->msg->eapol_length - MKA_ICV_LEN);
1123
1124 /* Validate the Integrity Check Value before continuing to process the packet. */
1125 rc = _mka_compare_icv(link_rec->mka_ctrl.mka_info, msg, icv_ptr);
1126 BCMOS_CHECK_RETURN_ERROR(BCM_ERR_OK != rc, rc);
1127
1128 while (bcmolt_buf_get_remaining_size(msg->buf) > 0)
1129 {
1130 /* Don't parse past the ICV Parameter Set */
1131 if (bcmolt_buf_snap_get(msg->buf) >= icv_ptr)
1132 {
1133 break;
1134 }
1135
1136 /* Read what should be the Basic Parameter Set header. */
1137 if (!bcmolt_buf_read_u8(msg->buf, &param_set_type) ||
1138 !bcmolt_buf_read_u8(msg->buf, &ks_priority) ||
1139 !bcmolt_buf_read_u16_be(msg->buf, &body_len))
1140 {
1141 rc = BCM_ERR_PARSE;
1142 break;
1143 }
1144
1145 /* The body length is really 12-bits. */
1146 body_len &= 0x0fff;
1147
1148 if (param_set_type == MKPDU_PARAM_SET_LIVE_PEER_LIST)
1149 {
1150 /* need to find out whether it is Basic parameter set OR Live Peer List */
1151 if (body_len >= MKA_BASIC_PARAM_SET_LEN)
1152 {
1153 /* in our environment, ONU can not have more than one live peer. So, just seeing param set body len
1154 should be good enough. */
1155 uint32_t link_mn;
1156 uint8_t sci[MKA_SCI_LEN];
1157 uint8_t mi[MKA_MI_LEN];
1158
1159 rc = _mka_parse_basic_param_set(link_rec, msg->buf, &bytes_read, body_len, sci, mi, &link_mn);
1160 if (rc != BCM_ERR_OK)
1161 {
1162 break;
1163 }
1164
1165 /* Verify that ONU SCI is what's expected. */
1166 if (memcmp(link_rec->mka_ctrl.mka_info->onu_sci, sci, MKA_SCI_LEN) != 0)
1167 {
1168 rc = BCM_ERR_ONU_ERR_RESP;
1169 break;
1170 }
1171
1172 /* Verify that ONU MI is what's expected. */
1173 if (memcmp(link_rec->mka_ctrl.mka_info->link_memeber_id, mi, MKA_MI_LEN) != 0)
1174 {
1175 rc = BCM_ERR_ONU_ERR_RESP;
1176 break;
1177 }
1178
1179 if (link_rec->mka_ctrl.mka_info->link_msg_num < link_mn)
1180 {
1181 /* correct MN! */
1182 link_rec->mka_ctrl.mka_info->link_msg_num = link_mn;
1183 }
1184 }
1185 else
1186 {
1187 /* Live Peer List. skip */
1188 if (!bcmolt_buf_skip(msg->buf, body_len))
1189 {
1190 rc = BCM_ERR_PARSE;
1191 break;
1192 }
1193 }
1194 }
1195 else if (param_set_type == MKPDU_PARAM_SET_MACSEC_SAK_USE)
1196 {
1197 uint32_t llpn;
1198
1199 /* Skip to the LLPN. */
1200 if (!bcmolt_buf_skip(msg->buf, MKA_MI_LEN + MKA_KN_LEN))
1201 {
1202 rc = BCM_ERR_PARSE;
1203 break;
1204 }
1205
1206 /* read Latest Lowest Acceptable PN */
1207 if (!bcmolt_buf_read_u32_be(msg->buf, &llpn))
1208 {
1209 rc = BCM_ERR_PARSE;
1210 break;
1211 }
1212
1213 if (llpn > MKA_MAX_ACCEPTABLE_PN)
1214 {
1215 /* Set flag to indicate SAK refresh is needed. */
1216 link_rec->mka_ctrl.mka_info->sak_refresh_needed = BCMOS_TRUE;
1217 }
1218
1219 /* check only Latest key tx & rx bits (bit 4 & 5) */
1220 if ((ks_priority & 0x30) != 0x30)
1221 {
1222 /* Wrong LK Flag */ /* TODO: why isn't this an error? */
1223 }
1224
1225 /* The MI, KN, and LLPN were read. */
1226 bytes_read = body_len - (MKA_MI_LEN + MKA_KN_LEN + sizeof(uint32_t));
1227
1228 /* Skip the rest */
1229 if (!bcmolt_buf_skip(msg->buf, bytes_read))
1230 {
1231 rc = BCM_ERR_PARSE;
1232 break;
1233 }
1234 }
1235 else
1236 {
1237 /* Skip all other Parameter Set data. */
1238 if (!bcmolt_buf_skip(msg->buf, body_len))
1239 {
1240 rc = BCM_ERR_PARSE;
1241 break;
1242 }
1243 }
1244 }
1245
1246 /* refresh retry count. This is a Critical counter */
1247 link_rec->mka_ctrl.mka_info->retry_cnt = 0;
1248
1249 return rc;
1250}
1251
1252/* MKA frame handler for stable state */
1253static bcmos_errno _mka_sak_done(mka_event *msg, dpoe_sec_link_rec *link_rec)
1254{
1255 bcmos_errno rc = BCM_ERR_OK;
1256
1257 /* Parameter checks. */
1258 BUG_ON(msg == NULL);
1259 BUG_ON(link_rec == NULL);
1260 BUG_ON(link_rec->mka_ctrl.mka_info == NULL);
1261
1262 switch (msg->type)
1263 {
1264 case MKA_MSG_TIMEOUT:
1265 /* send keepalive frame at every 2 seconds */
1266 (void)_mka_send_keepalive_frame(link_rec);
1267 break;
1268
1269 case MKA_MSG_DATA_IND:
1270 rc = _mka_sak_done_data_ind(msg, link_rec);
1271 break;
1272
1273 default:
1274 rc = BCM_ERR_ONU_ERR_RESP;
1275 break;
1276 }
1277
1278 return rc;
1279}
1280
1281/* Validate the MKA packet. */
1282static bcmos_bool _mka_validate_pkt(bcmolt_u8_list_u16 mka_msg, eapol_msg_hdr *eapol)
1283{
1284 /* Parameter checks. */
1285 BUG_ON(eapol == NULL);
1286
1287 /* This had better be an MKA packet. */
1288 if (eapol->eapol_packet_type != EAPOL_TYPE_MKA)
1289 {
1290 return BCMOS_FALSE;
1291 }
1292
1293 /* The EAPOL length plus the size of the EapolMsgHdr must equal the length of the received packet. */
1294 if (mka_msg.len != (eapol->eapol_length + EAPOL_MSG_HDR_SIZE))
1295 {
1296 return BCMOS_FALSE;
1297 }
1298
1299 /* The EAPOL length must be greater than the minimum supported length, Ethernet + EAPOL header length. */
1300 if (eapol->eapol_length < MKA_PDU_MIN_LENGTH)
1301 {
1302 return BCMOS_FALSE;
1303 }
1304
1305 /* The EAPOL length must be a multiple of four. */
1306 if ((eapol->eapol_length % 4) != 0)
1307 {
1308 return BCMOS_FALSE;
1309 }
1310
1311 return BCMOS_TRUE;
1312}
1313
1314/* Wrapper into the MKA code that sends an SAK Confirm response to the ONU. */
1315bcmos_errno mka_send_sak_confirm(dpoe_sec_link_rec *link_rec)
1316{
1317 bcmos_errno rc = BCM_ERR_OK;
1318
1319 /* Parameter checks. */
1320 BUG_ON(link_rec == NULL);
1321 BUG_ON(link_rec->mka_ctrl.mka_info == NULL);
1322
1323 /* proceed to next state */
1324 if (_mka_send_sak_confirm_frame(link_rec))
1325 {
1326 /* Everything looks good so far. Update AN and Key Number */
1327 link_rec->mka_ctrl.mka_info->key_number += 1;
1328 link_rec->mka_ctrl.mka_info->association_number += 1;
1329 if (link_rec->mka_ctrl.mka_info->association_number == 4)
1330 {
1331 /* The association number is concatenated with the OLT SCI to identify a secure association between OLT and
1332 ONU. The AN value starts at zero and cycles through values 0 - 3 as a new SAK is distributed to the ONU.
1333 */
1334 link_rec->mka_ctrl.mka_info->association_number = 0; /* AN = 0 ~ 3 */
1335 }
1336
1337 link_rec->mka_ctrl.mka_info->state = MKA_STATE_MKA_DONE;
1338 link_rec->mka_ctrl.mka_info->refresh_cnt += 1;
1339 link_rec->mka_ctrl.mka_info->retry_cnt = 0;
1340
1341 /* start keepalive timer (2 second) */
1342 bcmos_timer_start(&link_rec->mka_ctrl.mka_fsm_info->tx_timer, MKA_HELLO_TIME * 1000);
1343 }
1344 else
1345 {
1346 rc = BCM_ERR_COMM_FAIL;
1347 }
1348
1349 return rc;
1350}
1351
1352/* Wrapper into the MKA code that handles MKA PDUs from the ONU. */
1353bcmos_errno mka_process_packet(dpoe_sec_link_rec *link_rec, bcmolt_u8_list_u16 rx_frame, mka_op_type op_type)
1354{
1355 bcmos_errno rc = BCM_ERR_PARM;
1356 mka_event mka_msg;
1357 bcmolt_buf buf;
1358 eapol_msg_hdr eapol;
1359
1360 /* Parameter checks. */
1361 BUG_ON(link_rec == NULL);
1362 BUG_ON(rx_frame.val == NULL);
1363 BUG_ON((op_type <= MKA_OP__INVALID) || (op_type > MKA_OP_KEEP_ALIVE));
1364
1365 bcmolt_buf_init(&buf, rx_frame.len, rx_frame.val, BCMOLT_BUF_ENDIAN_FIXED);
1366 if (!dpoe_sec_eapol_unpack(&buf, &eapol))
1367 {
1368 DPOE_SEC_LINK_LOG(ERROR, link_rec, "failed to unpack EAPOL header!\n");
1369 return BCM_ERR_PARSE;
1370 }
1371
1372 /* Validate the MKA packet length before processing. */
1373 if (!_mka_validate_pkt(rx_frame, &eapol))
1374 {
1375 DPOE_SEC_LINK_LOG(ERROR, link_rec, "Invalid MKA packet!\n");
1376 return BCM_ERR_PARSE;
1377 }
1378
1379 /* Pass the packet to the handler. */
1380 mka_msg.type = MKA_MSG_DATA_IND;
1381 mka_msg.msg = &eapol;
1382 mka_msg.buf = &buf;
1383
1384 /* Process the MKA packet. */
1385 switch (op_type)
1386 {
1387 case MKA_OP_START_RSP:
1388 rc = _mka_waiting_initial_response(&mka_msg, link_rec);
1389 break;
1390 case MKA_OP_SAK_RSP:
1391 rc = _mka_initial_sak_sent(&mka_msg, link_rec);
1392 break;
1393 case MKA_OP_KEEP_ALIVE:
1394 rc = _mka_sak_done(&mka_msg, link_rec);
1395 break;
1396 default:
1397 break;
1398 }
1399
1400 return rc;
1401}
1402
1403/* Wrapper into the MKA code that handles MKA timeouts. */
1404bcmos_errno mka_process_timeout(dpoe_sec_link_rec *link_rec, mka_op_type op_type)
1405{
1406 bcmos_errno rc = BCM_ERR_TIMEOUT;
1407 mka_event mka_msg;
1408
1409 /* Parameter checks. */
1410 BUG_ON(link_rec == NULL);
1411 BUG_ON((op_type < MKA_OP_START_TIMEOUT) || (op_type >= MKA_OP__COUNT));
1412
1413 /* Pass the packet to the handler. */
1414 mka_msg.type = MKA_MSG_TIMEOUT;
1415
1416 /* Process the MKA packet. */
1417 switch (op_type)
1418 {
1419 case MKA_OP_START_TIMEOUT:
1420 rc = _mka_waiting_initial_response(&mka_msg, link_rec);
1421 break;
1422 case MKA_OP_SAK_TIMEOUT:
1423 rc = _mka_initial_sak_sent(&mka_msg, link_rec);
1424 break;
1425 case MKA_OP_SEND_KEEP_ALIVE:
1426 rc = _mka_sak_done(&mka_msg, link_rec);
1427 break;
1428 default:
1429 break;
1430 }
1431
1432 return rc;
1433}
1434