1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Thunderbolt XDomain property support 4 * 5 * Copyright (C) 2017, Intel Corporation 6 * Authors: Michael Jamet <michael.jamet@intel.com> 7 * Mika Westerberg <mika.westerberg@linux.intel.com> 8 */ 9 10 #include <linux/err.h> 11 #include <linux/overflow.h> 12 #include <linux/slab.h> 13 #include <linux/string.h> 14 #include <linux/uuid.h> 15 #include <linux/thunderbolt.h> 16 17 struct tb_property_entry { 18 u32 key_hi; 19 u32 key_lo; 20 u16 length; 21 u8 reserved; 22 u8 type; 23 u32 value; 24 }; 25 26 struct tb_property_rootdir_entry { 27 u32 magic; 28 u32 length; 29 struct tb_property_entry entries[]; 30 }; 31 32 struct tb_property_dir_entry { 33 u32 uuid[4]; 34 struct tb_property_entry entries[]; 35 }; 36 37 #define TB_PROPERTY_ROOTDIR_MAGIC 0x55584401 38 #define TB_PROPERTY_MAX_DEPTH 8 39 40 static struct tb_property_dir *__tb_property_parse_dir(const u32 *block, 41 size_t block_len, unsigned int dir_offset, size_t dir_len, 42 bool is_root, unsigned int depth); 43 44 static inline void parse_dwdata(void *dst, const void *src, size_t dwords) 45 { 46 be32_to_cpu_array(dst, src, dwords); 47 } 48 49 static inline void format_dwdata(void *dst, const void *src, size_t dwords) 50 { 51 cpu_to_be32_array(dst, src, dwords); 52 } 53 54 static bool tb_property_entry_valid(const struct tb_property_entry *entry, 55 size_t block_len) 56 { 57 u32 end; 58 59 switch (entry->type) { 60 case TB_PROPERTY_TYPE_DIRECTORY: 61 case TB_PROPERTY_TYPE_DATA: 62 case TB_PROPERTY_TYPE_TEXT: 63 if (!entry->length) 64 return false; 65 if (entry->length > block_len) 66 return false; 67 if (check_add_overflow(entry->value, entry->length, &end) || 68 end > block_len) 69 return false; 70 break; 71 72 case TB_PROPERTY_TYPE_VALUE: 73 if (entry->length != 1) 74 return false; 75 break; 76 } 77 78 return true; 79 } 80 81 static bool tb_property_key_valid(const char *key) 82 { 83 return key && strlen(key) <= TB_PROPERTY_KEY_SIZE; 84 } 85 86 static struct tb_property * 87 tb_property_alloc(const char *key, enum tb_property_type type) 88 { 89 struct tb_property *property; 90 91 property = kzalloc_obj(*property); 92 if (!property) 93 return NULL; 94 95 strcpy(property->key, key); 96 property->type = type; 97 INIT_LIST_HEAD(&property->list); 98 99 return property; 100 } 101 102 static struct tb_property *tb_property_parse(const u32 *block, size_t block_len, 103 const struct tb_property_entry *entry, 104 unsigned int depth) 105 { 106 char key[TB_PROPERTY_KEY_SIZE + 1]; 107 struct tb_property *property; 108 struct tb_property_dir *dir; 109 110 if (!tb_property_entry_valid(entry, block_len)) 111 return NULL; 112 113 parse_dwdata(key, entry, 2); 114 key[TB_PROPERTY_KEY_SIZE] = '\0'; 115 116 property = tb_property_alloc(key, entry->type); 117 if (!property) 118 return NULL; 119 120 property->length = entry->length; 121 122 switch (property->type) { 123 case TB_PROPERTY_TYPE_DIRECTORY: 124 dir = __tb_property_parse_dir(block, block_len, entry->value, 125 entry->length, false, depth + 1); 126 if (!dir) { 127 kfree(property); 128 return NULL; 129 } 130 property->value.dir = dir; 131 break; 132 133 case TB_PROPERTY_TYPE_DATA: 134 property->value.data = kcalloc(property->length, sizeof(u32), 135 GFP_KERNEL); 136 if (!property->value.data) { 137 kfree(property); 138 return NULL; 139 } 140 parse_dwdata(property->value.data, block + entry->value, 141 entry->length); 142 break; 143 144 case TB_PROPERTY_TYPE_TEXT: 145 property->value.text = kcalloc(property->length, sizeof(u32), 146 GFP_KERNEL); 147 if (!property->value.text) { 148 kfree(property); 149 return NULL; 150 } 151 parse_dwdata(property->value.text, block + entry->value, 152 entry->length); 153 /* Force null termination */ 154 property->value.text[property->length * 4 - 1] = '\0'; 155 break; 156 157 case TB_PROPERTY_TYPE_VALUE: 158 property->value.immediate = entry->value; 159 break; 160 161 default: 162 property->type = TB_PROPERTY_TYPE_UNKNOWN; 163 break; 164 } 165 166 return property; 167 } 168 169 static struct tb_property_dir *__tb_property_parse_dir(const u32 *block, 170 size_t block_len, unsigned int dir_offset, size_t dir_len, bool is_root, 171 unsigned int depth) 172 { 173 const struct tb_property_entry *entries; 174 size_t i, content_len, nentries; 175 unsigned int content_offset; 176 struct tb_property_dir *dir; 177 178 if (depth > TB_PROPERTY_MAX_DEPTH) 179 return NULL; 180 181 dir = kzalloc_obj(*dir); 182 if (!dir) 183 return NULL; 184 185 INIT_LIST_HEAD(&dir->properties); 186 187 if (is_root) { 188 content_offset = dir_offset + 2; 189 content_len = dir_len; 190 if (content_offset + content_len > block_len) { 191 tb_property_free_dir(dir); 192 return NULL; 193 } 194 } else { 195 if (dir_len < 4) { 196 tb_property_free_dir(dir); 197 return NULL; 198 } 199 dir->uuid = kmemdup(&block[dir_offset], sizeof(*dir->uuid), 200 GFP_KERNEL); 201 if (!dir->uuid) { 202 tb_property_free_dir(dir); 203 return NULL; 204 } 205 content_offset = dir_offset + 4; 206 content_len = dir_len - 4; /* Length includes UUID */ 207 } 208 209 entries = (const struct tb_property_entry *)&block[content_offset]; 210 nentries = content_len / (sizeof(*entries) / 4); 211 212 for (i = 0; i < nentries; i++) { 213 struct tb_property *property; 214 215 property = tb_property_parse(block, block_len, &entries[i], depth); 216 if (!property) { 217 tb_property_free_dir(dir); 218 return NULL; 219 } 220 221 list_add_tail(&property->list, &dir->properties); 222 } 223 224 return dir; 225 } 226 227 /** 228 * tb_property_parse_dir() - Parses properties from given property block 229 * @block: Property block to parse 230 * @block_len: Number of dword elements in the property block 231 * 232 * This function parses the XDomain properties data block into format that 233 * can be traversed using the helper functions provided by this module. 234 * 235 * The resulting &struct tb_property_dir needs to be released by 236 * calling tb_property_free_dir() when not needed anymore. 237 * 238 * The @block is expected to be root directory. 239 * 240 * Return: Pointer to &struct tb_property_dir, %NULL in case of failure. 241 */ 242 struct tb_property_dir *tb_property_parse_dir(const u32 *block, 243 size_t block_len) 244 { 245 const struct tb_property_rootdir_entry *rootdir = 246 (const struct tb_property_rootdir_entry *)block; 247 248 if (rootdir->magic != TB_PROPERTY_ROOTDIR_MAGIC) 249 return NULL; 250 if (rootdir->length > block_len) 251 return NULL; 252 253 return __tb_property_parse_dir(block, block_len, 0, rootdir->length, 254 true, 0); 255 } 256 257 /** 258 * tb_property_create_dir() - Creates new property directory 259 * @uuid: UUID used to identify the particular directory 260 * 261 * Creates new, empty property directory. If @uuid is %NULL then the 262 * directory is assumed to be root directory. 263 * 264 * Return: Pointer to &struct tb_property_dir, %NULL in case of failure. 265 */ 266 struct tb_property_dir *tb_property_create_dir(const uuid_t *uuid) 267 { 268 struct tb_property_dir *dir; 269 270 dir = kzalloc_obj(*dir); 271 if (!dir) 272 return NULL; 273 274 INIT_LIST_HEAD(&dir->properties); 275 if (uuid) { 276 dir->uuid = kmemdup(uuid, sizeof(*dir->uuid), GFP_KERNEL); 277 if (!dir->uuid) { 278 kfree(dir); 279 return NULL; 280 } 281 } 282 283 return dir; 284 } 285 EXPORT_SYMBOL_GPL(tb_property_create_dir); 286 287 static void tb_property_free(struct tb_property *property) 288 { 289 switch (property->type) { 290 case TB_PROPERTY_TYPE_DIRECTORY: 291 tb_property_free_dir(property->value.dir); 292 break; 293 294 case TB_PROPERTY_TYPE_DATA: 295 kfree(property->value.data); 296 break; 297 298 case TB_PROPERTY_TYPE_TEXT: 299 kfree(property->value.text); 300 break; 301 302 default: 303 break; 304 } 305 306 kfree(property); 307 } 308 309 /** 310 * tb_property_free_dir() - Release memory allocated for property directory 311 * @dir: Directory to release 312 * 313 * This will release all the memory the directory occupies including all 314 * descendants. It is OK to pass %NULL @dir, then the function does 315 * nothing. 316 */ 317 void tb_property_free_dir(struct tb_property_dir *dir) 318 { 319 struct tb_property *property, *tmp; 320 321 if (!dir) 322 return; 323 324 list_for_each_entry_safe(property, tmp, &dir->properties, list) { 325 list_del(&property->list); 326 tb_property_free(property); 327 } 328 kfree(dir->uuid); 329 kfree(dir); 330 } 331 EXPORT_SYMBOL_GPL(tb_property_free_dir); 332 333 static size_t tb_property_dir_length(const struct tb_property_dir *dir, 334 bool recurse, size_t *data_len) 335 { 336 const struct tb_property *property; 337 size_t len = 0; 338 339 if (dir->uuid) 340 len += sizeof(*dir->uuid) / 4; 341 else 342 len += sizeof(struct tb_property_rootdir_entry) / 4; 343 344 list_for_each_entry(property, &dir->properties, list) { 345 len += sizeof(struct tb_property_entry) / 4; 346 347 switch (property->type) { 348 case TB_PROPERTY_TYPE_DIRECTORY: 349 if (recurse) { 350 len += tb_property_dir_length( 351 property->value.dir, recurse, data_len); 352 } 353 /* Reserve dword padding after each directory */ 354 if (data_len) 355 *data_len += 1; 356 break; 357 358 case TB_PROPERTY_TYPE_DATA: 359 case TB_PROPERTY_TYPE_TEXT: 360 if (data_len) 361 *data_len += property->length; 362 break; 363 364 default: 365 break; 366 } 367 } 368 369 return len; 370 } 371 372 static ssize_t __tb_property_format_dir(const struct tb_property_dir *dir, 373 u32 *block, unsigned int start_offset, size_t block_len) 374 { 375 unsigned int data_offset, dir_end; 376 const struct tb_property *property; 377 struct tb_property_entry *entry; 378 size_t dir_len, data_len = 0; 379 int ret; 380 381 /* 382 * The structure of property block looks like following. Leaf 383 * data/text is included right after the directory and each 384 * directory follows each other (even nested ones). 385 * 386 * +----------+ <-- start_offset 387 * | header | <-- root directory header 388 * +----------+ --- 389 * | entry 0 | -^--------------------. 390 * +----------+ | | 391 * | entry 1 | -|--------------------|--. 392 * +----------+ | | | 393 * | entry 2 | -|-----------------. | | 394 * +----------+ | | | | 395 * : : | dir_len | | | 396 * . . | | | | 397 * : : | | | | 398 * +----------+ | | | | 399 * | entry n | v | | | 400 * +----------+ <-- data_offset | | | 401 * | data 0 | <------------------|--' | 402 * +----------+ | | 403 * | data 1 | <------------------|-----' 404 * +----------+ | 405 * | 00000000 | padding | 406 * +----------+ <-- dir_end <------' 407 * | UUID | <-- directory UUID (child directory) 408 * +----------+ 409 * | entry 0 | 410 * +----------+ 411 * | entry 1 | 412 * +----------+ 413 * : : 414 * . . 415 * : : 416 * +----------+ 417 * | entry n | 418 * +----------+ 419 * | data 0 | 420 * +----------+ 421 * 422 * We use dir_end to hold pointer to the end of the directory. It 423 * will increase as we add directories and each directory should be 424 * added starting from previous dir_end. 425 */ 426 dir_len = tb_property_dir_length(dir, false, &data_len); 427 data_offset = start_offset + dir_len; 428 dir_end = start_offset + data_len + dir_len; 429 430 if (data_offset > dir_end) 431 return -EINVAL; 432 if (dir_end > block_len) 433 return -EINVAL; 434 435 /* Write headers first */ 436 if (dir->uuid) { 437 struct tb_property_dir_entry *pe; 438 439 pe = (struct tb_property_dir_entry *)&block[start_offset]; 440 memcpy(pe->uuid, dir->uuid, sizeof(pe->uuid)); 441 entry = pe->entries; 442 } else { 443 struct tb_property_rootdir_entry *re; 444 445 re = (struct tb_property_rootdir_entry *)&block[start_offset]; 446 re->magic = TB_PROPERTY_ROOTDIR_MAGIC; 447 re->length = dir_len - sizeof(*re) / 4; 448 entry = re->entries; 449 } 450 451 list_for_each_entry(property, &dir->properties, list) { 452 const struct tb_property_dir *child; 453 454 format_dwdata(entry, property->key, 2); 455 entry->type = property->type; 456 457 switch (property->type) { 458 case TB_PROPERTY_TYPE_DIRECTORY: 459 child = property->value.dir; 460 ret = __tb_property_format_dir(child, block, dir_end, 461 block_len); 462 if (ret < 0) 463 return ret; 464 entry->length = tb_property_dir_length(child, false, 465 NULL); 466 entry->value = dir_end; 467 dir_end = ret; 468 break; 469 470 case TB_PROPERTY_TYPE_DATA: 471 format_dwdata(&block[data_offset], property->value.data, 472 property->length); 473 entry->length = property->length; 474 entry->value = data_offset; 475 data_offset += entry->length; 476 break; 477 478 case TB_PROPERTY_TYPE_TEXT: 479 format_dwdata(&block[data_offset], property->value.text, 480 property->length); 481 entry->length = property->length; 482 entry->value = data_offset; 483 data_offset += entry->length; 484 break; 485 486 case TB_PROPERTY_TYPE_VALUE: 487 entry->length = property->length; 488 entry->value = property->value.immediate; 489 break; 490 491 default: 492 break; 493 } 494 495 entry++; 496 } 497 498 return dir_end; 499 } 500 501 /** 502 * tb_property_format_dir() - Formats directory to the packed XDomain format 503 * @dir: Directory to format 504 * @block: Property block where the packed data is placed 505 * @block_len: Length of the property block 506 * 507 * This function formats the directory to the packed format that can be 508 * then sent over the thunderbolt fabric to receiving host. 509 * 510 * Passing %NULL in @block returns number of entries the block takes. 511 * 512 * Return: %0 on success, negative errno otherwise. 513 */ 514 ssize_t tb_property_format_dir(const struct tb_property_dir *dir, u32 *block, 515 size_t block_len) 516 { 517 ssize_t ret; 518 519 if (!block) { 520 size_t dir_len, data_len = 0; 521 522 dir_len = tb_property_dir_length(dir, true, &data_len); 523 return dir_len + data_len; 524 } 525 526 ret = __tb_property_format_dir(dir, block, 0, block_len); 527 return ret < 0 ? ret : 0; 528 } 529 530 /** 531 * tb_property_copy_dir() - Take a deep copy of directory 532 * @dir: Directory to copy 533 * 534 * The resulting directory needs to be released by calling tb_property_free_dir(). 535 * 536 * Return: Pointer to &struct tb_property_dir, %NULL in case of failure. 537 */ 538 struct tb_property_dir *tb_property_copy_dir(const struct tb_property_dir *dir) 539 { 540 struct tb_property *property, *p = NULL; 541 struct tb_property_dir *d; 542 543 if (!dir) 544 return NULL; 545 546 d = tb_property_create_dir(dir->uuid); 547 if (!d) 548 return NULL; 549 550 list_for_each_entry(property, &dir->properties, list) { 551 struct tb_property *p; 552 553 p = tb_property_alloc(property->key, property->type); 554 if (!p) 555 goto err_free; 556 557 p->length = property->length; 558 559 switch (property->type) { 560 case TB_PROPERTY_TYPE_DIRECTORY: 561 p->value.dir = tb_property_copy_dir(property->value.dir); 562 if (!p->value.dir) 563 goto err_free; 564 break; 565 566 case TB_PROPERTY_TYPE_DATA: 567 p->value.data = kmemdup(property->value.data, 568 property->length * 4, 569 GFP_KERNEL); 570 if (!p->value.data) 571 goto err_free; 572 break; 573 574 case TB_PROPERTY_TYPE_TEXT: 575 p->value.text = kzalloc(p->length * 4, GFP_KERNEL); 576 if (!p->value.text) 577 goto err_free; 578 strcpy(p->value.text, property->value.text); 579 break; 580 581 case TB_PROPERTY_TYPE_VALUE: 582 p->value.immediate = property->value.immediate; 583 break; 584 585 default: 586 break; 587 } 588 589 list_add_tail(&p->list, &d->properties); 590 } 591 592 return d; 593 594 err_free: 595 kfree(p); 596 tb_property_free_dir(d); 597 598 return NULL; 599 } 600 601 /** 602 * tb_property_add_immediate() - Add immediate property to directory 603 * @parent: Directory to add the property 604 * @key: Key for the property 605 * @value: Immediate value to store with the property 606 * 607 * Return: %0 on success, negative errno otherwise. 608 */ 609 int tb_property_add_immediate(struct tb_property_dir *parent, const char *key, 610 u32 value) 611 { 612 struct tb_property *property; 613 614 if (!tb_property_key_valid(key)) 615 return -EINVAL; 616 617 property = tb_property_alloc(key, TB_PROPERTY_TYPE_VALUE); 618 if (!property) 619 return -ENOMEM; 620 621 property->length = 1; 622 property->value.immediate = value; 623 624 list_add_tail(&property->list, &parent->properties); 625 return 0; 626 } 627 EXPORT_SYMBOL_GPL(tb_property_add_immediate); 628 629 /** 630 * tb_property_add_data() - Adds arbitrary data property to directory 631 * @parent: Directory to add the property 632 * @key: Key for the property 633 * @buf: Data buffer to add 634 * @buflen: Number of bytes in the data buffer 635 * 636 * Function takes a copy of @buf and adds it to the directory. 637 * 638 * Return: %0 on success, negative errno otherwise. 639 */ 640 int tb_property_add_data(struct tb_property_dir *parent, const char *key, 641 const void *buf, size_t buflen) 642 { 643 /* Need to pad to dword boundary */ 644 size_t size = round_up(buflen, 4); 645 struct tb_property *property; 646 647 if (!tb_property_key_valid(key)) 648 return -EINVAL; 649 650 property = tb_property_alloc(key, TB_PROPERTY_TYPE_DATA); 651 if (!property) 652 return -ENOMEM; 653 654 property->length = size / 4; 655 property->value.data = kzalloc(size, GFP_KERNEL); 656 if (!property->value.data) { 657 kfree(property); 658 return -ENOMEM; 659 } 660 661 memcpy(property->value.data, buf, buflen); 662 663 list_add_tail(&property->list, &parent->properties); 664 return 0; 665 } 666 EXPORT_SYMBOL_GPL(tb_property_add_data); 667 668 /** 669 * tb_property_add_text() - Adds string property to directory 670 * @parent: Directory to add the property 671 * @key: Key for the property 672 * @text: String to add 673 * 674 * Function takes a copy of @text and adds it to the directory. 675 * 676 * Return: %0 on success, negative errno otherwise. 677 */ 678 int tb_property_add_text(struct tb_property_dir *parent, const char *key, 679 const char *text) 680 { 681 /* Need to pad to dword boundary */ 682 size_t size = round_up(strlen(text) + 1, 4); 683 struct tb_property *property; 684 685 if (!tb_property_key_valid(key)) 686 return -EINVAL; 687 688 property = tb_property_alloc(key, TB_PROPERTY_TYPE_TEXT); 689 if (!property) 690 return -ENOMEM; 691 692 property->length = size / 4; 693 property->value.text = kzalloc(size, GFP_KERNEL); 694 if (!property->value.text) { 695 kfree(property); 696 return -ENOMEM; 697 } 698 699 strcpy(property->value.text, text); 700 701 list_add_tail(&property->list, &parent->properties); 702 return 0; 703 } 704 EXPORT_SYMBOL_GPL(tb_property_add_text); 705 706 /** 707 * tb_property_add_dir() - Adds a directory to the parent directory 708 * @parent: Directory to add the property 709 * @key: Key for the property 710 * @dir: Directory to add 711 * 712 * Return: %0 on success, negative errno otherwise. 713 */ 714 int tb_property_add_dir(struct tb_property_dir *parent, const char *key, 715 struct tb_property_dir *dir) 716 { 717 struct tb_property *property; 718 719 if (!tb_property_key_valid(key)) 720 return -EINVAL; 721 722 property = tb_property_alloc(key, TB_PROPERTY_TYPE_DIRECTORY); 723 if (!property) 724 return -ENOMEM; 725 726 property->value.dir = dir; 727 728 list_add_tail(&property->list, &parent->properties); 729 return 0; 730 } 731 EXPORT_SYMBOL_GPL(tb_property_add_dir); 732 733 /** 734 * tb_property_remove() - Removes property from a parent directory 735 * @property: Property to remove 736 * 737 * Note memory for @property is released as well so it is not allowed to 738 * touch the object after call to this function. 739 */ 740 void tb_property_remove(struct tb_property *property) 741 { 742 list_del(&property->list); 743 kfree(property); 744 } 745 EXPORT_SYMBOL_GPL(tb_property_remove); 746 747 /** 748 * tb_property_find() - Find a property from a directory 749 * @dir: Directory where the property is searched 750 * @key: Key to look for 751 * @type: Type of the property 752 * 753 * Finds and returns property from the given directory. Does not 754 * recurse into sub-directories. 755 * 756 * Return: Pointer to &struct tb_property, %NULL if the property was not found. 757 */ 758 struct tb_property *tb_property_find(struct tb_property_dir *dir, 759 const char *key, enum tb_property_type type) 760 { 761 struct tb_property *property; 762 763 list_for_each_entry(property, &dir->properties, list) { 764 if (property->type == type && !strcmp(property->key, key)) 765 return property; 766 } 767 768 return NULL; 769 } 770 EXPORT_SYMBOL_GPL(tb_property_find); 771 772 /** 773 * tb_property_get_next() - Get next property from directory 774 * @dir: Directory holding properties 775 * @prev: Previous property in the directory (%NULL returns the first) 776 * 777 * Return: Pointer to &struct tb_property, %NULL if property was not found. 778 */ 779 struct tb_property *tb_property_get_next(struct tb_property_dir *dir, 780 struct tb_property *prev) 781 { 782 if (prev) { 783 if (list_is_last(&prev->list, &dir->properties)) 784 return NULL; 785 return list_next_entry(prev, list); 786 } 787 return list_first_entry_or_null(&dir->properties, struct tb_property, 788 list); 789 } 790 EXPORT_SYMBOL_GPL(tb_property_get_next); 791