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