1 /* SPDX-License-Identifier: BSD-3-Clause 2 * 3 * Copyright(c) 2019-2021 Xilinx, Inc. 4 * Copyright(c) 2009-2019 Solarflare Communications Inc. 5 */ 6 7 #include "efx.h" 8 #include "efx_impl.h" 9 10 #if EFSYS_OPT_BOOTCFG 11 12 /* 13 * Maximum size of BOOTCFG block across all nics as understood by SFCgPXE. 14 * NOTE: This is larger than the Medford per-PF bootcfg sector. 15 */ 16 #define BOOTCFG_MAX_SIZE 0x1000 17 18 /* Medford per-PF bootcfg sector */ 19 #define BOOTCFG_PER_PF 0x800 20 #define BOOTCFG_PF_COUNT 16 21 22 #define DHCP_OPT_HAS_VALUE(opt) \ 23 (((opt) > EFX_DHCP_PAD) && ((opt) < EFX_DHCP_END)) 24 25 #define DHCP_MAX_VALUE 255 26 27 #define DHCP_ENCAPSULATOR(encap_opt) ((encap_opt) >> 8) 28 #define DHCP_ENCAPSULATED(encap_opt) ((encap_opt) & 0xff) 29 #define DHCP_IS_ENCAP_OPT(opt) DHCP_OPT_HAS_VALUE(DHCP_ENCAPSULATOR(opt)) 30 31 typedef struct efx_dhcp_tag_hdr_s { 32 uint8_t tag; 33 uint8_t length; 34 } efx_dhcp_tag_hdr_t; 35 36 /* 37 * Length calculations for tags with value field. PAD and END 38 * have a fixed length of 1, with no length or value field. 39 */ 40 #define DHCP_FULL_TAG_LENGTH(hdr) \ 41 (sizeof (efx_dhcp_tag_hdr_t) + (hdr)->length) 42 43 #define DHCP_NEXT_TAG(hdr) \ 44 ((efx_dhcp_tag_hdr_t *)(((uint8_t *)(hdr)) + \ 45 DHCP_FULL_TAG_LENGTH((hdr)))) 46 47 #define DHCP_CALC_TAG_LENGTH(payload_len) \ 48 ((payload_len) + sizeof (efx_dhcp_tag_hdr_t)) 49 50 51 /* Report the layout of bootcfg sectors in NVRAM partition. */ 52 __checkReturn efx_rc_t 53 efx_bootcfg_sector_info( 54 __in efx_nic_t *enp, 55 __in uint32_t pf, 56 __out_opt uint32_t *sector_countp, 57 __out size_t *offsetp, 58 __out size_t *max_sizep) 59 { 60 uint32_t count; 61 size_t max_size; 62 size_t offset; 63 int rc; 64 65 switch (enp->en_family) { 66 #if EFSYS_OPT_SIENA 67 case EFX_FAMILY_SIENA: 68 max_size = BOOTCFG_MAX_SIZE; 69 offset = 0; 70 count = 1; 71 break; 72 #endif /* EFSYS_OPT_SIENA */ 73 74 #if EFSYS_OPT_HUNTINGTON 75 case EFX_FAMILY_HUNTINGTON: 76 max_size = BOOTCFG_MAX_SIZE; 77 offset = 0; 78 count = 1; 79 break; 80 #endif /* EFSYS_OPT_HUNTINGTON */ 81 82 #if EFSYS_OPT_MEDFORD 83 case EFX_FAMILY_MEDFORD: { 84 /* Shared partition (array indexed by PF) */ 85 max_size = BOOTCFG_PER_PF; 86 count = BOOTCFG_PF_COUNT; 87 if (pf >= count) { 88 rc = EINVAL; 89 goto fail2; 90 } 91 offset = max_size * pf; 92 break; 93 } 94 #endif /* EFSYS_OPT_MEDFORD */ 95 96 #if EFSYS_OPT_MEDFORD2 97 case EFX_FAMILY_MEDFORD2: { 98 /* Shared partition (array indexed by PF) */ 99 max_size = BOOTCFG_PER_PF; 100 count = BOOTCFG_PF_COUNT; 101 if (pf >= count) { 102 rc = EINVAL; 103 goto fail3; 104 } 105 offset = max_size * pf; 106 break; 107 } 108 #endif /* EFSYS_OPT_MEDFORD2 */ 109 110 default: 111 EFSYS_ASSERT(0); 112 rc = ENOTSUP; 113 goto fail1; 114 } 115 EFSYS_ASSERT3U(max_size, <=, BOOTCFG_MAX_SIZE); 116 117 if (sector_countp != NULL) 118 *sector_countp = count; 119 *offsetp = offset; 120 *max_sizep = max_size; 121 122 return (0); 123 124 #if EFSYS_OPT_MEDFORD2 125 fail3: 126 EFSYS_PROBE(fail3); 127 #endif 128 #if EFSYS_OPT_MEDFORD 129 fail2: 130 EFSYS_PROBE(fail2); 131 #endif 132 fail1: 133 EFSYS_PROBE1(fail1, efx_rc_t, rc); 134 return (rc); 135 } 136 137 138 __checkReturn uint8_t 139 efx_dhcp_csum( 140 __in_bcount(size) uint8_t const *data, 141 __in size_t size) 142 { 143 unsigned int pos; 144 uint8_t checksum = 0; 145 146 for (pos = 0; pos < size; pos++) 147 checksum += data[pos]; 148 return (checksum); 149 } 150 151 __checkReturn efx_rc_t 152 efx_dhcp_verify( 153 __in_bcount(size) uint8_t const *data, 154 __in size_t size, 155 __out_opt size_t *usedp) 156 { 157 size_t offset = 0; 158 size_t used = 0; 159 efx_rc_t rc; 160 161 /* Start parsing tags immediately after the checksum */ 162 for (offset = 1; offset < size; ) { 163 uint8_t tag; 164 uint8_t length; 165 166 /* Consume tag */ 167 tag = data[offset]; 168 if (tag == EFX_DHCP_END) { 169 offset++; 170 used = offset; 171 break; 172 } 173 if (tag == EFX_DHCP_PAD) { 174 offset++; 175 continue; 176 } 177 178 /* Consume length */ 179 if (offset + 1 >= size) { 180 rc = ENOSPC; 181 goto fail1; 182 } 183 length = data[offset + 1]; 184 185 /* Consume *length */ 186 if (offset + 1 + length >= size) { 187 rc = ENOSPC; 188 goto fail2; 189 } 190 191 offset += 2 + length; 192 used = offset; 193 } 194 195 /* Checksum the entire sector, including bytes after any EFX_DHCP_END */ 196 if (efx_dhcp_csum(data, size) != 0) { 197 rc = EINVAL; 198 goto fail3; 199 } 200 201 if (usedp != NULL) 202 *usedp = used; 203 204 return (0); 205 206 fail3: 207 EFSYS_PROBE(fail3); 208 fail2: 209 EFSYS_PROBE(fail2); 210 fail1: 211 EFSYS_PROBE1(fail1, efx_rc_t, rc); 212 213 return (rc); 214 } 215 216 /* 217 * Walk the entire tag set looking for option. The sought option may be 218 * encapsulated. ENOENT indicates the walk completed without finding the 219 * option. If we run out of buffer during the walk the function will return 220 * ENOSPC. 221 */ 222 static efx_rc_t 223 efx_dhcp_walk_tags( 224 __deref_inout uint8_t **tagpp, 225 __inout size_t *buffer_sizep, 226 __in uint16_t opt) 227 { 228 efx_rc_t rc = 0; 229 boolean_t is_encap = B_FALSE; 230 231 if (DHCP_IS_ENCAP_OPT(opt)) { 232 /* 233 * Look for the encapsulator and, if found, limit ourselves 234 * to its payload. If it's not found then the entire tag 235 * cannot be found, so the encapsulated opt search is 236 * skipped. 237 */ 238 rc = efx_dhcp_walk_tags(tagpp, buffer_sizep, 239 DHCP_ENCAPSULATOR(opt)); 240 if (rc == 0) { 241 *buffer_sizep = ((efx_dhcp_tag_hdr_t *)*tagpp)->length; 242 (*tagpp) += sizeof (efx_dhcp_tag_hdr_t); 243 } 244 opt = DHCP_ENCAPSULATED(opt); 245 is_encap = B_TRUE; 246 } 247 248 EFSYS_ASSERT(!DHCP_IS_ENCAP_OPT(opt)); 249 250 while (rc == 0) { 251 size_t size; 252 253 if (*buffer_sizep == 0) { 254 rc = ENOSPC; 255 goto fail1; 256 } 257 258 if (DHCP_ENCAPSULATED(**tagpp) == opt) 259 break; 260 261 if ((**tagpp) == EFX_DHCP_END) { 262 rc = ENOENT; 263 break; 264 } else if ((**tagpp) == EFX_DHCP_PAD) { 265 size = 1; 266 } else { 267 if (*buffer_sizep < sizeof (efx_dhcp_tag_hdr_t)) { 268 rc = ENOSPC; 269 goto fail2; 270 } 271 272 size = 273 DHCP_FULL_TAG_LENGTH((efx_dhcp_tag_hdr_t *)*tagpp); 274 } 275 276 if (size > *buffer_sizep) { 277 rc = ENOSPC; 278 goto fail3; 279 } 280 281 (*tagpp) += size; 282 (*buffer_sizep) -= size; 283 284 if ((*buffer_sizep == 0) && is_encap) { 285 /* Search within encapulator tag finished */ 286 rc = ENOENT; 287 break; 288 } 289 } 290 291 /* 292 * Returns 0 if found otherwise ENOENT indicating search finished 293 * correctly 294 */ 295 return (rc); 296 297 fail3: 298 EFSYS_PROBE(fail3); 299 fail2: 300 EFSYS_PROBE(fail2); 301 fail1: 302 EFSYS_PROBE1(fail1, efx_rc_t, rc); 303 304 return (rc); 305 } 306 307 /* 308 * Locate value buffer for option in the given buffer. 309 * Returns 0 if found, ENOENT indicating search finished 310 * correctly, otherwise search failed before completion. 311 */ 312 __checkReturn efx_rc_t 313 efx_dhcp_find_tag( 314 __in_bcount(buffer_length) uint8_t *bufferp, 315 __in size_t buffer_length, 316 __in uint16_t opt, 317 __deref_out uint8_t **valuepp, 318 __out size_t *value_lengthp) 319 { 320 efx_rc_t rc; 321 uint8_t *tagp = bufferp; 322 size_t len = buffer_length; 323 324 rc = efx_dhcp_walk_tags(&tagp, &len, opt); 325 if (rc == 0) { 326 efx_dhcp_tag_hdr_t *hdrp; 327 328 hdrp = (efx_dhcp_tag_hdr_t *)tagp; 329 *valuepp = (uint8_t *)(&hdrp[1]); 330 *value_lengthp = hdrp->length; 331 } else if (rc != ENOENT) { 332 goto fail1; 333 } 334 335 return (rc); 336 337 fail1: 338 EFSYS_PROBE1(fail1, efx_rc_t, rc); 339 340 return (rc); 341 } 342 343 /* 344 * Locate the end tag in the given buffer. 345 * Returns 0 if found, ENOENT indicating search finished 346 * correctly but end tag was not found; otherwise search 347 * failed before completion. 348 */ 349 __checkReturn efx_rc_t 350 efx_dhcp_find_end( 351 __in_bcount(buffer_length) uint8_t *bufferp, 352 __in size_t buffer_length, 353 __deref_out uint8_t **endpp) 354 { 355 efx_rc_t rc; 356 uint8_t *endp = bufferp; 357 size_t len = buffer_length; 358 359 rc = efx_dhcp_walk_tags(&endp, &len, EFX_DHCP_END); 360 if (rc == 0) 361 *endpp = endp; 362 else if (rc != ENOENT) 363 goto fail1; 364 365 return (rc); 366 367 fail1: 368 EFSYS_PROBE1(fail1, efx_rc_t, rc); 369 370 return (rc); 371 } 372 373 374 /* 375 * Delete the given tag from anywhere in the buffer. Copes with 376 * encapsulated tags, and updates or deletes the encapsulating opt as 377 * necessary. 378 */ 379 __checkReturn efx_rc_t 380 efx_dhcp_delete_tag( 381 __inout_bcount(buffer_length) uint8_t *bufferp, 382 __in size_t buffer_length, 383 __in uint16_t opt) 384 { 385 efx_rc_t rc; 386 efx_dhcp_tag_hdr_t *hdrp; 387 size_t len; 388 uint8_t *startp; 389 uint8_t *endp; 390 391 len = buffer_length; 392 startp = bufferp; 393 394 if (!DHCP_OPT_HAS_VALUE(DHCP_ENCAPSULATED(opt))) { 395 rc = EINVAL; 396 goto fail1; 397 } 398 399 rc = efx_dhcp_walk_tags(&startp, &len, opt); 400 if (rc != 0) 401 goto fail1; 402 403 hdrp = (efx_dhcp_tag_hdr_t *)startp; 404 405 if (DHCP_IS_ENCAP_OPT(opt)) { 406 uint8_t tag_length = DHCP_FULL_TAG_LENGTH(hdrp); 407 uint8_t *encapp = bufferp; 408 efx_dhcp_tag_hdr_t *encap_hdrp; 409 410 len = buffer_length; 411 rc = efx_dhcp_walk_tags(&encapp, &len, 412 DHCP_ENCAPSULATOR(opt)); 413 if (rc != 0) 414 goto fail2; 415 416 encap_hdrp = (efx_dhcp_tag_hdr_t *)encapp; 417 if (encap_hdrp->length > tag_length) { 418 encap_hdrp->length = (uint8_t)( 419 (size_t)encap_hdrp->length - tag_length); 420 } else { 421 /* delete the encapsulating tag */ 422 hdrp = encap_hdrp; 423 } 424 } 425 426 startp = (uint8_t *)hdrp; 427 endp = (uint8_t *)DHCP_NEXT_TAG(hdrp); 428 429 if (startp < bufferp) { 430 rc = EINVAL; 431 goto fail3; 432 } 433 434 if (endp > &bufferp[buffer_length]) { 435 rc = EINVAL; 436 goto fail4; 437 } 438 439 memmove(startp, endp, 440 buffer_length - (endp - bufferp)); 441 442 return (0); 443 444 fail4: 445 EFSYS_PROBE(fail4); 446 fail3: 447 EFSYS_PROBE(fail3); 448 fail2: 449 EFSYS_PROBE(fail2); 450 fail1: 451 EFSYS_PROBE1(fail1, efx_rc_t, rc); 452 453 return (rc); 454 } 455 456 /* 457 * Write the tag header into write_pointp and optionally copies the payload 458 * into the space following. 459 */ 460 static void 461 efx_dhcp_write_tag( 462 __in uint8_t *write_pointp, 463 __in uint16_t opt, 464 __in_bcount_opt(value_length) 465 uint8_t *valuep, 466 __in size_t value_length) 467 { 468 efx_dhcp_tag_hdr_t *hdrp = (efx_dhcp_tag_hdr_t *)write_pointp; 469 hdrp->tag = DHCP_ENCAPSULATED(opt); 470 hdrp->length = (uint8_t)value_length; 471 if ((value_length > 0) && (valuep != NULL)) 472 memcpy(&hdrp[1], valuep, value_length); 473 } 474 475 /* 476 * Add the given tag to the end of the buffer. Copes with creating an 477 * encapsulated tag, and updates or creates the encapsulating opt as 478 * necessary. 479 */ 480 __checkReturn efx_rc_t 481 efx_dhcp_add_tag( 482 __inout_bcount(buffer_length) uint8_t *bufferp, 483 __in size_t buffer_length, 484 __in uint16_t opt, 485 __in_bcount_opt(value_length) uint8_t *valuep, 486 __in size_t value_length) 487 { 488 efx_rc_t rc; 489 efx_dhcp_tag_hdr_t *encap_hdrp = NULL; 490 uint8_t *insert_pointp = NULL; 491 uint8_t *endp; 492 size_t available_space; 493 size_t added_length; 494 size_t search_size; 495 uint8_t *searchp; 496 497 if (!DHCP_OPT_HAS_VALUE(DHCP_ENCAPSULATED(opt))) { 498 rc = EINVAL; 499 goto fail1; 500 } 501 502 if (value_length > DHCP_MAX_VALUE) { 503 rc = EINVAL; 504 goto fail2; 505 } 506 507 if ((value_length > 0) && (valuep == NULL)) { 508 rc = EINVAL; 509 goto fail3; 510 } 511 512 endp = bufferp; 513 available_space = buffer_length; 514 rc = efx_dhcp_walk_tags(&endp, &available_space, EFX_DHCP_END); 515 if (rc != 0) 516 goto fail4; 517 518 searchp = bufferp; 519 search_size = buffer_length; 520 if (DHCP_IS_ENCAP_OPT(opt)) { 521 rc = efx_dhcp_walk_tags(&searchp, &search_size, 522 DHCP_ENCAPSULATOR(opt)); 523 if (rc == 0) { 524 encap_hdrp = (efx_dhcp_tag_hdr_t *)searchp; 525 526 /* Check encapsulated tag is not present */ 527 search_size = encap_hdrp->length; 528 rc = efx_dhcp_walk_tags(&searchp, &search_size, 529 opt); 530 if (rc != ENOENT) { 531 rc = EINVAL; 532 goto fail5; 533 } 534 535 /* Check encapsulator will not overflow */ 536 if (((size_t)encap_hdrp->length + 537 DHCP_CALC_TAG_LENGTH(value_length)) > 538 DHCP_MAX_VALUE) { 539 rc = E2BIG; 540 goto fail6; 541 } 542 543 /* Insert at start of existing encapsulator */ 544 insert_pointp = (uint8_t *)&encap_hdrp[1]; 545 opt = DHCP_ENCAPSULATED(opt); 546 } else if (rc == ENOENT) { 547 encap_hdrp = NULL; 548 } else { 549 goto fail7; 550 } 551 } else { 552 /* Check unencapsulated tag is not present */ 553 rc = efx_dhcp_walk_tags(&searchp, &search_size, 554 opt); 555 if (rc != ENOENT) { 556 rc = EINVAL; 557 goto fail8; 558 } 559 } 560 561 if (insert_pointp == NULL) { 562 /* Insert at end of existing tags */ 563 insert_pointp = endp; 564 } 565 566 /* Includes the new encapsulator tag hdr if required */ 567 added_length = DHCP_CALC_TAG_LENGTH(value_length) + 568 (DHCP_IS_ENCAP_OPT(opt) ? sizeof (efx_dhcp_tag_hdr_t) : 0); 569 570 if (available_space <= added_length) { 571 rc = ENOMEM; 572 goto fail9; 573 } 574 575 memmove(insert_pointp + added_length, insert_pointp, 576 available_space - added_length); 577 578 if (DHCP_IS_ENCAP_OPT(opt)) { 579 /* Create new encapsulator header */ 580 added_length -= sizeof (efx_dhcp_tag_hdr_t); 581 efx_dhcp_write_tag(insert_pointp, 582 DHCP_ENCAPSULATOR(opt), NULL, added_length); 583 insert_pointp += sizeof (efx_dhcp_tag_hdr_t); 584 } else if (encap_hdrp) 585 /* Modify existing encapsulator header */ 586 encap_hdrp->length += 587 ((uint8_t)DHCP_CALC_TAG_LENGTH(value_length)); 588 589 efx_dhcp_write_tag(insert_pointp, opt, valuep, value_length); 590 591 return (0); 592 593 fail9: 594 EFSYS_PROBE(fail9); 595 fail8: 596 EFSYS_PROBE(fail8); 597 fail7: 598 EFSYS_PROBE(fail7); 599 fail6: 600 EFSYS_PROBE(fail6); 601 fail5: 602 EFSYS_PROBE(fail5); 603 fail4: 604 EFSYS_PROBE(fail4); 605 fail3: 606 EFSYS_PROBE(fail3); 607 fail2: 608 EFSYS_PROBE(fail2); 609 fail1: 610 EFSYS_PROBE1(fail1, efx_rc_t, rc); 611 612 return (rc); 613 } 614 615 /* 616 * Update an existing tag to the new value. Copes with encapsulated 617 * tags, and updates the encapsulating opt as necessary. 618 */ 619 __checkReturn efx_rc_t 620 efx_dhcp_update_tag( 621 __inout_bcount(buffer_length) uint8_t *bufferp, 622 __in size_t buffer_length, 623 __in uint16_t opt, 624 __in uint8_t *value_locationp, 625 __in_bcount_opt(value_length) uint8_t *valuep, 626 __in size_t value_length) 627 { 628 efx_rc_t rc; 629 uint8_t *write_pointp = value_locationp - sizeof (efx_dhcp_tag_hdr_t); 630 efx_dhcp_tag_hdr_t *hdrp = (efx_dhcp_tag_hdr_t *)write_pointp; 631 efx_dhcp_tag_hdr_t *encap_hdrp = NULL; 632 size_t old_length; 633 634 if (!DHCP_OPT_HAS_VALUE(DHCP_ENCAPSULATED(opt))) { 635 rc = EINVAL; 636 goto fail1; 637 } 638 639 if (value_length > DHCP_MAX_VALUE) { 640 rc = EINVAL; 641 goto fail2; 642 } 643 644 if ((value_length > 0) && (valuep == NULL)) { 645 rc = EINVAL; 646 goto fail3; 647 } 648 649 old_length = hdrp->length; 650 651 if (old_length < value_length) { 652 uint8_t *endp = bufferp; 653 size_t available_space = buffer_length; 654 655 rc = efx_dhcp_walk_tags(&endp, &available_space, 656 EFX_DHCP_END); 657 if (rc != 0) 658 goto fail4; 659 660 if (available_space < (value_length - old_length)) { 661 rc = EINVAL; 662 goto fail5; 663 } 664 } 665 666 if (DHCP_IS_ENCAP_OPT(opt)) { 667 uint8_t *encapp = bufferp; 668 size_t following_encap = buffer_length; 669 size_t new_length; 670 671 rc = efx_dhcp_walk_tags(&encapp, &following_encap, 672 DHCP_ENCAPSULATOR(opt)); 673 if (rc != 0) 674 goto fail6; 675 676 encap_hdrp = (efx_dhcp_tag_hdr_t *)encapp; 677 678 new_length = ((size_t)encap_hdrp->length + 679 value_length - old_length); 680 /* Check encapsulator will not overflow */ 681 if (new_length > DHCP_MAX_VALUE) { 682 rc = E2BIG; 683 goto fail7; 684 } 685 686 encap_hdrp->length = (uint8_t)new_length; 687 } 688 689 /* 690 * Move the following data up/down to accomodate the new payload 691 * length. 692 */ 693 if (old_length != value_length) { 694 uint8_t *destp = (uint8_t *)DHCP_NEXT_TAG(hdrp) + 695 value_length - old_length; 696 size_t count = &bufferp[buffer_length] - 697 (uint8_t *)DHCP_NEXT_TAG(hdrp); 698 699 memmove(destp, DHCP_NEXT_TAG(hdrp), count); 700 } 701 702 EFSYS_ASSERT(hdrp->tag == DHCP_ENCAPSULATED(opt)); 703 efx_dhcp_write_tag(write_pointp, opt, valuep, value_length); 704 705 return (0); 706 707 fail7: 708 EFSYS_PROBE(fail7); 709 fail6: 710 EFSYS_PROBE(fail6); 711 fail5: 712 EFSYS_PROBE(fail5); 713 fail4: 714 EFSYS_PROBE(fail4); 715 fail3: 716 EFSYS_PROBE(fail3); 717 fail2: 718 EFSYS_PROBE(fail2); 719 fail1: 720 EFSYS_PROBE1(fail1, efx_rc_t, rc); 721 722 return (rc); 723 } 724 725 726 /* 727 * Copy bootcfg sector data to a target buffer which may differ in size. 728 * Optionally corrects format errors in source buffer. 729 */ 730 efx_rc_t 731 efx_bootcfg_copy_sector( 732 __in efx_nic_t *enp, 733 __inout_bcount(sector_length) 734 uint8_t *sector, 735 __in size_t sector_length, 736 __out_bcount(data_size) uint8_t *data, 737 __in size_t data_size, 738 __in boolean_t handle_format_errors) 739 { 740 _NOTE(ARGUNUSED(enp)) 741 742 size_t used_bytes; 743 efx_rc_t rc; 744 745 /* Minimum buffer is checksum byte and EFX_DHCP_END terminator */ 746 if (data_size < 2) { 747 rc = ENOSPC; 748 goto fail1; 749 } 750 751 /* Verify that the area is correctly formatted and checksummed */ 752 rc = efx_dhcp_verify(sector, sector_length, 753 &used_bytes); 754 755 if (!handle_format_errors) { 756 if (rc != 0) 757 goto fail2; 758 759 if ((used_bytes < 2) || 760 (sector[used_bytes - 1] != EFX_DHCP_END)) { 761 /* Block too short, or EFX_DHCP_END missing */ 762 rc = ENOENT; 763 goto fail3; 764 } 765 } 766 767 /* Synthesize empty format on verification failure */ 768 if (rc != 0 || used_bytes == 0) { 769 sector[0] = 0; 770 sector[1] = EFX_DHCP_END; 771 used_bytes = 2; 772 } 773 EFSYS_ASSERT(used_bytes >= 2); /* checksum and EFX_DHCP_END */ 774 EFSYS_ASSERT(used_bytes <= sector_length); 775 EFSYS_ASSERT(sector_length >= 2); 776 777 /* 778 * Legacy bootcfg sectors don't terminate with an EFX_DHCP_END 779 * character. Modify the returned payload so it does. 780 * Reinitialise the sector if there isn't room for the character. 781 */ 782 if (sector[used_bytes - 1] != EFX_DHCP_END) { 783 if (used_bytes >= sector_length) { 784 sector[0] = 0; 785 used_bytes = 1; 786 } 787 sector[used_bytes] = EFX_DHCP_END; 788 ++used_bytes; 789 } 790 791 /* 792 * Verify that the target buffer is large enough for the 793 * entire used bootcfg area, then copy into the target buffer. 794 */ 795 if (used_bytes > data_size) { 796 rc = ENOSPC; 797 goto fail4; 798 } 799 800 data[0] = 0; /* checksum, updated below */ 801 802 /* Copy all after the checksum to the target buffer */ 803 memcpy(data + 1, sector + 1, used_bytes - 1); 804 805 /* Zero out the unused portion of the target buffer */ 806 if (used_bytes < data_size) 807 (void) memset(data + used_bytes, 0, data_size - used_bytes); 808 809 /* 810 * The checksum includes trailing data after any EFX_DHCP_END 811 * character, which we've just modified (by truncation or appending 812 * EFX_DHCP_END). 813 */ 814 data[0] -= efx_dhcp_csum(data, data_size); 815 816 return (0); 817 818 fail4: 819 EFSYS_PROBE(fail4); 820 fail3: 821 EFSYS_PROBE(fail3); 822 fail2: 823 EFSYS_PROBE(fail2); 824 fail1: 825 EFSYS_PROBE1(fail1, efx_rc_t, rc); 826 827 return (rc); 828 } 829 830 efx_rc_t 831 efx_bootcfg_read( 832 __in efx_nic_t *enp, 833 __out_bcount(size) uint8_t *data, 834 __in size_t size) 835 { 836 uint8_t *payload = NULL; 837 size_t used_bytes; 838 size_t partn_length; 839 size_t sector_length; 840 size_t sector_offset; 841 efx_rc_t rc; 842 uint32_t sector_number; 843 844 /* Minimum buffer is checksum byte and EFX_DHCP_END terminator */ 845 if (size < 2) { 846 rc = ENOSPC; 847 goto fail1; 848 } 849 850 #if EFX_OPTS_EF10() 851 sector_number = enp->en_nic_cfg.enc_pf; 852 #else 853 sector_number = 0; 854 #endif 855 rc = efx_nvram_size(enp, EFX_NVRAM_BOOTROM_CFG, &partn_length); 856 if (rc != 0) 857 goto fail2; 858 859 /* The bootcfg sector may be stored in a (larger) shared partition */ 860 rc = efx_bootcfg_sector_info(enp, sector_number, 861 NULL, §or_offset, §or_length); 862 if (rc != 0) 863 goto fail3; 864 865 if (sector_length < 2) { 866 rc = EINVAL; 867 goto fail4; 868 } 869 870 if (sector_length > BOOTCFG_MAX_SIZE) 871 sector_length = BOOTCFG_MAX_SIZE; 872 873 if (sector_offset + sector_length > partn_length) { 874 /* Partition is too small */ 875 rc = EFBIG; 876 goto fail5; 877 } 878 879 /* 880 * We need to read the entire BOOTCFG sector to ensure we read all 881 * tags, because legacy bootcfg sectors are not guaranteed to end 882 * with an EFX_DHCP_END character. If the user hasn't supplied a 883 * sufficiently large buffer then use our own buffer. 884 */ 885 if (sector_length > size) { 886 EFSYS_KMEM_ALLOC(enp->en_esip, sector_length, payload); 887 if (payload == NULL) { 888 rc = ENOMEM; 889 goto fail6; 890 } 891 } else 892 payload = (uint8_t *)data; 893 894 if ((rc = efx_nvram_rw_start(enp, EFX_NVRAM_BOOTROM_CFG, NULL)) != 0) 895 goto fail7; 896 897 if ((rc = efx_nvram_read_chunk(enp, EFX_NVRAM_BOOTROM_CFG, 898 sector_offset, (caddr_t)payload, sector_length)) != 0) { 899 (void) efx_nvram_rw_finish(enp, EFX_NVRAM_BOOTROM_CFG, NULL); 900 goto fail8; 901 } 902 903 if ((rc = efx_nvram_rw_finish(enp, EFX_NVRAM_BOOTROM_CFG, NULL)) != 0) 904 goto fail9; 905 906 /* Verify that the area is correctly formatted and checksummed */ 907 rc = efx_dhcp_verify(payload, sector_length, 908 &used_bytes); 909 if (rc != 0 || used_bytes == 0) { 910 payload[0] = 0; 911 payload[1] = EFX_DHCP_END; 912 used_bytes = 2; 913 } 914 915 EFSYS_ASSERT(used_bytes >= 2); /* checksum and EFX_DHCP_END */ 916 EFSYS_ASSERT(used_bytes <= sector_length); 917 918 /* 919 * Legacy bootcfg sectors don't terminate with an EFX_DHCP_END 920 * character. Modify the returned payload so it does. 921 * BOOTCFG_MAX_SIZE is by definition large enough for any valid 922 * (per-port) bootcfg sector, so reinitialise the sector if there 923 * isn't room for the character. 924 */ 925 if (payload[used_bytes - 1] != EFX_DHCP_END) { 926 if (used_bytes >= sector_length) 927 used_bytes = 1; 928 929 payload[used_bytes] = EFX_DHCP_END; 930 ++used_bytes; 931 } 932 933 /* 934 * Verify that the user supplied buffer is large enough for the 935 * entire used bootcfg area, then copy into the user supplied buffer. 936 */ 937 if (used_bytes > size) { 938 rc = ENOSPC; 939 goto fail10; 940 } 941 942 data[0] = 0; /* checksum, updated below */ 943 944 if (sector_length > size) { 945 /* Copy all after the checksum to the target buffer */ 946 memcpy(data + 1, payload + 1, used_bytes - 1); 947 EFSYS_KMEM_FREE(enp->en_esip, sector_length, payload); 948 } 949 950 /* Zero out the unused portion of the user buffer */ 951 if (used_bytes < size) 952 (void) memset(data + used_bytes, 0, size - used_bytes); 953 954 /* 955 * The checksum includes trailing data after any EFX_DHCP_END character, 956 * which we've just modified (by truncation or appending EFX_DHCP_END). 957 */ 958 data[0] -= efx_dhcp_csum(data, size); 959 960 return (0); 961 962 fail10: 963 EFSYS_PROBE(fail10); 964 fail9: 965 EFSYS_PROBE(fail9); 966 fail8: 967 EFSYS_PROBE(fail8); 968 fail7: 969 EFSYS_PROBE(fail7); 970 if (sector_length > size) 971 EFSYS_KMEM_FREE(enp->en_esip, sector_length, payload); 972 fail6: 973 EFSYS_PROBE(fail6); 974 fail5: 975 EFSYS_PROBE(fail5); 976 fail4: 977 EFSYS_PROBE(fail4); 978 fail3: 979 EFSYS_PROBE(fail3); 980 fail2: 981 EFSYS_PROBE(fail2); 982 fail1: 983 EFSYS_PROBE1(fail1, efx_rc_t, rc); 984 985 return (rc); 986 } 987 988 efx_rc_t 989 efx_bootcfg_write( 990 __in efx_nic_t *enp, 991 __in_bcount(size) uint8_t *data, 992 __in size_t size) 993 { 994 uint8_t *partn_data; 995 uint8_t checksum; 996 size_t partn_length; 997 size_t sector_length; 998 size_t sector_offset; 999 size_t used_bytes; 1000 efx_rc_t rc; 1001 uint32_t sector_number; 1002 1003 #if EFX_OPTS_EF10() 1004 sector_number = enp->en_nic_cfg.enc_pf; 1005 #else 1006 sector_number = 0; 1007 #endif 1008 1009 rc = efx_nvram_size(enp, EFX_NVRAM_BOOTROM_CFG, &partn_length); 1010 if (rc != 0) 1011 goto fail1; 1012 1013 /* The bootcfg sector may be stored in a (larger) shared partition */ 1014 rc = efx_bootcfg_sector_info(enp, sector_number, 1015 NULL, §or_offset, §or_length); 1016 if (rc != 0) 1017 goto fail2; 1018 1019 if (sector_length > BOOTCFG_MAX_SIZE) 1020 sector_length = BOOTCFG_MAX_SIZE; 1021 1022 if (sector_offset + sector_length > partn_length) { 1023 /* Partition is too small */ 1024 rc = EFBIG; 1025 goto fail3; 1026 } 1027 1028 if ((rc = efx_dhcp_verify(data, size, &used_bytes)) != 0) 1029 goto fail4; 1030 1031 /* 1032 * The caller *must* terminate their block with a EFX_DHCP_END 1033 * character 1034 */ 1035 if ((used_bytes < 2) || ((uint8_t)data[used_bytes - 1] != 1036 EFX_DHCP_END)) { 1037 /* Block too short or EFX_DHCP_END missing */ 1038 rc = ENOENT; 1039 goto fail5; 1040 } 1041 1042 /* Check that the hardware has support for this much data */ 1043 if (used_bytes > MIN(sector_length, BOOTCFG_MAX_SIZE)) { 1044 rc = ENOSPC; 1045 goto fail6; 1046 } 1047 1048 /* 1049 * If the BOOTCFG sector is stored in a shared partition, then we must 1050 * read the whole partition and insert the updated bootcfg sector at the 1051 * correct offset. 1052 */ 1053 EFSYS_KMEM_ALLOC(enp->en_esip, partn_length, partn_data); 1054 if (partn_data == NULL) { 1055 rc = ENOMEM; 1056 goto fail7; 1057 } 1058 1059 rc = efx_nvram_rw_start(enp, EFX_NVRAM_BOOTROM_CFG, NULL); 1060 if (rc != 0) 1061 goto fail8; 1062 1063 /* Read the entire partition */ 1064 rc = efx_nvram_read_chunk(enp, EFX_NVRAM_BOOTROM_CFG, 0, 1065 (caddr_t)partn_data, partn_length); 1066 if (rc != 0) 1067 goto fail9; 1068 1069 /* 1070 * Insert the BOOTCFG sector into the partition, Zero out all data 1071 * after the EFX_DHCP_END tag, and adjust the checksum. 1072 */ 1073 (void) memset(partn_data + sector_offset, 0x0, sector_length); 1074 (void) memcpy(partn_data + sector_offset, data, used_bytes); 1075 1076 checksum = efx_dhcp_csum(data, used_bytes); 1077 partn_data[sector_offset] -= checksum; 1078 1079 if ((rc = efx_nvram_erase(enp, EFX_NVRAM_BOOTROM_CFG)) != 0) 1080 goto fail10; 1081 1082 if ((rc = efx_nvram_write_chunk(enp, EFX_NVRAM_BOOTROM_CFG, 1083 0, (caddr_t)partn_data, partn_length)) != 0) 1084 goto fail11; 1085 1086 if ((rc = efx_nvram_rw_finish(enp, EFX_NVRAM_BOOTROM_CFG, NULL)) != 0) 1087 goto fail12; 1088 1089 EFSYS_KMEM_FREE(enp->en_esip, partn_length, partn_data); 1090 1091 return (0); 1092 1093 fail12: 1094 EFSYS_PROBE(fail12); 1095 fail11: 1096 EFSYS_PROBE(fail11); 1097 fail10: 1098 EFSYS_PROBE(fail10); 1099 fail9: 1100 EFSYS_PROBE(fail9); 1101 1102 (void) efx_nvram_rw_finish(enp, EFX_NVRAM_BOOTROM_CFG, NULL); 1103 fail8: 1104 EFSYS_PROBE(fail8); 1105 1106 EFSYS_KMEM_FREE(enp->en_esip, partn_length, partn_data); 1107 fail7: 1108 EFSYS_PROBE(fail7); 1109 fail6: 1110 EFSYS_PROBE(fail6); 1111 fail5: 1112 EFSYS_PROBE(fail5); 1113 fail4: 1114 EFSYS_PROBE(fail4); 1115 fail3: 1116 EFSYS_PROBE(fail3); 1117 fail2: 1118 EFSYS_PROBE(fail2); 1119 fail1: 1120 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1121 1122 return (rc); 1123 } 1124 1125 #endif /* EFSYS_OPT_BOOTCFG */ 1126