1 /* 2 * Copyright 2006, Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Axel Dörfler, axeld@pinc-software.de 7 */ 8 9 10 #include "utility.h" 11 12 #include <net_buffer.h> 13 #include <util/list.h> 14 15 #include <ByteOrder.h> 16 #include <KernelExport.h> 17 18 #include <stdlib.h> 19 #include <string.h> 20 #include <sys/uio.h> 21 22 23 #define TRACE_BUFFER 24 #ifdef TRACE_BUFFER 25 # define TRACE(x) dprintf x 26 #else 27 # define TRACE(x) ; 28 #endif 29 30 #define BUFFER_SIZE 2048 31 32 struct data_node { 33 struct list_link link; 34 struct data_header *header; 35 size_t offset; // the net_buffer-wide offset of this node 36 uint8 *start; // points to the start of the data 37 size_t used; // defines how much memory is used by this node 38 size_t header_space; 39 size_t tail_space; 40 }; 41 42 struct data_header { 43 int32 ref_count; 44 addr_t physical_address; 45 size_t size; 46 uint8 *data_end; 47 size_t data_space; 48 data_node *first_node; 49 }; 50 51 struct net_buffer_private : net_buffer { 52 struct list buffers; 53 data_node first_node; 54 }; 55 56 57 static status_t append_data(net_buffer *buffer, const void *data, size_t size); 58 static status_t trim_data(net_buffer *_buffer, size_t newSize); 59 static status_t remove_header(net_buffer *_buffer, size_t bytes); 60 static status_t remove_trailer(net_buffer *_buffer, size_t bytes); 61 62 63 #if 0 64 static void 65 dump_buffer(net_buffer *_buffer) 66 { 67 net_buffer_private *buffer = (net_buffer_private *)_buffer; 68 69 dprintf("buffer %p, size %ld\n", buffer, buffer->size); 70 data_node *node = NULL; 71 while ((node = (data_node *)list_get_next_item(&buffer->buffers, node)) != NULL) { 72 dprintf(" node %p, offset %ld, used %ld, header %ld, tail %ld, header %p\n", 73 node, node->offset, node->used, node->header_space, node->tail_space, node->header); 74 //dump_block((char *)node->start, node->used, " "); 75 dump_block((char *)node->start, min_c(node->used, 32), " "); 76 } 77 } 78 #endif 79 80 81 static data_header * 82 create_data_header(size_t size, size_t headerSpace) 83 { 84 // TODO: don't use malloc! 85 data_header *header = (data_header *)malloc(size); 86 if (header == NULL) 87 return NULL; 88 89 header->ref_count = 1; 90 header->physical_address = 0; 91 // TODO: initialize this correctly 92 header->size = size; 93 header->data_space = headerSpace; 94 header->data_end = (uint8 *)header + sizeof(struct data_header); 95 header->first_node = NULL; 96 97 TRACE((" create new data header %p\n", header)); 98 return header; 99 } 100 101 102 static void 103 release_data_header(data_header *header) 104 { 105 if (atomic_add(&header->ref_count, -1) != 1) 106 return; 107 108 TRACE((" free header %p\n", header)); 109 free(header); 110 } 111 112 113 inline void 114 acquire_data_header(data_header *header) 115 { 116 atomic_add(&header->ref_count, 1); 117 } 118 119 120 static void 121 free_data_header_space(data_header *header, uint8 *data, size_t size) 122 { 123 if (header->data_end != data + size) { 124 // this wasn't the last allocation, unfortunately, there is nothing 125 // to do for us, then 126 // TODO: if the need arises, a simple free list could do wonder 127 // TODO: remove_data_node() currently calls this function no matter 128 // where the node had been placed - this would need to be changed 129 // then, too. 130 return; 131 } 132 133 header->data_end -= size; 134 header->data_space += size; 135 } 136 137 138 static uint8 * 139 alloc_data_header_space(data_header *header, size_t size) 140 { 141 if (header->data_space < size) 142 return NULL; 143 144 uint8 *data = header->data_end; 145 header->data_end += size; 146 header->data_space -= size; 147 148 if (header->first_node != NULL) 149 header->first_node->header_space -= size; 150 #if 0 151 else 152 dprintf("add data to a header without first node - could overwrite something!\n"); 153 #endif 154 155 return data; 156 } 157 158 159 static void 160 init_data_node(data_node *node, data_header *header, size_t headerSpace) 161 { 162 node->header = header; 163 node->offset = 0; 164 node->start = (uint8 *)header + sizeof(data_header) + headerSpace; 165 node->used = 0; 166 node->header_space = headerSpace; 167 node->tail_space = header->size - headerSpace - sizeof(data_header); 168 } 169 170 171 static data_node * 172 add_data_node(data_header *header) 173 { 174 data_node *node = (data_node *)alloc_data_header_space(header, sizeof(data_node)); 175 if (node == NULL) 176 return NULL; 177 178 TRACE((" add data node %p to header %p\n", node, header)); 179 acquire_data_header(header); 180 memset(node, 0, sizeof(struct data_node)); 181 return node; 182 } 183 184 185 void 186 remove_data_node(data_node *node) 187 { 188 data_header *header = node->header; 189 190 TRACE((" remove data node %p from header %p\n", node, header)); 191 free_data_header_space(header, (uint8 *)node, sizeof(data_node)); 192 if (header->first_node == node) 193 header->first_node = NULL; 194 195 release_data_header(node->header); 196 } 197 198 199 // #pragma mark - 200 201 202 static net_buffer * 203 create_buffer(size_t headerSpace) 204 { 205 net_buffer_private *buffer = (net_buffer_private *)malloc(sizeof(struct net_buffer_private)); 206 if (buffer == NULL) 207 return NULL; 208 209 TRACE(("create buffer %p\n", buffer)); 210 211 data_header *header = create_data_header(BUFFER_SIZE, headerSpace); 212 if (header == NULL) { 213 free(buffer); 214 return NULL; 215 } 216 217 init_data_node(&buffer->first_node, header, headerSpace); 218 header->first_node = &buffer->first_node; 219 220 list_init(&buffer->buffers); 221 list_add_item(&buffer->buffers, &buffer->first_node); 222 223 buffer->source.ss_len = 0; 224 buffer->destination.ss_len = 0; 225 buffer->interface = NULL; 226 buffer->flags = 0; 227 buffer->size = 0; 228 229 return buffer; 230 } 231 232 233 static void 234 free_buffer(net_buffer *_buffer) 235 { 236 net_buffer_private *buffer = (net_buffer_private *)_buffer; 237 238 TRACE(("free buffer %p\n", buffer)); 239 240 data_node *node; 241 while ((node = (data_node *)list_remove_head_item(&buffer->buffers)) != NULL) { 242 remove_data_node(node); 243 } 244 245 free(buffer); 246 } 247 248 249 /*! Creates a duplicate of the \a buffer. The new buffer does not share internal 250 storage; they are completely independent from each other. 251 */ 252 static net_buffer * 253 duplicate_buffer(net_buffer *_buffer) 254 { 255 net_buffer_private *buffer = (net_buffer_private *)_buffer; 256 257 net_buffer *duplicate = create_buffer(buffer->first_node.header_space); 258 if (duplicate == NULL) 259 return NULL; 260 261 // copy the data from the source buffer 262 263 data_node *node = (data_node *)list_get_first_item(&buffer->buffers); 264 while (true) { 265 if (append_data(duplicate, node->start, node->used) < B_OK) { 266 free_buffer(duplicate); 267 return NULL; 268 } 269 270 node = (data_node *)list_get_next_item(&buffer->buffers, node); 271 if (node == NULL) 272 break; 273 } 274 275 // copy meta data from source buffer 276 277 memcpy(&duplicate->source, &buffer->source, buffer->source.ss_len); 278 memcpy(&duplicate->destination, &buffer->destination, buffer->destination.ss_len); 279 280 duplicate->flags = buffer->flags; 281 duplicate->interface = buffer->interface; 282 duplicate->size = buffer->size; 283 duplicate->protocol = buffer->protocol; 284 285 return duplicate; 286 } 287 288 289 /*! Clones the buffer by grabbing another reference to the underlying data. 290 If that data changes, it will be changed in the clone as well. 291 292 If \a shareFreeSpace is \c true, the cloned buffer may claim the free 293 space in the original buffer as the original buffer can still do. If you 294 are using this, it's your responsibility that only one of the buffers 295 will do this. 296 */ 297 static net_buffer * 298 clone_buffer(net_buffer *_buffer, bool shareFreeSpace) 299 { 300 net_buffer_private *buffer = (net_buffer_private *)_buffer; 301 302 net_buffer_private *clone = (net_buffer_private *)malloc(sizeof(struct net_buffer_private)); 303 if (clone == NULL) 304 return NULL; 305 306 data_node *node = &clone->first_node; 307 data_node *sourceNode = (data_node *)list_get_first_item(&buffer->buffers); 308 if (sourceNode == NULL) { 309 free(clone); 310 return NULL; 311 } 312 313 list_init(&clone->buffers); 314 315 // grab reference to this buffer - all additional nodes will get 316 // theirs in add_data_node() 317 atomic_add(&sourceNode->header->ref_count, 1); 318 319 while (sourceNode != NULL) { 320 node->header = sourceNode->header; 321 node->start = sourceNode->start; 322 node->used = sourceNode->used; 323 node->offset = sourceNode->offset; 324 325 if (shareFreeSpace) { 326 // both buffers could claim the free space - note that this option 327 // has to be used carefully 328 node->header_space = sourceNode->header_space; 329 node->tail_space = sourceNode->tail_space; 330 } else { 331 // the free space stays with the original buffer 332 node->header_space = 0; 333 node->tail_space = 0; 334 } 335 336 // add node to clone's list of buffers 337 list_add_item(&clone->buffers, node); 338 339 sourceNode = (data_node *)list_get_next_item(&buffer->buffers, sourceNode); 340 if (sourceNode == NULL) 341 break; 342 343 node = add_data_node(sourceNode->header); 344 if (node == NULL) { 345 // There was not enough space left for another node in this buffer 346 // TODO: handle this case! 347 panic("clone buffer hits size limit... (fix me)"); 348 free(clone); 349 return NULL; 350 } 351 } 352 353 // copy meta data from source buffer 354 355 memcpy(&clone->source, &buffer->source, buffer->source.ss_len); 356 memcpy(&clone->destination, &buffer->destination, buffer->destination.ss_len); 357 358 clone->flags = buffer->flags; 359 clone->interface = buffer->interface; 360 clone->size = buffer->size; 361 clone->protocol = buffer->protocol; 362 363 return clone; 364 } 365 366 367 /*! 368 Split the buffer at offset, the header data 369 is returned as new buffer. 370 TODO: optimize and avoid making a copy. 371 */ 372 static net_buffer * 373 split_buffer(net_buffer *from, uint32 offset) 374 { 375 net_buffer *buffer = duplicate_buffer(from); 376 if (buffer == NULL) 377 return NULL; 378 379 TRACE(("split_buffer(buffer %p -> %p, offset %ld)\n", from, buffer, offset)); 380 381 if (remove_header(from, offset) == B_OK 382 && trim_data(buffer, offset) == B_OK) 383 return buffer; 384 385 free_buffer(buffer); 386 return NULL; 387 } 388 389 390 /*! 391 Merges the second buffer with the first. If \a after is \c true, the 392 second buffer's contents will be appended to the first ones, else they 393 will be prepended. 394 The second buffer will be freed if this function succeeds. 395 */ 396 static status_t 397 merge_buffer(net_buffer *_buffer, net_buffer *_with, bool after) 398 { 399 net_buffer_private *buffer = (net_buffer_private *)_buffer; 400 net_buffer_private *with = (net_buffer_private *)_with; 401 if (with == NULL) 402 return B_BAD_VALUE; 403 404 TRACE(("merge buffer %p with %p (%s)\n", buffer, with, after ? "after" : "before")); 405 //dump_buffer(buffer); 406 //dprintf("with:\n"); 407 //dump_buffer(with); 408 409 // TODO: this is currently very simplistic, I really need to finish the 410 // harder part of this implementation (data_node management per header) 411 412 data_node *before = NULL; 413 414 if (!after) { 415 // change offset of all nodes already in the buffer 416 data_node *node = NULL; 417 while (true) { 418 node = (data_node *)list_get_next_item(&buffer->buffers, node); 419 if (node == NULL) 420 break; 421 422 node->offset += with->size; 423 if (before == NULL) 424 before = node; 425 } 426 } 427 428 data_node *last = NULL; 429 430 while (true) { 431 data_node *node = (data_node *)list_get_next_item(&with->buffers, last); 432 if (node == NULL) 433 break; 434 435 if ((uint8 *)node > (uint8 *)node->header 436 && (uint8 *)node < (uint8 *)node->header + node->header->size) { 437 // The node is already in the buffer, we can just move it 438 // over to the new owner 439 list_remove_item(&with->buffers, node); 440 } else { 441 // we need a new place for this node 442 data_node *newNode = add_data_node(node->header); 443 if (newNode == NULL) { 444 // TODO: this can't work right now as add_data_node() also grabs a reference 445 // to the header - but in this case, we would need two references, one 446 // for the data, one for the node, and there is no mechanism for this. 447 #if 0 448 // try again on the buffers own header 449 newNode = add_data_node(buffer->first_node.header); 450 if (newNode == NULL) 451 #endif 452 // TODO: try to revert buffers to their initial state!! 453 return ENOBUFS; 454 } 455 456 last = node; 457 *newNode = *node; 458 node = newNode; 459 // the old node will get freed with its buffer 460 } 461 462 if (after) { 463 list_add_item(&buffer->buffers, node); 464 node->offset = buffer->size; 465 } else 466 list_insert_item_before(&buffer->buffers, before, node); 467 468 buffer->size += node->used; 469 } 470 471 // the data has been merged completely at this point 472 free_buffer(with); 473 474 //dprintf(" merge result:\n"); 475 //dump_buffer(buffer); 476 return B_OK; 477 } 478 479 480 /*! Writes into existing allocated memory. 481 \return B_BAD_VALUE if you write outside of the buffers current 482 bounds. 483 */ 484 static status_t 485 write_data(net_buffer *_buffer, size_t offset, const void *data, size_t size) 486 { 487 net_buffer_private *buffer = (net_buffer_private *)_buffer; 488 489 if (offset + size > buffer->size) 490 return B_BAD_VALUE; 491 if (size == 0) 492 return B_OK; 493 494 // find first node to write into 495 496 data_node *node = (data_node *)list_get_first_item(&buffer->buffers); 497 while (node->offset + node->used < offset) { 498 node = (data_node *)list_get_next_item(&buffer->buffers, node); 499 if (node == NULL) 500 return B_BAD_VALUE; 501 } 502 503 offset -= node->offset; 504 505 while (true) { 506 size_t written = min_c(size, node->used - offset); 507 memcpy(node->start + offset, data, written); 508 509 size -= written; 510 if (size == 0) 511 break; 512 513 offset = 0; 514 data = (void *)((uint8 *)data + written); 515 516 node = (data_node *)list_get_next_item(&buffer->buffers, node); 517 if (node == NULL) 518 return B_BAD_VALUE; 519 } 520 521 return B_OK; 522 } 523 524 525 static status_t 526 read_data(net_buffer *_buffer, size_t offset, void *data, size_t size) 527 { 528 net_buffer_private *buffer = (net_buffer_private *)_buffer; 529 530 if (offset + size > buffer->size) 531 return B_BAD_VALUE; 532 if (size == 0) 533 return B_OK; 534 535 // find first node to read from 536 537 data_node *node = (data_node *)list_get_first_item(&buffer->buffers); 538 while (node->offset + node->used < offset) { 539 node = (data_node *)list_get_next_item(&buffer->buffers, node); 540 if (node == NULL) 541 return B_BAD_VALUE; 542 } 543 544 offset -= node->offset; 545 546 while (true) { 547 size_t bytesRead = min_c(size, node->used - offset); 548 memcpy(data, node->start + offset, bytesRead); 549 550 size -= bytesRead; 551 if (size == 0) 552 break; 553 554 offset = 0; 555 data = (void *)((uint8 *)data + bytesRead); 556 557 node = (data_node *)list_get_next_item(&buffer->buffers, node); 558 if (node == NULL) 559 return B_BAD_VALUE; 560 } 561 562 return B_OK; 563 } 564 565 566 static status_t 567 prepend_size(net_buffer *_buffer, size_t size, void **_contiguousBuffer) 568 { 569 net_buffer_private *buffer = (net_buffer_private *)_buffer; 570 data_node *node = (data_node *)list_get_first_item(&buffer->buffers); 571 572 TRACE(("prepend_size(buffer %p, size %ld)\n", buffer, size)); 573 //dump_buffer(buffer); 574 575 if (node->header_space < size) { 576 // we need to prepend a new buffer 577 578 // TODO: implement me! 579 panic("prepending buffer not implemented\n"); 580 581 if (_contiguousBuffer) 582 *_contiguousBuffer = NULL; 583 584 return B_ERROR; 585 } 586 587 // the data fits into this buffer 588 node->header_space -= size; 589 node->start -= size; 590 node->used += size; 591 592 if (_contiguousBuffer) 593 *_contiguousBuffer = node->start; 594 595 // adjust offset of following nodes 596 while ((node = (data_node *)list_get_next_item(&buffer->buffers, node)) != NULL) { 597 node->offset += size; 598 } 599 600 buffer->size += size; 601 602 //dprintf(" prepend_size result:\n"); 603 //dump_buffer(buffer); 604 return B_OK; 605 } 606 607 608 static status_t 609 prepend_data(net_buffer *buffer, const void *data, size_t size) 610 { 611 void *contiguousBuffer; 612 status_t status = prepend_size(buffer, size, &contiguousBuffer); 613 if (status < B_OK) 614 return status; 615 616 if (contiguousBuffer) 617 memcpy(contiguousBuffer, data, size); 618 else 619 write_data(buffer, 0, data, size); 620 621 //dprintf(" prepend result:\n"); 622 //dump_buffer(buffer); 623 624 return B_OK; 625 } 626 627 628 static status_t 629 append_size(net_buffer *_buffer, size_t size, void **_contiguousBuffer) 630 { 631 net_buffer_private *buffer = (net_buffer_private *)_buffer; 632 data_node *node = (data_node *)list_get_last_item(&buffer->buffers); 633 634 TRACE(("append_size(buffer %p, size %ld)\n", buffer, size)); 635 //dump_buffer(buffer); 636 637 if (node->tail_space < size) { 638 // we need to append a new buffer 639 640 // compute how many buffers we're going to need 641 // TODO: this doesn't leave any tail space, if that should be desired... 642 uint32 tailSpace = node->tail_space; 643 uint32 minimalHeaderSpace = sizeof(data_header) + 2 * sizeof(data_node); 644 uint32 sizeNeeded = size - tailSpace; 645 uint32 count = (sizeNeeded + BUFFER_SIZE - minimalHeaderSpace - 1) 646 / (BUFFER_SIZE - minimalHeaderSpace); 647 uint32 averageHeaderSpace = BUFFER_SIZE - sizeNeeded / count - sizeof(data_header); 648 uint32 averageSize = BUFFER_SIZE - sizeof(data_header) - averageHeaderSpace; 649 650 // allocate space left in the node 651 node->tail_space -= tailSpace; 652 node->used += tailSpace; 653 buffer->size += tailSpace; 654 655 // allocate all buffers 656 657 for (uint32 i = 0; i < count; i++) { 658 data_header *header = create_data_header(BUFFER_SIZE, averageHeaderSpace); 659 if (header == NULL) { 660 // TODO: free up headers we already allocated! 661 return B_NO_MEMORY; 662 } 663 664 node = (data_node *)alloc_data_header_space(header, sizeof(data_node)); 665 // this can't fail as we made sure there will be enough header space 666 667 init_data_node(node, header, averageHeaderSpace); 668 node->header_space = header->data_space; 669 node->tail_space -= averageSize; 670 node->used = averageSize; 671 node->offset = buffer->size; 672 buffer->size += averageSize; 673 674 list_add_item(&buffer->buffers, node); 675 } 676 677 if (_contiguousBuffer) 678 *_contiguousBuffer = NULL; 679 680 //dprintf(" append result 1:\n"); 681 //dump_buffer(buffer); 682 return B_OK; 683 } 684 685 // the data fits into this buffer 686 node->tail_space -= size; 687 688 if (_contiguousBuffer) 689 *_contiguousBuffer = node->start + node->used; 690 691 node->used += size; 692 buffer->size += size; 693 694 //dprintf(" append result 2:\n"); 695 //dump_buffer(buffer); 696 return B_OK; 697 } 698 699 700 static status_t 701 append_data(net_buffer *buffer, const void *data, size_t size) 702 { 703 size_t used = buffer->size; 704 705 void *contiguousBuffer; 706 status_t status = append_size(buffer, size, &contiguousBuffer); 707 if (status < B_OK) 708 return status; 709 710 if (contiguousBuffer) 711 memcpy(contiguousBuffer, data, size); 712 else 713 write_data(buffer, used, data, size); 714 715 return B_OK; 716 } 717 718 719 /*! 720 Removes bytes from the beginning of the buffer. 721 */ 722 static status_t 723 remove_header(net_buffer *_buffer, size_t bytes) 724 { 725 net_buffer_private *buffer = (net_buffer_private *)_buffer; 726 727 if (bytes > buffer->size) 728 return B_BAD_VALUE; 729 730 TRACE(("remove_header(buffer %p, %ld bytes)\n", buffer, bytes)); 731 //dump_buffer(buffer); 732 733 size_t left = bytes; 734 data_node *node = NULL; 735 736 while (left >= 0) { 737 node = (data_node *)list_get_first_item(&buffer->buffers); 738 if (node == NULL) { 739 if (left == 0) 740 break; 741 return B_ERROR; 742 } 743 744 if (node->used > left) 745 break; 746 747 // node will be removed completely 748 list_remove_item(&buffer->buffers, node); 749 left -= node->used; 750 remove_data_node(node); 751 node = NULL; 752 } 753 754 // cut remaining node, if any 755 756 if (node != NULL) { 757 size_t cut = min_c(node->used, left); 758 node->offset = 0; 759 node->start += cut; 760 node->header_space += cut; 761 node->used -= cut; 762 763 node = (data_node *)list_get_next_item(&buffer->buffers, node); 764 } 765 766 // adjust offset of following nodes 767 while (node != NULL) { 768 node->offset -= bytes; 769 node = (data_node *)list_get_next_item(&buffer->buffers, node); 770 } 771 772 buffer->size -= bytes; 773 774 //dprintf(" remove result:\n"); 775 //dump_buffer(buffer); 776 return B_OK; 777 } 778 779 780 /*! 781 Removes bytes from the end of the buffer. 782 */ 783 static status_t 784 remove_trailer(net_buffer *buffer, size_t bytes) 785 { 786 return trim_data(buffer, buffer->size - bytes); 787 } 788 789 790 /*! 791 Trims the buffer to the specified \a newSize by removing space from 792 the end of the buffer. 793 */ 794 static status_t 795 trim_data(net_buffer *_buffer, size_t newSize) 796 { 797 net_buffer_private *buffer = (net_buffer_private *)_buffer; 798 TRACE(("trim_data(buffer %p, newSize = %ld, buffer size = %ld)\n", 799 buffer, newSize, buffer->size)); 800 //dump_buffer(buffer); 801 802 if (newSize > buffer->size) 803 return B_BAD_VALUE; 804 if (newSize == buffer->size) 805 return B_OK; 806 807 data_node *node = (data_node *)list_get_first_item(&buffer->buffers); 808 while (node->offset + node->used < newSize) { 809 node = (data_node *)list_get_next_item(&buffer->buffers, node); 810 if (node == NULL) { 811 // trim size greater than buffer size 812 return B_BAD_VALUE; 813 } 814 } 815 816 int32 diff = node->used + node->offset - newSize; 817 node->tail_space += diff; 818 node->used -= diff; 819 820 if (node->used > 0) 821 node = (data_node *)list_get_next_item(&buffer->buffers, node); 822 823 while (node != NULL) { 824 data_node *next = (data_node *)list_get_next_item(&buffer->buffers, node); 825 list_remove_item(&buffer->buffers, node); 826 remove_data_node(node); 827 828 node = next; 829 } 830 831 buffer->size = newSize; 832 833 //dprintf(" trim result:\n"); 834 //dump_buffer(buffer); 835 return B_OK; 836 } 837 838 839 /*! 840 Tries to directly access the requested space in the buffer. 841 If the space is contiguous, the function will succeed and place a pointer 842 to that space into \a _contiguousBuffer. 843 844 \return B_BAD_VALUE if the offset is outside of the buffer's bounds. 845 \return B_ERROR in case the buffer is not contiguous at that location. 846 */ 847 static status_t 848 direct_access(net_buffer *_buffer, uint32 offset, size_t size, 849 void **_contiguousBuffer) 850 { 851 net_buffer_private *buffer = (net_buffer_private *)_buffer; 852 853 //TRACE(("direct_access(buffer %p, offset %ld, size %ld)\n", buffer, offset, size)); 854 855 if (offset + size > buffer->size) 856 return B_BAD_VALUE; 857 858 // find node to access 859 860 data_node *node = (data_node *)list_get_first_item(&buffer->buffers); 861 while (node->offset + node->used < offset) { 862 node = (data_node *)list_get_next_item(&buffer->buffers, node); 863 if (node == NULL) 864 return B_BAD_VALUE; 865 } 866 867 offset -= node->offset; 868 869 if (size > node->used - offset) 870 return B_ERROR; 871 872 *_contiguousBuffer = node->start + offset; 873 return B_OK; 874 } 875 876 877 static int32 878 checksum_data(net_buffer *_buffer, uint32 offset, size_t size, bool finalize) 879 { 880 net_buffer_private *buffer = (net_buffer_private *)_buffer; 881 882 if (offset + size > buffer->size || size == 0) 883 return B_BAD_VALUE; 884 885 // find first node to read from 886 887 data_node *node = (data_node *)list_get_first_item(&buffer->buffers); 888 while (node->offset + node->used < offset) { 889 node = (data_node *)list_get_next_item(&buffer->buffers, node); 890 if (node == NULL) 891 return B_ERROR; 892 } 893 894 offset -= node->offset; 895 896 // Since the maximum buffer size is 65536 bytes, it's impossible 897 // to overlap 32 bit - we don't need to handle this overlap in 898 // the loop, we can safely do it afterwards 899 uint32 sum = 0; 900 901 while (true) { 902 size_t bytes = min_c(size, node->used - offset); 903 if ((offset + node->offset) & 1) { 904 // if we're at an uneven offset, we have to swap the checksum 905 sum += __swap_int16(compute_checksum(node->start + offset, bytes)); 906 } else 907 sum += compute_checksum(node->start + offset, bytes); 908 909 size -= bytes; 910 if (size == 0) 911 break; 912 913 offset = 0; 914 915 node = (data_node *)list_get_next_item(&buffer->buffers, node); 916 if (node == NULL) 917 return B_ERROR; 918 } 919 920 while (sum >> 16) { 921 sum = (sum & 0xffff) + (sum >> 16); 922 } 923 924 if (!finalize) 925 return (uint16)sum; 926 927 return (uint16)~sum; 928 } 929 930 931 static uint32 932 get_iovecs(net_buffer *_buffer, struct iovec *iovecs, uint32 vecCount) 933 { 934 net_buffer_private *buffer = (net_buffer_private *)_buffer; 935 data_node *node = (data_node *)list_get_first_item(&buffer->buffers); 936 uint32 count = 0; 937 938 while (count < vecCount) { 939 iovecs[count].iov_base = node->start; 940 iovecs[count].iov_len = node->used; 941 count++; 942 943 node = (data_node *)list_get_next_item(&buffer->buffers, node); 944 if (node == NULL) 945 break; 946 } 947 948 return count; 949 } 950 951 952 static uint32 953 count_iovecs(net_buffer *_buffer) 954 { 955 net_buffer_private *buffer = (net_buffer_private *)_buffer; 956 data_node *node = (data_node *)list_get_first_item(&buffer->buffers); 957 uint32 count = 0; 958 959 while (true) { 960 count++; 961 962 node = (data_node *)list_get_next_item(&buffer->buffers, node); 963 if (node == NULL) 964 break; 965 } 966 967 return count; 968 } 969 970 971 static status_t 972 std_ops(int32 op, ...) 973 { 974 switch (op) { 975 case B_MODULE_INIT: 976 case B_MODULE_UNINIT: 977 return B_OK; 978 979 default: 980 return B_ERROR; 981 } 982 } 983 984 985 net_buffer_module_info gNetBufferModule = { 986 { 987 NET_BUFFER_MODULE_NAME, 988 0, 989 std_ops 990 }, 991 create_buffer, 992 free_buffer, 993 994 duplicate_buffer, 995 clone_buffer, 996 split_buffer, 997 merge_buffer, 998 999 prepend_size, 1000 prepend_data, 1001 append_size, 1002 append_data, 1003 NULL, // insert 1004 NULL, // remove 1005 remove_header, 1006 remove_trailer, 1007 trim_data, 1008 1009 NULL, // associate_data 1010 1011 direct_access, 1012 read_data, 1013 write_data, 1014 1015 checksum_data, 1016 1017 NULL, // get_memory_map 1018 get_iovecs, 1019 count_iovecs, 1020 1021 NULL, // dump 1022 }; 1023 1024