1.\" $NetBSD: mbuf.9,v 1.53 2018/01/01 12:46:49 wiz Exp $ 2.\" 3.\" Copyright (c) 1997 The NetBSD Foundation, Inc. 4.\" All rights reserved. 5.\" 6.\" This documentation is derived from text contributed to The NetBSD Foundation 7.\" by S.P.Zeidler (aka stargazer). 8.\" 9.\" Redistribution and use in source and binary forms, with or without 10.\" modification, are permitted provided that the following conditions 11.\" are met: 12.\" 1. Redistributions of source code must retain the above copyright 13.\" notice, this list of conditions and the following disclaimer. 14.\" 2. Redistributions in binary form must reproduce the above copyright 15.\" notice, this list of conditions and the following disclaimer in the 16.\" documentation and/or other materials provided with the distribution. 17.\" 18.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 19.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 21.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 22.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28.\" POSSIBILITY OF SUCH DAMAGE. 29.\" 30.Dd January 1, 2018 31.Dt MBUF 9 32.Os 33.Sh NAME 34.Nm mbuf , 35.Nm m_get , 36.Nm m_getclr , 37.Nm m_gethdr , 38.Nm m_devget , 39.Nm m_copym , 40.Nm m_copypacket , 41.Nm m_copydata , 42.Nm m_copyback , 43.Nm m_copyback_cow , 44.Nm m_cat , 45.Nm m_dup , 46.Nm m_makewritable , 47.Nm m_prepend , 48.Nm m_pulldown , 49.Nm m_pullup , 50.Nm m_copyup , 51.Nm m_split , 52.Nm m_adj , 53.Nm m_apply , 54.Nm m_free , 55.Nm m_freem , 56.Nm mtod , 57.Nm MGET , 58.Nm MGETHDR , 59.Nm MEXTMALLOC , 60.Nm MEXTADD , 61.Nm MCLGET , 62.Nm M_COPY_PKTHDR , 63.Nm M_MOVE_PKTHDR , 64.Nm M_ALIGN , 65.Nm MH_ALIGN , 66.Nm M_LEADINGSPACE , 67.Nm M_TRAILINGSPACE , 68.Nm M_PREPEND , 69.Nm MCHTYPE 70.Nd "functions and macros for managing memory used by networking code" 71.Sh SYNOPSIS 72.In sys/mbuf.h 73.Ft struct mbuf * 74.Fn m_get "int nowait" "int type" 75.Ft struct mbuf * 76.Fn m_getclr "int nowait" "int type" 77.Ft struct mbuf * 78.Fn m_gethdr "int nowait" "int type" 79.Ft struct mbuf * 80.Fn m_devget "char *buf" "int totlen" "int off0" "struct ifnet *ifp" "void (*copy)(const void *, void *, size_t)" 81.Ft struct mbuf * 82.Fn m_copym "struct mbuf *m" "int off0" "int len" "int wait" 83.Ft struct mbuf * 84.Fn m_copypacket "struct mbuf *m" "int how" 85.Ft void 86.Fn m_copydata "struct mbuf *m" "int off" "int len" "void *cp" 87.Ft void 88.Fn m_copyback "struct mbuf *m0" "int off" "int len" "void *cp" 89.Ft struct mbuf * 90.Fn m_copyback_cow "struct mbuf *m0" "int off" "int len" "void *cp" "int how" 91.Ft int 92.Fn m_makewritable "struct mbuf **mp" "int off" "int len" "int how" 93.Ft void 94.Fn m_cat "struct mbuf *m" "struct mbuf *n" 95.Ft struct mbuf * 96.Fn m_dup "struct mbuf *m" "int off0" "int len" "int wait" 97.Ft struct mbuf * 98.Fn m_prepend "struct mbuf *m" "int len" "int how" 99.Ft struct mbuf * 100.Fn m_pulldown "struct mbuf *m" "int off" "int len" "int *offp" 101.Ft struct mbuf * 102.Fn m_pullup "struct mbuf *n" "int len" 103.Ft struct mbuf * 104.Fn m_copyup "struct mbuf *m" "int len" "int dstoff" 105.Ft struct mbuf * 106.Fn m_split "struct mbuf *m0" "int len0" "int wait" 107.Ft void 108.Fn m_adj "struct mbuf *mp" "int req_len" 109.Ft int 110.Fn m_apply "struct mbuf *m" "int off" "int len" "int *f(void *, void *, unsigned int)" "void *arg" 111.Ft struct mbuf * 112.Fn m_free "struct mbuf *m" 113.Ft void 114.Fn m_freem "struct mbuf *m" 115.Ft datatype 116.Fn mtod "struct mbuf *m" "datatype" 117.Ft void 118.Fn MGET "struct mbuf *m" "int how" "int type" 119.Ft void 120.Fn MGETHDR "struct mbuf *m" "int how" "int type" 121.Ft void 122.Fn MEXTMALLOC "struct mbuf *m" "int len" "int how" 123.Ft void 124.Fn MEXTADD "struct mbuf *m" "void *buf" "int size" "int type" "void (*free)(struct mbuf *, void *, size_t, void *)" "void *arg" 125.Ft void 126.Fn MCLGET "struct mbuf *m" "int how" 127.Ft void 128.Fn M_COPY_PKTHDR "struct mbuf *to" "struct mbuf *from" 129.Ft void 130.Fn M_MOVE_PKTHDR "struct mbuf *to" "struct mbuf *from" 131.Ft void 132.Fn M_ALIGN "struct mbuf *m" "int len" 133.Ft void 134.Fn MH_ALIGN "struct mbuf *m" "int len" 135.Ft int 136.Fn M_LEADINGSPACE "struct mbuf *m" 137.Ft int 138.Fn M_TRAILINGSPACE "struct mbuf *m" 139.Ft void 140.Fn M_PREPEND "struct mbuf *m" "int plen" "int how" 141.Ft void 142.Fn MCHTYPE "struct mbuf *m" "int type" 143.Sh DESCRIPTION 144The 145.Nm 146functions and macros provide an easy and consistent way to handle 147a networking stack's memory management needs. 148An 149.Nm 150consists of a header and a data area. 151It is of a fixed size, 152.Dv MSIZE 153.Pq defined in Aq Pa machine/param.h , 154which includes overhead. 155The header contains a pointer to the next 156.Nm 157in the 158.Sq "mbuf chain" , 159a pointer to the next 160.Sq "mbuf chain" , 161a pointer to the data area, the amount of data in this mbuf, its type 162and a 163.Dv flags 164field. 165.Pp 166The 167.Dv type 168variable can signify: 169.Bl -tag -compact -offset indent -width "XXXXXXXXXXX" 170.It Dv MT_FREE 171the mbuf should be on the ``free'' list 172.It Dv MT_DATA 173data was dynamically allocated 174.It Dv MT_HEADER 175data is a packet header 176.It Dv MT_SONAME 177data is a socket name 178.It Dv MT_SOOPTS 179data is socket options 180.It Dv MT_FTABLE 181data is the fragment reassembly header 182.It Dv MT_CONTROL 183mbuf contains ancillary \&(protocol control\&) data 184.It Dv MT_OOBDATA 185mbuf contains out-of-band data. 186.El 187.Pp 188The 189.Dv flags 190variable contains information describing the 191.Nm , 192notably: 193.Bl -tag -compact -offset indent -width "XXXXXXXXXXX" 194.It Dv M_EXT 195has external storage 196.It Dv M_PKTHDR 197is start of record 198.It Dv M_EOR 199is end of record 200.It Dv M_CLUSTER 201external storage is a cluster. 202.El 203.Pp 204If an 205.Nm 206designates the start of a record 207.Pq Dv M_PKTHDR , 208its 209.Dv flags 210field may contain additional information describing the content of 211the record: 212.Bl -tag -compact -offset indent -width "XXXXXXXXXXX" 213.It Dv M_BCAST 214sent/received as link-level broadcast 215.It Dv M_MCAST 216sent/received as link-level multicast 217.It Dv M_LINK0 , 218.It Dv M_LINK1 , 219.It Dv M_LINK2 220three link-level specific flags. 221.El 222.Pp 223An 224.Nm 225may add a single 226.Sq "mbuf cluster" 227of 228.Dv MCLBYTES 229bytes 230.Pq also defined in Aq Pa machine/param.h , 231which has no additional overhead 232and is used instead of the internal data area; this is done when at least 233.Dv MINCLSIZE 234bytes of data must be stored. 235.Pp 236When the 237.Dv M_EXT 238flag is raised for an mbuf, 239the external storage area could be shared among multiple mbufs. 240Be careful when you attempt to overwrite the data content of the mbuf. 241.Bl -tag -width compact 242.It Fn m_get "int nowait" "int type" 243Allocates an mbuf and initializes it to contain internal data. 244The 245.Fa nowait 246parameter is a choice of 247.Dv M_WAIT / M_DONTWAIT 248from caller. 249.Dv M_WAIT 250means the call cannot fail, but may take forever. 251The 252.Fa type 253parameter is an mbuf type. 254.It Fn m_getclr "int nowait" "int type" 255Allocates an mbuf and initializes it to contain internal data, then 256zeros the data area. 257The 258.Fa nowait 259parameter is a choice of 260.Dv M_WAIT / M_DONTWAIT 261from caller. 262The 263.Fa type 264parameter is an mbuf type. 265.It Fn m_gethdr "int nowait" "int type" 266Allocates an mbuf and initializes it to contain a packet header and internal 267data. 268The 269.Fa nowait 270parameter is a choice of 271.Dv M_WAIT / M_DONTWAIT 272from caller. 273The 274.Fa type 275parameter is an mbuf type. 276.It Fn m_devget "char *buf" "int totlen" "int off0" "struct ifnet *ifp" "void (*copy)(const void *, void *, size_t)" 277Copies 278.Fa len 279bytes from device local memory into mbufs using copy routine 280.Fa copy . 281If parameter 282.Fa off 283is non-zero, the packet is supposed to be trailer-encapsulated and 284.Fa off 285bytes plus the type and length fields will be skipped before copying. 286Returns the top of the mbuf chain it created. 287.It Fn m_copym "struct mbuf *m" "int off0" "int len" "int wait" 288Creates a copy of an mbuf chain starting 289.Fa off0 290bytes from the beginning, continuing for 291.Fa len 292bytes. 293If the 294.Fa len 295requested is 296.Dv M_COPYALL , 297the complete mbuf chain will be copied. 298The 299.Fa wait 300parameter is a choice of 301.Dv M_WAIT / M_DONTWAIT 302from caller. 303.It Fn m_copypacket "struct mbuf *m" "int how" 304Copies an entire packet, including header (which must be present). 305This function is an optimization of the common case 306.Li m_copym ( m , 0 , Dv M_COPYALL , Fa how ) . 307.It Fn m_copydata "struct mbuf *m" "int off" "int len" "void *cp" 308Copies 309.Fa len 310bytes data from mbuf chain 311.Fa m 312into the buffer 313.Fa cp , 314starting 315.Fa off 316bytes from the beginning. 317.It Fn m_copyback "struct mbuf *m0" "int off" "int len" "void *cp" 318Copies 319.Fa len 320bytes data from buffer 321.Fa cp 322back into the mbuf chain 323.Fa m0 , 324starting 325.Fa off 326bytes from the beginning of the chain, extending the mbuf chain if necessary. 327.Fn m_copyback 328can only fail when extending the chain. 329The caller should check for this kind of failure 330by checking the resulting length of the chain in that case. 331It is an error to use 332.Fn m_copyback 333on read-only mbufs. 334.It Fn m_copyback_cow "struct mbuf *m0" "int off" "int len" "void *cp" \ 335"int how" 336Copies 337.Fa len 338bytes data from buffer 339.Fa cp 340back into the mbuf chain 341.Fa m0 342as 343.Fn m_copyback 344does. 345Unlike 346.Fn m_copyback , 347it is safe to use 348.Fn m_copyback_cow 349on read-only mbufs. 350If needed, 351.Fn m_copyback_cow 352automatically allocates new mbufs and adjusts the chain. 353On success, it returns a pointer to the resulting mbuf chain, 354and frees the original mbuf 355.Fa m0 . 356Otherwise, it returns 357.Dv NULL . 358The 359.Fa how 360parameter is a choice of 361.Dv M_WAIT / M_DONTWAIT 362from the caller. 363Unlike 364.Fn m_copyback , 365extending the mbuf chain isn't supported. 366It is an error to attempt to extend the mbuf chain using 367.Fn m_copyback_cow . 368.It Fn m_makewritable "struct mbuf **mp" "int off" "int len" "int how" 369Rearranges an mbuf chain so that 370.Fa len 371bytes from offset 372.Fa off 373are writable. 374When it meets read-only mbufs, it allocates new mbufs, adjusts the chain as 375.Fn m_copyback_cow 376does, and copies the original content into them. 377.Fn m_makewritable 378does 379.Em not 380guarantee that all 381.Fa len 382bytes at 383.Fa off 384are consecutive. 385The 386.Fa how 387parameter is a choice of 388.Dv M_WAIT / M_DONTWAIT 389from the caller. 390.Fn m_makewritable 391preserves the contents of the mbuf chain even in the case of failure. 392It updates a pointer to the mbuf chain pointed to by 393.Fa mp . 394It returns 0 on success. 395Otherwise, it returns an error code, typically 396.Er ENOBUFS . 397.It Fn m_cat "struct mbuf *m" "struct mbuf *n" 398Concatenates mbuf chain 399.Fa n 400to 401.Fa m . 402Both chains must be of the same type; packet headers will 403.Em not 404be updated if present. 405.It Fn m_dup "struct mbuf *m" "int off0" "int len" "int wait" 406Similarly to 407.Fn m_copym , 408the function creates a copy of an mbuf chain starting 409.Fa off0 410bytes from the beginning, continuing for 411.Fa len 412bytes. 413While 414.Fn m_copym 415tries to share external storage for mbufs with 416.Dv M_EXT 417flag, 418.Fn m_dup 419will deep-copy the whole data content into new mbuf chain 420and avoids shared external storage. 421.It Fn m_prepend "struct mbuf *m" "int len" "int how" 422Lesser-used path for 423.Fn M_PREPEND : 424allocates new mbuf 425.Fa m 426of size 427.Fa len 428to prepend to the chain, copying junk along. 429The 430.Fa how 431parameter is a choice of 432.Dv M_WAIT / M_DONTWAIT 433from caller. 434.It Fn m_pulldown "struct mbuf *m" "int off" "int len" "int *offp" 435Rearranges an mbuf chain so that 436.Fa len 437bytes from offset 438.Fa off 439are contiguous and in the data area of an mbuf. 440The return value points to an mbuf in the middle of the mbuf chain 441.Fa m . 442If we call the return value 443.Fa n , 444the contiguous data region is available at 445.Li "mtod(n, void *) + *offp" , 446or 447.Li "mtod(n, void *)" 448if 449.Fa offp 450is 451.Dv NULL . 452The top of the mbuf chain 453.Fa m , 454and mbufs up to 455.Fa off , 456will not be modified. 457On successful return, it is guaranteed that the mbuf pointed to by 458.Fa n 459does not have a shared external storage, 460therefore it is safe to update the contiguous region. 461Returns 462.Dv NULL 463and frees the mbuf chain on failure. 464.Fa len 465must be smaller or equal than 466.Dv MCLBYTES . 467.It Fn m_pullup "struct mbuf *m" "int len" 468Rearranges an mbuf chain so that 469.Fa len 470bytes are contiguous 471and in the data area of an mbuf (so that 472.Fn mtod 473will work for a structure of size 474.Fa len ) . 475Returns the resulting 476mbuf chain on success, frees it and returns 477.Dv NULL 478on failure. 479If there is room, it will add up to 480.Dv max_protohdr 481- 482.Fa len 483extra bytes to the 484contiguous region to possibly avoid being called again. 485.Fa len 486must be smaller or equal than 487.Dv MHLEN . 488.It Fn m_copyup "struct mbuf *m" "int len" "int dstoff" 489Similar to 490.Fn m_pullup 491but copies 492.Fa len 493bytes of data into a new mbuf at 494.Fa dstoff 495bytes into the mbuf. 496The 497.Fa dstoff 498argument aligns the data and leaves room for a link layer header. 499Returns the new 500mbuf chain on success, and frees the mbuf chain and returns 501.Dv NULL 502on failure. 503Note that 504the function does not allocate mbuf clusters, so 505.Fa len + dstoff 506must be less than 507.Dv MHLEN . 508.It Fn m_split "struct mbuf *m0" "int len0" "int wait" 509Partitions an mbuf chain in two pieces, returning the tail, 510which is all but the first 511.Fa len0 512bytes. 513In case of failure, it returns 514.Dv NULL 515and attempts to 516restore the chain to its original state. 517.It Fn m_adj "struct mbuf *mp" "int req_len" 518Shaves off 519.Fa req_len 520bytes from head or tail of the (valid) data area. 521If 522.Fa req_len 523is greater than zero, front bytes are being shaved off, if it's smaller, 524from the back (and if it is zero, the mbuf will stay bearded). 525This function does not move data in any way, but is used to manipulate the 526data area pointer and data length variable of the mbuf in a non-clobbering 527way. 528.It Fn m_apply "struct mbuf *m" "int off" "int len" "int (*f)(void *, void *, unsigned int)" "void *arg" 529Apply function 530.Fa f 531to the data in an mbuf chain starting 532.Fa off 533bytes from the beginning, continuing for 534.Fa len 535bytes. 536Neither 537.Fa off 538nor 539.Fa len 540may be negative. 541.Fa arg 542will be supplied as first argument for 543.Fa f , 544the second argument will be the pointer to the data buffer of a 545packet (starting after 546.Fa off 547bytes in the stream), and the third argument is the amount 548of data in bytes in this call. 549If 550.Fa f 551returns something not equal to zero 552.Fn m_apply 553will bail out, returning the return code of 554.Fa f . 555Upon successful completion it will return zero. 556.It Fn m_free "struct mbuf *m" 557Frees mbuf 558.Fa m . 559.It Fn m_freem "struct mbuf *m" 560Frees the mbuf chain beginning with 561.Fa m . 562This function contains the elementary sanity check for a 563.Dv NULL 564pointer. 565.It Fn mtod "struct mbuf *m" "datatype" 566Returns a pointer to the data contained in the specified mbuf 567.Fa m , 568type-casted to the specified data type 569.Fa datatype . 570Implemented as a macro. 571.It Fn MGET "struct mbuf *m" "int how" "int type" 572Allocates mbuf 573.Fa m 574and initializes it to contain internal data. 575See 576.Fn m_get . 577Implemented as a macro. 578.It Fn MGETHDR "struct mbuf *m" "int how" "int type" 579Allocates mbuf 580.Fa m 581and initializes it to contain a packet header. 582See 583.Fn m_gethdr . 584Implemented as a macro. 585.It Fn MEXTMALLOC "struct mbuf *m" "int len" "int how" 586Allocates external storage of size 587.Fa len 588for mbuf 589.Fa m . 590The 591.Fa how 592parameter is a choice of 593.Dv M_WAIT / M_DONTWAIT 594from caller. 595The flag 596.Dv M_EXT 597is set upon success. 598Implemented as a macro. 599.It Fn MEXTADD "struct mbuf *m" "void *buf" "int size" "int type" "void (*free)(struct mbuf *, void *, size_t, void *)" "void *arg" 600Adds pre-allocated external storage 601.Fa buf 602to a normal mbuf 603.Fa m ; 604the parameters 605.Fa size , 606.Fa type , 607.Fa free 608and 609.Fa arg 610describe the external storage. 611.Fa size 612is the size of the storage, 613.Fa type 614describes its 615.Xr malloc 9 616type, 617.Fa free 618is a free routine (if not the usual one), and 619.Fa arg 620is a possible argument to the free routine. 621The flag 622.Dv M_EXT 623is set upon success. 624Implemented as a macro. 625If a free routine is specified, it will be called when the mbuf is freed. 626In the case of former, the first argument for a free routine is the mbuf 627.Fa m 628and the routine is expected to free it in addition to the external storage 629pointed by second argument. 630In the case of latter, the first argument for the routine is NULL. 631.It Fn MCLGET "struct mbuf *m" "int how" 632Allocates and adds an mbuf cluster to a normal mbuf 633.Fa m . 634The 635.Fa how 636parameter is a choice of 637.Dv M_WAIT / M_DONTWAIT 638from caller. 639The flag 640.Dv M_EXT 641is set upon success. 642Implemented as a macro. 643.It Fn M_COPY_PKTHDR "struct mbuf *to" "struct mbuf *from" 644Copies the mbuf pkthdr from mbuf 645.Fa from 646to mbuf 647.Fa to . 648.Fa from 649must have the type flag 650.Dv M_PKTHDR 651set, and 652.Fa to 653must be empty. 654Implemented as a macro. 655.It Fn M_MOVE_PKTHDR "struct mbuf *to" "struct mbuf *from" 656Moves the mbuf pkthdr from mbuf 657.Fa from 658to mbuf 659.Fa to . 660.Fa from 661must have the type flag 662.Dv M_PKTHDR 663set, and 664.Fa to 665must be empty. 666The flag 667.Dv M_PKTHDR 668in mbuf 669.Fa from 670will be cleared. 671.It Fn M_ALIGN "struct mbuf *m" "int len" 672Sets the data pointer of a newly allocated mbuf 673.Fa m 674to 675.Fa len 676bytes from the end of the mbuf data area, so that 677.Fa len 678bytes of data written to the mbuf 679.Fa m , 680starting at the data pointer, will be aligned to the end of the data area. 681Implemented as a macro. 682.It Fn MH_ALIGN "struct mbuf *m" "int len" 683Sets the data pointer of a newly allocated packetheader mbuf 684.Fa m 685to 686.Fa len 687bytes from the end of the mbuf data area, so that 688.Fa len 689bytes of data written to the mbuf 690.Fa m , 691starting at the data pointer, will be aligned to the end of the data area. 692Implemented as a macro. 693.It Fn M_LEADINGSPACE "struct mbuf *m" 694Returns the amount of space available before the current start of valid 695data in mbuf 696.Fa m . 697Returns 0 if the mbuf data part is shared across multiple mbufs 698.Pq i.e. not writable . 699Implemented as a macro. 700.It Fn M_TRAILINGSPACE "struct mbuf *m" 701Returns the amount of space available after the current end of valid 702data in mbuf 703.Fa m . 704Returns 0 if the mbuf data part is shared across multiple mbufs 705.Pq i.e. not writable . 706Implemented as a macro. 707.It Fn M_PREPEND "struct mbuf *m" "int plen" "int how" 708Prepends space of size 709.Fa plen 710to mbuf 711.Fa m . 712If a new mbuf must be allocated, 713.Fa how 714specifies whether to wait. 715If 716.Fa how 717is 718.Dv M_DONTWAIT 719and allocation fails, the original mbuf chain is freed and 720.Fa m 721is set to 722.Dv NULL . 723Implemented as a macro. 724.It Fn MCHTYPE "struct mbuf *m" "int type" 725Change mbuf 726.Fa m 727to new type 728.Fa type . 729Implemented as a macro. 730.El 731.Sh CODE REFERENCES 732The 733.Nm 734management functions are implemented within the file 735.Pa sys/kern/uipc_mbuf.c . 736Function prototypes, and the functions implemented as macros 737are located in 738.Pa sys/sys/mbuf.h . 739.Sh SEE ALSO 740.Pa /usr/share/doc/smm/18.net , 741.Xr netstat 1 , 742.Xr m_tag 9 , 743.Xr malloc 9 744.Rs 745.%A Jun-ichiro Hagino 746.%T "Mbuf issues in 4.4BSD IPv6/IPsec support (experiences from KAME IPv6/IPsec implementation)" 747.%B "Proceedings of the freenix track: 2000 USENIX annual technical conference" 748.%D June 2000 749.Re 750.Sh AUTHORS 751.An -nosplit 752The original mbuf data structures were designed by Rob Gurwitz 753when he did the initial TCP/IP implementation at BBN. 754.Pp 755Further extensions and enhancements were made by Bill Joy, Sam Leffler, 756and Mike Karels at CSRG. 757.Pp 758Current implementation of external storage by 759.An Matt Thomas 760.Aq matt@3am-software.com 761and 762.An Jason R. Thorpe 763.Aq thorpej@NetBSD.org . 764