| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589 |
- /*-
- * Copyright (c) 1982, 1986, 1988, 1993
- * The Regents of the University of California.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- */
- /*
- * __Userspace__ version of /usr/src/sys/kern/kern_mbuf.c
- * We are initializing two zones for Mbufs and Clusters.
- *
- */
- #include <stdio.h>
- #include <string.h>
- /* #include <sys/param.h> This defines MSIZE 256 */
- #if !defined(SCTP_SIMPLE_ALLOCATOR)
- #include "umem.h"
- #endif
- #include "user_mbuf.h"
- #include "user_environment.h"
- #include "user_atomic.h"
- #include "netinet/sctp_pcb.h"
- #define KIPC_MAX_LINKHDR 4 /* int: max length of link header (see sys/sysclt.h) */
- #define KIPC_MAX_PROTOHDR 5 /* int: max length of network header (see sys/sysclt.h)*/
- int max_linkhdr = KIPC_MAX_LINKHDR;
- int max_protohdr = KIPC_MAX_PROTOHDR; /* Size of largest protocol layer header. */
- /*
- * Zones from which we allocate.
- */
- sctp_zone_t zone_mbuf;
- sctp_zone_t zone_clust;
- sctp_zone_t zone_ext_refcnt;
- /* __Userspace__ clust_mb_args will be passed as callback data to mb_ctor_clust
- * and mb_dtor_clust.
- * Note: I had to use struct clust_args as an encapsulation for an mbuf pointer.
- * struct mbuf * clust_mb_args; does not work.
- */
- struct clust_args clust_mb_args;
- /* __Userspace__
- * Local prototypes.
- */
- static int mb_ctor_mbuf(void *, void *, int);
- static int mb_ctor_clust(void *, void *, int);
- static void mb_dtor_mbuf(void *, void *);
- static void mb_dtor_clust(void *, void *);
- /***************** Functions taken from user_mbuf.h *************/
- static int mbuf_constructor_dup(struct mbuf *m, int pkthdr, short type)
- {
- int flags = pkthdr;
- m->m_next = NULL;
- m->m_nextpkt = NULL;
- m->m_len = 0;
- m->m_flags = flags;
- m->m_type = type;
- if (flags & M_PKTHDR) {
- m->m_data = m->m_pktdat;
- m->m_pkthdr.rcvif = NULL;
- m->m_pkthdr.len = 0;
- m->m_pkthdr.header = NULL;
- m->m_pkthdr.csum_flags = 0;
- m->m_pkthdr.csum_data = 0;
- m->m_pkthdr.tso_segsz = 0;
- m->m_pkthdr.ether_vtag = 0;
- SLIST_INIT(&m->m_pkthdr.tags);
- } else
- m->m_data = m->m_dat;
- return (0);
- }
- /* __Userspace__ */
- struct mbuf *
- m_get(int how, short type)
- {
- struct mbuf *mret;
- #if defined(SCTP_SIMPLE_ALLOCATOR)
- struct mb_args mbuf_mb_args;
- /* The following setter function is not yet being enclosed within
- * #if USING_MBUF_CONSTRUCTOR - #endif, until I have thoroughly tested
- * mb_dtor_mbuf. See comment there
- */
- mbuf_mb_args.flags = 0;
- mbuf_mb_args.type = type;
- #endif
- /* Mbuf master zone, zone_mbuf, has already been
- * created in mbuf_initialize() */
- mret = SCTP_ZONE_GET(zone_mbuf, struct mbuf);
- #if defined(SCTP_SIMPLE_ALLOCATOR)
- mb_ctor_mbuf(mret, &mbuf_mb_args, 0);
- #endif
- /*mret = ((struct mbuf *)umem_cache_alloc(zone_mbuf, UMEM_DEFAULT));*/
- /* There are cases when an object available in the current CPU's
- * loaded magazine and in those cases the object's constructor is not applied.
- * If that is the case, then we are duplicating constructor initialization here,
- * so that the mbuf is properly constructed before returning it.
- */
- if (mret) {
- #if USING_MBUF_CONSTRUCTOR
- if (! (mret->m_type == type) ) {
- mbuf_constructor_dup(mret, 0, type);
- }
- #else
- mbuf_constructor_dup(mret, 0, type);
- #endif
- }
- return mret;
- }
- /* __Userspace__ */
- struct mbuf *
- m_gethdr(int how, short type)
- {
- struct mbuf *mret;
- #if defined(SCTP_SIMPLE_ALLOCATOR)
- struct mb_args mbuf_mb_args;
- /* The following setter function is not yet being enclosed within
- * #if USING_MBUF_CONSTRUCTOR - #endif, until I have thoroughly tested
- * mb_dtor_mbuf. See comment there
- */
- mbuf_mb_args.flags = M_PKTHDR;
- mbuf_mb_args.type = type;
- #endif
- mret = SCTP_ZONE_GET(zone_mbuf, struct mbuf);
- #if defined(SCTP_SIMPLE_ALLOCATOR)
- mb_ctor_mbuf(mret, &mbuf_mb_args, 0);
- #endif
- /*mret = ((struct mbuf *)umem_cache_alloc(zone_mbuf, UMEM_DEFAULT));*/
- /* There are cases when an object available in the current CPU's
- * loaded magazine and in those cases the object's constructor is not applied.
- * If that is the case, then we are duplicating constructor initialization here,
- * so that the mbuf is properly constructed before returning it.
- */
- if (mret) {
- #if USING_MBUF_CONSTRUCTOR
- if (! ((mret->m_flags & M_PKTHDR) && (mret->m_type == type)) ) {
- mbuf_constructor_dup(mret, M_PKTHDR, type);
- }
- #else
- mbuf_constructor_dup(mret, M_PKTHDR, type);
- #endif
- }
- return mret;
- }
- /* __Userspace__ */
- struct mbuf *
- m_free(struct mbuf *m)
- {
- struct mbuf *n = m->m_next;
- if (m->m_flags & M_EXT)
- mb_free_ext(m);
- else if ((m->m_flags & M_NOFREE) == 0) {
- #if defined(SCTP_SIMPLE_ALLOCATOR)
- mb_dtor_mbuf(m, NULL);
- #endif
- SCTP_ZONE_FREE(zone_mbuf, m);
- }
- /*umem_cache_free(zone_mbuf, m);*/
- return (n);
- }
- static void
- clust_constructor_dup(caddr_t m_clust, struct mbuf* m)
- {
- u_int *refcnt;
- int type, size;
- if (m == NULL) {
- return;
- }
- /* Assigning cluster of MCLBYTES. TODO: Add jumbo frame functionality */
- type = EXT_CLUSTER;
- size = MCLBYTES;
- refcnt = SCTP_ZONE_GET(zone_ext_refcnt, u_int);
- /*refcnt = (u_int *)umem_cache_alloc(zone_ext_refcnt, UMEM_DEFAULT);*/
- #if !defined(SCTP_SIMPLE_ALLOCATOR)
- if (refcnt == NULL) {
- umem_reap();
- refcnt = SCTP_ZONE_GET(zone_ext_refcnt, u_int);
- /*refcnt = (u_int *)umem_cache_alloc(zone_ext_refcnt, UMEM_DEFAULT);*/
- }
- #endif
- *refcnt = 1;
- m->m_ext.ext_buf = (caddr_t)m_clust;
- m->m_data = m->m_ext.ext_buf;
- m->m_flags |= M_EXT;
- m->m_ext.ext_free = NULL;
- m->m_ext.ext_args = NULL;
- m->m_ext.ext_size = size;
- m->m_ext.ext_type = type;
- m->m_ext.ref_cnt = refcnt;
- return;
- }
- /* __Userspace__ */
- void
- m_clget(struct mbuf *m, int how)
- {
- caddr_t mclust_ret;
- #if defined(SCTP_SIMPLE_ALLOCATOR)
- struct clust_args clust_mb_args_l;
- #endif
- if (m->m_flags & M_EXT) {
- SCTPDBG(SCTP_DEBUG_USR, "%s: %p mbuf already has cluster\n", __func__, (void *)m);
- }
- m->m_ext.ext_buf = (char *)NULL;
- #if defined(SCTP_SIMPLE_ALLOCATOR)
- clust_mb_args_l.parent_mbuf = m;
- #endif
- mclust_ret = SCTP_ZONE_GET(zone_clust, char);
- #if defined(SCTP_SIMPLE_ALLOCATOR)
- mb_ctor_clust(mclust_ret, &clust_mb_args_l, 0);
- #endif
- /*mclust_ret = umem_cache_alloc(zone_clust, UMEM_DEFAULT);*/
- /*
- On a cluster allocation failure, call umem_reap() and retry.
- */
- if (mclust_ret == NULL) {
- #if !defined(SCTP_SIMPLE_ALLOCATOR)
- /* mclust_ret = SCTP_ZONE_GET(zone_clust, char);
- mb_ctor_clust(mclust_ret, &clust_mb_args, 0);
- #else*/
- umem_reap();
- mclust_ret = SCTP_ZONE_GET(zone_clust, char);
- #endif
- /*mclust_ret = umem_cache_alloc(zone_clust, UMEM_DEFAULT);*/
- /* if (NULL == mclust_ret) { */
- SCTPDBG(SCTP_DEBUG_USR, "Memory allocation failure in %s\n", __func__);
- /* } */
- }
- #if USING_MBUF_CONSTRUCTOR
- if ((m->m_ext.ext_buf == NULL)) {
- clust_constructor_dup(mclust_ret, m);
- }
- #else
- clust_constructor_dup(mclust_ret, m);
- #endif
- }
- struct mbuf *
- m_getm2(struct mbuf *m, int len, int how, short type, int flags, int allonebuf)
- {
- struct mbuf *mb, *nm = NULL, *mtail = NULL;
- int size, mbuf_threshold, space_needed = len;
- KASSERT(len >= 0, ("%s: len is < 0", __func__));
- /* Validate flags. */
- flags &= (M_PKTHDR | M_EOR);
- /* Packet header mbuf must be first in chain. */
- if ((flags & M_PKTHDR) && m != NULL) {
- flags &= ~M_PKTHDR;
- }
- if (allonebuf == 0)
- mbuf_threshold = SCTP_BASE_SYSCTL(sctp_mbuf_threshold_count);
- else
- mbuf_threshold = 1;
- /* Loop and append maximum sized mbufs to the chain tail. */
- while (len > 0) {
- if ((!allonebuf && len >= MCLBYTES) || (len > (int)(((mbuf_threshold - 1) * MLEN) + MHLEN))) {
- mb = m_gethdr(how, type);
- MCLGET(mb, how);
- size = MCLBYTES;
- /* SCTP_BUF_LEN(mb) = MCLBYTES; */
- } else if (flags & M_PKTHDR) {
- mb = m_gethdr(how, type);
- if (len < MHLEN) {
- size = len;
- } else {
- size = MHLEN;
- }
- } else {
- mb = m_get(how, type);
- if (len < MLEN) {
- size = len;
- } else {
- size = MLEN;
- }
- }
- /* Fail the whole operation if one mbuf can't be allocated. */
- if (mb == NULL) {
- if (nm != NULL)
- m_freem(nm);
- return (NULL);
- }
- if (allonebuf != 0 && size < space_needed) {
- m_freem(mb);
- return (NULL);
- }
- /* Book keeping. */
- len -= size;
- if (mtail != NULL)
- mtail->m_next = mb;
- else
- nm = mb;
- mtail = mb;
- flags &= ~M_PKTHDR; /* Only valid on the first mbuf. */
- }
- if (flags & M_EOR) {
- mtail->m_flags |= M_EOR; /* Only valid on the last mbuf. */
- }
- /* If mbuf was supplied, append new chain to the end of it. */
- if (m != NULL) {
- for (mtail = m; mtail->m_next != NULL; mtail = mtail->m_next);
- mtail->m_next = nm;
- mtail->m_flags &= ~M_EOR;
- } else {
- m = nm;
- }
- return (m);
- }
- /*
- * Copy the contents of uio into a properly sized mbuf chain.
- */
- struct mbuf *
- m_uiotombuf(struct uio *uio, int how, int len, int align, int flags)
- {
- struct mbuf *m, *mb;
- int error, length;
- ssize_t total;
- int progress = 0;
- /*
- * len can be zero or an arbitrary large value bound by
- * the total data supplied by the uio.
- */
- if (len > 0)
- total = min(uio->uio_resid, len);
- else
- total = uio->uio_resid;
- /*
- * The smallest unit returned by m_getm2() is a single mbuf
- * with pkthdr. We can't align past it.
- */
- if (align >= MHLEN)
- return (NULL);
- /*
- * Give us the full allocation or nothing.
- * If len is zero return the smallest empty mbuf.
- */
- m = m_getm2(NULL, (int)max(total + align, 1), how, MT_DATA, flags, 0);
- if (m == NULL)
- return (NULL);
- m->m_data += align;
- /* Fill all mbufs with uio data and update header information. */
- for (mb = m; mb != NULL; mb = mb->m_next) {
- length = (int)min(M_TRAILINGSPACE(mb), total - progress);
- error = uiomove(mtod(mb, void *), length, uio);
- if (error) {
- m_freem(m);
- return (NULL);
- }
- mb->m_len = length;
- progress += length;
- if (flags & M_PKTHDR)
- m->m_pkthdr.len += length;
- }
- KASSERT(progress == total, ("%s: progress != total", __func__));
- return (m);
- }
- u_int
- m_length(struct mbuf *m0, struct mbuf **last)
- {
- struct mbuf *m;
- u_int len;
- len = 0;
- for (m = m0; m != NULL; m = m->m_next) {
- len += m->m_len;
- if (m->m_next == NULL)
- break;
- }
- if (last != NULL)
- *last = m;
- return (len);
- }
- struct mbuf *
- m_last(struct mbuf *m)
- {
- while (m->m_next) {
- m = m->m_next;
- }
- return (m);
- }
- /*
- * Unlink a tag from the list of tags associated with an mbuf.
- */
- static __inline void
- m_tag_unlink(struct mbuf *m, struct m_tag *t)
- {
- SLIST_REMOVE(&m->m_pkthdr.tags, t, m_tag, m_tag_link);
- }
- /*
- * Reclaim resources associated with a tag.
- */
- static __inline void
- m_tag_free(struct m_tag *t)
- {
- (*t->m_tag_free)(t);
- }
- /*
- * Set up the contents of a tag. Note that this does not fill in the free
- * method; the caller is expected to do that.
- *
- * XXX probably should be called m_tag_init, but that was already taken.
- */
- static __inline void
- m_tag_setup(struct m_tag *t, uint32_t cookie, int type, int len)
- {
- t->m_tag_id = type;
- t->m_tag_len = len;
- t->m_tag_cookie = cookie;
- }
- /************ End functions from user_mbuf.h ******************/
- /************ End functions to substitute umem_cache_alloc and umem_cache_free **************/
- void
- mbuf_initialize(void *dummy)
- {
- /*
- * __Userspace__Configure UMA zones for Mbufs and Clusters.
- * (TODO: m_getcl() - using packet secondary zone).
- * There is no provision for trash_init and trash_fini in umem.
- *
- */
- /* zone_mbuf = umem_cache_create(MBUF_MEM_NAME, MSIZE, 0,
- mb_ctor_mbuf, mb_dtor_mbuf, NULL,
- &mbuf_mb_args,
- NULL, 0);
- zone_mbuf = umem_cache_create(MBUF_MEM_NAME, MSIZE, 0, NULL, NULL, NULL, NULL, NULL, 0);*/
- #if defined(SCTP_SIMPLE_ALLOCATOR)
- SCTP_ZONE_INIT(zone_mbuf, MBUF_MEM_NAME, MSIZE, 0);
- #else
- zone_mbuf = umem_cache_create(MBUF_MEM_NAME, MSIZE, 0,
- mb_ctor_mbuf, mb_dtor_mbuf, NULL,
- NULL,
- NULL, 0);
- #endif
- /*zone_ext_refcnt = umem_cache_create(MBUF_EXTREFCNT_MEM_NAME, sizeof(u_int), 0,
- NULL, NULL, NULL,
- NULL,
- NULL, 0);*/
- SCTP_ZONE_INIT(zone_ext_refcnt, MBUF_EXTREFCNT_MEM_NAME, sizeof(u_int), 0);
- /*zone_clust = umem_cache_create(MBUF_CLUSTER_MEM_NAME, MCLBYTES, 0,
- mb_ctor_clust, mb_dtor_clust, NULL,
- &clust_mb_args,
- NULL, 0);
- zone_clust = umem_cache_create(MBUF_CLUSTER_MEM_NAME, MCLBYTES, 0, NULL, NULL, NULL, NULL, NULL,0);*/
- #if defined(SCTP_SIMPLE_ALLOCATOR)
- SCTP_ZONE_INIT(zone_clust, MBUF_CLUSTER_MEM_NAME, MCLBYTES, 0);
- #else
- zone_clust = umem_cache_create(MBUF_CLUSTER_MEM_NAME, MCLBYTES, 0,
- mb_ctor_clust, mb_dtor_clust, NULL,
- &clust_mb_args,
- NULL, 0);
- #endif
- /* uma_prealloc() goes here... */
- /* __Userspace__ Add umem_reap here for low memory situation?
- *
- */
- }
- /*
- * __Userspace__
- *
- * Constructor for Mbuf master zone. We have a different constructor
- * for allocating the cluster.
- *
- * The 'arg' pointer points to a mb_args structure which
- * contains call-specific information required to support the
- * mbuf allocation API. See user_mbuf.h.
- *
- * The flgs parameter below can be UMEM_DEFAULT or UMEM_NOFAIL depending on what
- * was passed when umem_cache_alloc was called.
- * TODO: Use UMEM_NOFAIL in umem_cache_alloc and also define a failure handler
- * and call umem_nofail_callback(my_failure_handler) in the stack initialization routines
- * The advantage of using UMEM_NOFAIL is that we don't have to check if umem_cache_alloc
- * was successful or not. The failure handler would take care of it, if we use the UMEM_NOFAIL
- * flag.
- *
- * NOTE Ref: http://docs.sun.com/app/docs/doc/819-2243/6n4i099p2?l=en&a=view&q=umem_zalloc)
- * The umem_nofail_callback() function sets the **process-wide** UMEM_NOFAIL callback.
- * It also mentions that umem_nofail_callback is Evolving.
- *
- */
- static int
- mb_ctor_mbuf(void *mem, void *arg, int flgs)
- {
- #if USING_MBUF_CONSTRUCTOR
- struct mbuf *m;
- struct mb_args *args;
- int flags;
- short type;
- m = (struct mbuf *)mem;
- args = (struct mb_args *)arg;
- flags = args->flags;
- type = args->type;
- m->m_next = NULL;
- m->m_nextpkt = NULL;
- m->m_len = 0;
- m->m_flags = flags;
- m->m_type = type;
- if (flags & M_PKTHDR) {
- m->m_data = m->m_pktdat;
- m->m_pkthdr.rcvif = NULL;
- m->m_pkthdr.len = 0;
- m->m_pkthdr.header = NULL;
- m->m_pkthdr.csum_flags = 0;
- m->m_pkthdr.csum_data = 0;
- m->m_pkthdr.tso_segsz = 0;
- m->m_pkthdr.ether_vtag = 0;
- SLIST_INIT(&m->m_pkthdr.tags);
- } else
- m->m_data = m->m_dat;
- #endif
- return (0);
- }
- /*
- * __Userspace__
- * The Mbuf master zone destructor.
- * This would be called in response to umem_cache_destroy
- * TODO: Recheck if this is what we want to do in this destructor.
- * (Note: the number of times mb_dtor_mbuf is called is equal to the
- * number of individual mbufs allocated from zone_mbuf.
- */
- static void
- mb_dtor_mbuf(void *mem, void *arg)
- {
- struct mbuf *m;
- m = (struct mbuf *)mem;
- if ((m->m_flags & M_PKTHDR) != 0) {
- m_tag_delete_chain(m, NULL);
- }
- }
- /* __Userspace__
- * The Cluster zone constructor.
- *
- * Here the 'arg' pointer points to the Mbuf which we
- * are configuring cluster storage for. If 'arg' is
- * empty we allocate just the cluster without setting
- * the mbuf to it. See mbuf.h.
- */
- static int
- mb_ctor_clust(void *mem, void *arg, int flgs)
- {
- #if USING_MBUF_CONSTRUCTOR
- struct mbuf *m;
- struct clust_args * cla;
- u_int *refcnt;
- int type, size;
- sctp_zone_t zone;
- /* Assigning cluster of MCLBYTES. TODO: Add jumbo frame functionality */
- type = EXT_CLUSTER;
- zone = zone_clust;
- size = MCLBYTES;
- cla = (struct clust_args *)arg;
- m = cla->parent_mbuf;
- refcnt = SCTP_ZONE_GET(zone_ext_refcnt, u_int);
- /*refcnt = (u_int *)umem_cache_alloc(zone_ext_refcnt, UMEM_DEFAULT);*/
- *refcnt = 1;
- if (m != NULL) {
- m->m_ext.ext_buf = (caddr_t)mem;
- m->m_data = m->m_ext.ext_buf;
- m->m_flags |= M_EXT;
- m->m_ext.ext_free = NULL;
- m->m_ext.ext_args = NULL;
- m->m_ext.ext_size = size;
- m->m_ext.ext_type = type;
- m->m_ext.ref_cnt = refcnt;
- }
- #endif
- return (0);
- }
- /* __Userspace__ */
- static void
- mb_dtor_clust(void *mem, void *arg)
- {
- /* mem is of type caddr_t. In sys/types.h we have typedef char * caddr_t; */
- /* mb_dtor_clust is called at time of umem_cache_destroy() (the number of times
- * mb_dtor_clust is called is equal to the number of individual mbufs allocated
- * from zone_clust. Similarly for mb_dtor_mbuf).
- * At this point the following:
- * struct mbuf *m;
- * m = (struct mbuf *)arg;
- * assert (*(m->m_ext.ref_cnt) == 0); is not meaningful since m->m_ext.ref_cnt = NULL;
- * has been done in mb_free_ext().
- */
- }
- /* Unlink and free a packet tag. */
- void
- m_tag_delete(struct mbuf *m, struct m_tag *t)
- {
- KASSERT(m && t, ("m_tag_delete: null argument, m %p t %p", (void *)m, (void *)t));
- m_tag_unlink(m, t);
- m_tag_free(t);
- }
- /* Unlink and free a packet tag chain, starting from given tag. */
- void
- m_tag_delete_chain(struct mbuf *m, struct m_tag *t)
- {
- struct m_tag *p, *q;
- KASSERT(m, ("m_tag_delete_chain: null mbuf"));
- if (t != NULL)
- p = t;
- else
- p = SLIST_FIRST(&m->m_pkthdr.tags);
- if (p == NULL)
- return;
- while ((q = SLIST_NEXT(p, m_tag_link)) != NULL)
- m_tag_delete(m, q);
- m_tag_delete(m, p);
- }
- #if 0
- static void
- sctp_print_mbuf_chain(struct mbuf *m)
- {
- SCTP_DEBUG_USR(SCTP_DEBUG_USR, "Printing mbuf chain %p.\n", (void *)m);
- for(; m; m=m->m_next) {
- SCTP_DEBUG_USR(SCTP_DEBUG_USR, "%p: m_len = %ld, m_type = %x, m_next = %p.\n", (void *)m, m->m_len, m->m_type, (void *)m->m_next);
- if (m->m_flags & M_EXT)
- SCTP_DEBUG_USR(SCTP_DEBUG_USR, "%p: extend_size = %d, extend_buffer = %p, ref_cnt = %d.\n", (void *)m, m->m_ext.ext_size, (void *)m->m_ext.ext_buf, *(m->m_ext.ref_cnt));
- }
- }
- #endif
- /*
- * Free an entire chain of mbufs and associated external buffers, if
- * applicable.
- */
- void
- m_freem(struct mbuf *mb)
- {
- while (mb != NULL)
- mb = m_free(mb);
- }
- /*
- * __Userspace__
- * clean mbufs with M_EXT storage attached to them
- * if the reference count hits 1.
- */
- void
- mb_free_ext(struct mbuf *m)
- {
- int skipmbuf;
- KASSERT((m->m_flags & M_EXT) == M_EXT, ("%s: M_EXT not set", __func__));
- KASSERT(m->m_ext.ref_cnt != NULL, ("%s: ref_cnt not set", __func__));
- /*
- * check if the header is embedded in the cluster
- */
- skipmbuf = (m->m_flags & M_NOFREE);
- /* Free the external attached storage if this
- * mbuf is the only reference to it.
- *__Userspace__ TODO: jumbo frames
- *
- */
- /* NOTE: We had the same code that SCTP_DECREMENT_AND_CHECK_REFCOUNT
- reduces to here before but the IPHONE malloc commit had changed
- this to compare to 0 instead of 1 (see next line). Why?
- . .. this caused a huge memory leak in Linux.
- */
- #ifdef IPHONE
- if (atomic_fetchadd_int(m->m_ext.ref_cnt, -1) == 0)
- #else
- if (SCTP_DECREMENT_AND_CHECK_REFCOUNT(m->m_ext.ref_cnt))
- #endif
- {
- if (m->m_ext.ext_type == EXT_CLUSTER){
- #if defined(SCTP_SIMPLE_ALLOCATOR)
- mb_dtor_clust(m->m_ext.ext_buf, &clust_mb_args);
- #endif
- SCTP_ZONE_FREE(zone_clust, m->m_ext.ext_buf);
- SCTP_ZONE_FREE(zone_ext_refcnt, (u_int*)m->m_ext.ref_cnt);
- m->m_ext.ref_cnt = NULL;
- }
- }
- if (skipmbuf)
- return;
- /* __Userspace__ Also freeing the storage for ref_cnt
- * Free this mbuf back to the mbuf zone with all m_ext
- * information purged.
- */
- m->m_ext.ext_buf = NULL;
- m->m_ext.ext_free = NULL;
- m->m_ext.ext_args = NULL;
- m->m_ext.ref_cnt = NULL;
- m->m_ext.ext_size = 0;
- m->m_ext.ext_type = 0;
- m->m_flags &= ~M_EXT;
- #if defined(SCTP_SIMPLE_ALLOCATOR)
- mb_dtor_mbuf(m, NULL);
- #endif
- SCTP_ZONE_FREE(zone_mbuf, m);
- /*umem_cache_free(zone_mbuf, m);*/
- }
- /*
- * "Move" mbuf pkthdr from "from" to "to".
- * "from" must have M_PKTHDR set, and "to" must be empty.
- */
- void
- m_move_pkthdr(struct mbuf *to, struct mbuf *from)
- {
- to->m_flags = (from->m_flags & M_COPYFLAGS) | (to->m_flags & M_EXT);
- if ((to->m_flags & M_EXT) == 0)
- to->m_data = to->m_pktdat;
- to->m_pkthdr = from->m_pkthdr; /* especially tags */
- SLIST_INIT(&from->m_pkthdr.tags); /* purge tags from src */
- from->m_flags &= ~M_PKTHDR;
- }
- /*
- * Rearange an mbuf chain so that len bytes are contiguous
- * and in the data area of an mbuf (so that mtod and dtom
- * will work for a structure of size len). Returns the resulting
- * mbuf chain on success, frees it and returns null on failure.
- * If there is room, it will add up to max_protohdr-len extra bytes to the
- * contiguous region in an attempt to avoid being called next time.
- */
- struct mbuf *
- m_pullup(struct mbuf *n, int len)
- {
- struct mbuf *m;
- int count;
- int space;
- /*
- * If first mbuf has no cluster, and has room for len bytes
- * without shifting current data, pullup into it,
- * otherwise allocate a new mbuf to prepend to the chain.
- */
- if ((n->m_flags & M_EXT) == 0 &&
- n->m_data + len < &n->m_dat[MLEN] && n->m_next) {
- if (n->m_len >= len)
- return (n);
- m = n;
- n = n->m_next;
- len -= m->m_len;
- } else {
- if (len > MHLEN)
- goto bad;
- MGET(m, M_NOWAIT, n->m_type);
- if (m == NULL)
- goto bad;
- m->m_len = 0;
- if (n->m_flags & M_PKTHDR)
- M_MOVE_PKTHDR(m, n);
- }
- space = (int)(&m->m_dat[MLEN] - (m->m_data + m->m_len));
- do {
- count = min(min(max(len, max_protohdr), space), n->m_len);
- memcpy(mtod(m, caddr_t) + m->m_len,mtod(n, caddr_t), (u_int)count);
- len -= count;
- m->m_len += count;
- n->m_len -= count;
- space -= count;
- if (n->m_len)
- n->m_data += count;
- else
- n = m_free(n);
- } while (len > 0 && n);
- if (len > 0) {
- (void) m_free(m);
- goto bad;
- }
- m->m_next = n;
- return (m);
- bad:
- m_freem(n);
- return (NULL);
- }
- static struct mbuf *
- m_dup1(struct mbuf *m, int off, int len, int wait)
- {
- struct mbuf *n = NULL;
- int copyhdr;
- if (len > MCLBYTES)
- return NULL;
- if (off == 0 && (m->m_flags & M_PKTHDR) != 0)
- copyhdr = 1;
- else
- copyhdr = 0;
- if (len >= MINCLSIZE) {
- if (copyhdr == 1) {
- m_clget(n, wait); /* TODO: include code for copying the header */
- m_dup_pkthdr(n, m, wait);
- } else
- m_clget(n, wait);
- } else {
- if (copyhdr == 1)
- n = m_gethdr(wait, m->m_type);
- else
- n = m_get(wait, m->m_type);
- }
- if (!n)
- return NULL; /* ENOBUFS */
- if (copyhdr && !m_dup_pkthdr(n, m, wait)) {
- m_free(n);
- return NULL;
- }
- m_copydata(m, off, len, mtod(n, caddr_t));
- n->m_len = len;
- return n;
- }
- /* Taken from sys/kern/uipc_mbuf2.c */
- struct mbuf *
- m_pulldown(struct mbuf *m, int off, int len, int *offp)
- {
- struct mbuf *n, *o;
- int hlen, tlen, olen;
- int writable;
- /* check invalid arguments. */
- KASSERT(m, ("m == NULL in m_pulldown()"));
- if (len > MCLBYTES) {
- m_freem(m);
- return NULL; /* impossible */
- }
- #ifdef PULLDOWN_DEBUG
- {
- struct mbuf *t;
- SCTP_DEBUG_USR(SCTP_DEBUG_USR, "before:");
- for (t = m; t; t = t->m_next)
- SCTP_DEBUG_USR(SCTP_DEBUG_USR, " %d", t->m_len);
- SCTP_DEBUG_USR(SCTP_DEBUG_USR, "\n");
- }
- #endif
- n = m;
- while (n != NULL && off > 0) {
- if (n->m_len > off)
- break;
- off -= n->m_len;
- n = n->m_next;
- }
- /* be sure to point non-empty mbuf */
- while (n != NULL && n->m_len == 0)
- n = n->m_next;
- if (!n) {
- m_freem(m);
- return NULL; /* mbuf chain too short */
- }
- writable = 0;
- if ((n->m_flags & M_EXT) == 0 ||
- (n->m_ext.ext_type == EXT_CLUSTER && M_WRITABLE(n)))
- writable = 1;
- /*
- * the target data is on <n, off>.
- * if we got enough data on the mbuf "n", we're done.
- */
- if ((off == 0 || offp) && len <= n->m_len - off && writable)
- goto ok;
- /*
- * when len <= n->m_len - off and off != 0, it is a special case.
- * len bytes from <n, off> sits in single mbuf, but the caller does
- * not like the starting position (off).
- * chop the current mbuf into two pieces, set off to 0.
- */
- if (len <= n->m_len - off) {
- o = m_dup1(n, off, n->m_len - off, M_NOWAIT);
- if (o == NULL) {
- m_freem(m);
- return NULL; /* ENOBUFS */
- }
- n->m_len = off;
- o->m_next = n->m_next;
- n->m_next = o;
- n = n->m_next;
- off = 0;
- goto ok;
- }
- /*
- * we need to take hlen from <n, off> and tlen from <n->m_next, 0>,
- * and construct contiguous mbuf with m_len == len.
- * note that hlen + tlen == len, and tlen > 0.
- */
- hlen = n->m_len - off;
- tlen = len - hlen;
- /*
- * ensure that we have enough trailing data on mbuf chain.
- * if not, we can do nothing about the chain.
- */
- olen = 0;
- for (o = n->m_next; o != NULL; o = o->m_next)
- olen += o->m_len;
- if (hlen + olen < len) {
- m_freem(m);
- return NULL; /* mbuf chain too short */
- }
- /*
- * easy cases first.
- * we need to use m_copydata() to get data from <n->m_next, 0>.
- */
- if ((off == 0 || offp) && (M_TRAILINGSPACE(n) >= tlen) && writable) {
- m_copydata(n->m_next, 0, tlen, mtod(n, caddr_t) + n->m_len);
- n->m_len += tlen;
- m_adj(n->m_next, tlen);
- goto ok;
- }
- if ((off == 0 || offp) && (M_LEADINGSPACE(n->m_next) >= hlen) && writable) {
- n->m_next->m_data -= hlen;
- n->m_next->m_len += hlen;
- memcpy( mtod(n->m_next, caddr_t), mtod(n, caddr_t) + off,hlen);
- n->m_len -= hlen;
- n = n->m_next;
- off = 0;
- goto ok;
- }
- /*
- * now, we need to do the hard way. don't m_copy as there's no room
- * on both end.
- */
- if (len > MLEN)
- m_clget(o, M_NOWAIT);
- /* o = m_getcl(M_NOWAIT, m->m_type, 0);*/
- else
- o = m_get(M_NOWAIT, m->m_type);
- if (!o) {
- m_freem(m);
- return NULL; /* ENOBUFS */
- }
- /* get hlen from <n, off> into <o, 0> */
- o->m_len = hlen;
- memcpy(mtod(o, caddr_t), mtod(n, caddr_t) + off, hlen);
- n->m_len -= hlen;
- /* get tlen from <n->m_next, 0> into <o, hlen> */
- m_copydata(n->m_next, 0, tlen, mtod(o, caddr_t) + o->m_len);
- o->m_len += tlen;
- m_adj(n->m_next, tlen);
- o->m_next = n->m_next;
- n->m_next = o;
- n = o;
- off = 0;
- ok:
- #ifdef PULLDOWN_DEBUG
- {
- struct mbuf *t;
- SCTP_DEBUG_USR(SCTP_DEBUG_USR, "after:");
- for (t = m; t; t = t->m_next)
- SCTP_DEBUG_USR(SCTP_DEBUG_USR, "%c%d", t == n ? '*' : ' ', t->m_len);
- SCTP_DEBUG_USR(SCTP_DEBUG_USR, " (off=%d)\n", off);
- }
- #endif
- if (offp)
- *offp = off;
- return n;
- }
- /*
- * Attach the the cluster from *m to *n, set up m_ext in *n
- * and bump the refcount of the cluster.
- */
- static void
- mb_dupcl(struct mbuf *n, struct mbuf *m)
- {
- KASSERT((m->m_flags & M_EXT) == M_EXT, ("%s: M_EXT not set", __func__));
- KASSERT(m->m_ext.ref_cnt != NULL, ("%s: ref_cnt not set", __func__));
- KASSERT((n->m_flags & M_EXT) == 0, ("%s: M_EXT set", __func__));
- if (*(m->m_ext.ref_cnt) == 1)
- *(m->m_ext.ref_cnt) += 1;
- else
- atomic_add_int(m->m_ext.ref_cnt, 1);
- n->m_ext.ext_buf = m->m_ext.ext_buf;
- n->m_ext.ext_free = m->m_ext.ext_free;
- n->m_ext.ext_args = m->m_ext.ext_args;
- n->m_ext.ext_size = m->m_ext.ext_size;
- n->m_ext.ref_cnt = m->m_ext.ref_cnt;
- n->m_ext.ext_type = m->m_ext.ext_type;
- n->m_flags |= M_EXT;
- }
- /*
- * Make a copy of an mbuf chain starting "off0" bytes from the beginning,
- * continuing for "len" bytes. If len is M_COPYALL, copy to end of mbuf.
- * The wait parameter is a choice of M_TRYWAIT/M_NOWAIT from caller.
- * Note that the copy is read-only, because clusters are not copied,
- * only their reference counts are incremented.
- */
- struct mbuf *
- m_copym(struct mbuf *m, int off0, int len, int wait)
- {
- struct mbuf *n, **np;
- int off = off0;
- struct mbuf *top;
- int copyhdr = 0;
- KASSERT(off >= 0, ("m_copym, negative off %d", off));
- KASSERT(len >= 0, ("m_copym, negative len %d", len));
- KASSERT(m != NULL, ("m_copym, m is NULL"));
- #if !defined(INVARIANTS)
- if (m == NULL) {
- return (NULL);
- }
- #endif
- if (off == 0 && m->m_flags & M_PKTHDR)
- copyhdr = 1;
- while (off > 0) {
- KASSERT(m != NULL, ("m_copym, offset > size of mbuf chain"));
- if (off < m->m_len)
- break;
- off -= m->m_len;
- m = m->m_next;
- }
- np = ⊤
- top = 0;
- while (len > 0) {
- if (m == NULL) {
- KASSERT(len == M_COPYALL, ("m_copym, length > size of mbuf chain"));
- break;
- }
- if (copyhdr)
- MGETHDR(n, wait, m->m_type);
- else
- MGET(n, wait, m->m_type);
- *np = n;
- if (n == NULL)
- goto nospace;
- if (copyhdr) {
- if (!m_dup_pkthdr(n, m, wait))
- goto nospace;
- if (len == M_COPYALL)
- n->m_pkthdr.len -= off0;
- else
- n->m_pkthdr.len = len;
- copyhdr = 0;
- }
- n->m_len = min(len, m->m_len - off);
- if (m->m_flags & M_EXT) {
- n->m_data = m->m_data + off;
- mb_dupcl(n, m);
- } else
- memcpy(mtod(n, caddr_t), mtod(m, caddr_t) + off, (u_int)n->m_len);
- if (len != M_COPYALL)
- len -= n->m_len;
- off = 0;
- m = m->m_next;
- np = &n->m_next;
- }
- return (top);
- nospace:
- m_freem(top);
- return (NULL);
- }
- int
- m_tag_copy_chain(struct mbuf *to, struct mbuf *from, int how)
- {
- struct m_tag *p, *t, *tprev = NULL;
- KASSERT(to && from, ("m_tag_copy_chain: null argument, to %p from %p", (void *)to, (void *)from));
- m_tag_delete_chain(to, NULL);
- SLIST_FOREACH(p, &from->m_pkthdr.tags, m_tag_link) {
- t = m_tag_copy(p, how);
- if (t == NULL) {
- m_tag_delete_chain(to, NULL);
- return 0;
- }
- if (tprev == NULL)
- SLIST_INSERT_HEAD(&to->m_pkthdr.tags, t, m_tag_link);
- else
- SLIST_INSERT_AFTER(tprev, t, m_tag_link);
- tprev = t;
- }
- return 1;
- }
- /*
- * Duplicate "from"'s mbuf pkthdr in "to".
- * "from" must have M_PKTHDR set, and "to" must be empty.
- * In particular, this does a deep copy of the packet tags.
- */
- int
- m_dup_pkthdr(struct mbuf *to, struct mbuf *from, int how)
- {
- KASSERT(to, ("m_dup_pkthdr: to is NULL"));
- KASSERT(from, ("m_dup_pkthdr: from is NULL"));
- to->m_flags = (from->m_flags & M_COPYFLAGS) | (to->m_flags & M_EXT);
- if ((to->m_flags & M_EXT) == 0)
- to->m_data = to->m_pktdat;
- to->m_pkthdr = from->m_pkthdr;
- SLIST_INIT(&to->m_pkthdr.tags);
- return (m_tag_copy_chain(to, from, MBTOM(how)));
- }
- /* Copy a single tag. */
- struct m_tag *
- m_tag_copy(struct m_tag *t, int how)
- {
- struct m_tag *p;
- KASSERT(t, ("m_tag_copy: null tag"));
- p = m_tag_alloc(t->m_tag_cookie, t->m_tag_id, t->m_tag_len, how);
- if (p == NULL)
- return (NULL);
- memcpy(p + 1, t + 1, t->m_tag_len); /* Copy the data */
- return p;
- }
- /* Get a packet tag structure along with specified data following. */
- struct m_tag *
- m_tag_alloc(uint32_t cookie, int type, int len, int wait)
- {
- struct m_tag *t;
- if (len < 0)
- return NULL;
- t = malloc(len + sizeof(struct m_tag));
- if (t == NULL)
- return NULL;
- m_tag_setup(t, cookie, type, len);
- t->m_tag_free = m_tag_free_default;
- return t;
- }
- /* Free a packet tag. */
- void
- m_tag_free_default(struct m_tag *t)
- {
- free(t);
- }
- /*
- * Copy data from a buffer back into the indicated mbuf chain,
- * starting "off" bytes from the beginning, extending the mbuf
- * chain if necessary.
- */
- void
- m_copyback(struct mbuf *m0, int off, int len, caddr_t cp)
- {
- int mlen;
- struct mbuf *m = m0, *n;
- int totlen = 0;
- if (m0 == NULL)
- return;
- while (off > (mlen = m->m_len)) {
- off -= mlen;
- totlen += mlen;
- if (m->m_next == NULL) {
- n = m_get(M_NOWAIT, m->m_type);
- if (n == NULL)
- goto out;
- memset(mtod(n, caddr_t), 0, MLEN);
- n->m_len = min(MLEN, len + off);
- m->m_next = n;
- }
- m = m->m_next;
- }
- while (len > 0) {
- mlen = min (m->m_len - off, len);
- memcpy(off + mtod(m, caddr_t), cp, (u_int)mlen);
- cp += mlen;
- len -= mlen;
- mlen += off;
- off = 0;
- totlen += mlen;
- if (len == 0)
- break;
- if (m->m_next == NULL) {
- n = m_get(M_NOWAIT, m->m_type);
- if (n == NULL)
- break;
- n->m_len = min(MLEN, len);
- m->m_next = n;
- }
- m = m->m_next;
- }
- out: if (((m = m0)->m_flags & M_PKTHDR) && (m->m_pkthdr.len < totlen))
- m->m_pkthdr.len = totlen;
- }
- /*
- * Apply function f to the data in an mbuf chain starting "off" bytes from
- * the beginning, continuing for "len" bytes.
- */
- int
- m_apply(struct mbuf *m, int off, int len,
- int (*f)(void *, void *, u_int), void *arg)
- {
- u_int count;
- int rval;
- KASSERT(off >= 0, ("m_apply, negative off %d", off));
- KASSERT(len >= 0, ("m_apply, negative len %d", len));
- while (off > 0) {
- KASSERT(m != NULL, ("m_apply, offset > size of mbuf chain"));
- if (off < m->m_len)
- break;
- off -= m->m_len;
- m = m->m_next;
- }
- while (len > 0) {
- KASSERT(m != NULL, ("m_apply, offset > size of mbuf chain"));
- count = min(m->m_len - off, len);
- rval = (*f)(arg, mtod(m, caddr_t) + off, count);
- if (rval)
- return (rval);
- len -= count;
- off = 0;
- m = m->m_next;
- }
- return (0);
- }
- /*
- * Lesser-used path for M_PREPEND:
- * allocate new mbuf to prepend to chain,
- * copy junk along.
- */
- struct mbuf *
- m_prepend(struct mbuf *m, int len, int how)
- {
- struct mbuf *mn;
- if (m->m_flags & M_PKTHDR)
- MGETHDR(mn, how, m->m_type);
- else
- MGET(mn, how, m->m_type);
- if (mn == NULL) {
- m_freem(m);
- return (NULL);
- }
- if (m->m_flags & M_PKTHDR)
- M_MOVE_PKTHDR(mn, m);
- mn->m_next = m;
- m = mn;
- if (m->m_flags & M_PKTHDR) {
- if (len < MHLEN)
- MH_ALIGN(m, len);
- } else {
- if (len < MLEN)
- M_ALIGN(m, len);
- }
- m->m_len = len;
- return (m);
- }
- /*
- * Copy data from an mbuf chain starting "off" bytes from the beginning,
- * continuing for "len" bytes, into the indicated buffer.
- */
- void
- m_copydata(const struct mbuf *m, int off, int len, caddr_t cp)
- {
- u_int count;
- KASSERT(off >= 0, ("m_copydata, negative off %d", off));
- KASSERT(len >= 0, ("m_copydata, negative len %d", len));
- while (off > 0) {
- KASSERT(m != NULL, ("m_copydata, offset > size of mbuf chain"));
- if (off < m->m_len)
- break;
- off -= m->m_len;
- m = m->m_next;
- }
- while (len > 0) {
- KASSERT(m != NULL, ("m_copydata, length > size of mbuf chain"));
- count = min(m->m_len - off, len);
- memcpy(cp, mtod(m, caddr_t) + off, count);
- len -= count;
- cp += count;
- off = 0;
- m = m->m_next;
- }
- }
- /*
- * Concatenate mbuf chain n to m.
- * Both chains must be of the same type (e.g. MT_DATA).
- * Any m_pkthdr is not updated.
- */
- void
- m_cat(struct mbuf *m, struct mbuf *n)
- {
- while (m->m_next)
- m = m->m_next;
- while (n) {
- if (m->m_flags & M_EXT ||
- m->m_data + m->m_len + n->m_len >= &m->m_dat[MLEN]) {
- /* just join the two chains */
- m->m_next = n;
- return;
- }
- /* splat the data from one into the other */
- memcpy(mtod(m, caddr_t) + m->m_len, mtod(n, caddr_t), (u_int)n->m_len);
- m->m_len += n->m_len;
- n = m_free(n);
- }
- }
- void
- m_adj(struct mbuf *mp, int req_len)
- {
- int len = req_len;
- struct mbuf *m;
- int count;
- if ((m = mp) == NULL)
- return;
- if (len >= 0) {
- /*
- * Trim from head.
- */
- while (m != NULL && len > 0) {
- if (m->m_len <= len) {
- len -= m->m_len;
- m->m_len = 0;
- m = m->m_next;
- } else {
- m->m_len -= len;
- m->m_data += len;
- len = 0;
- }
- }
- m = mp;
- if (mp->m_flags & M_PKTHDR)
- m->m_pkthdr.len -= (req_len - len);
- } else {
- /*
- * Trim from tail. Scan the mbuf chain,
- * calculating its length and finding the last mbuf.
- * If the adjustment only affects this mbuf, then just
- * adjust and return. Otherwise, rescan and truncate
- * after the remaining size.
- */
- len = -len;
- count = 0;
- for (;;) {
- count += m->m_len;
- if (m->m_next == (struct mbuf *)0)
- break;
- m = m->m_next;
- }
- if (m->m_len >= len) {
- m->m_len -= len;
- if (mp->m_flags & M_PKTHDR)
- mp->m_pkthdr.len -= len;
- return;
- }
- count -= len;
- if (count < 0)
- count = 0;
- /*
- * Correct length for chain is "count".
- * Find the mbuf with last data, adjust its length,
- * and toss data from remaining mbufs on chain.
- */
- m = mp;
- if (m->m_flags & M_PKTHDR)
- m->m_pkthdr.len = count;
- for (; m; m = m->m_next) {
- if (m->m_len >= count) {
- m->m_len = count;
- if (m->m_next != NULL) {
- m_freem(m->m_next);
- m->m_next = NULL;
- }
- break;
- }
- count -= m->m_len;
- }
- }
- }
- /* m_split is used within sctp_handle_cookie_echo. */
- /*
- * Partition an mbuf chain in two pieces, returning the tail --
- * all but the first len0 bytes. In case of failure, it returns NULL and
- * attempts to restore the chain to its original state.
- *
- * Note that the resulting mbufs might be read-only, because the new
- * mbuf can end up sharing an mbuf cluster with the original mbuf if
- * the "breaking point" happens to lie within a cluster mbuf. Use the
- * M_WRITABLE() macro to check for this case.
- */
- struct mbuf *
- m_split(struct mbuf *m0, int len0, int wait)
- {
- struct mbuf *m, *n;
- u_int len = len0, remain;
- /* MBUF_CHECKSLEEP(wait); */
- for (m = m0; m && (int)len > m->m_len; m = m->m_next)
- len -= m->m_len;
- if (m == NULL)
- return (NULL);
- remain = m->m_len - len;
- if (m0->m_flags & M_PKTHDR) {
- MGETHDR(n, wait, m0->m_type);
- if (n == NULL)
- return (NULL);
- n->m_pkthdr.rcvif = m0->m_pkthdr.rcvif;
- n->m_pkthdr.len = m0->m_pkthdr.len - len0;
- m0->m_pkthdr.len = len0;
- if (m->m_flags & M_EXT)
- goto extpacket;
- if (remain > MHLEN) {
- /* m can't be the lead packet */
- MH_ALIGN(n, 0);
- n->m_next = m_split(m, len, wait);
- if (n->m_next == NULL) {
- (void) m_free(n);
- return (NULL);
- } else {
- n->m_len = 0;
- return (n);
- }
- } else
- MH_ALIGN(n, remain);
- } else if (remain == 0) {
- n = m->m_next;
- m->m_next = NULL;
- return (n);
- } else {
- MGET(n, wait, m->m_type);
- if (n == NULL)
- return (NULL);
- M_ALIGN(n, remain);
- }
- extpacket:
- if (m->m_flags & M_EXT) {
- n->m_data = m->m_data + len;
- mb_dupcl(n, m);
- } else {
- memcpy(mtod(n, caddr_t), mtod(m, caddr_t) + len, remain);
- }
- n->m_len = remain;
- m->m_len = len;
- n->m_next = m->m_next;
- m->m_next = NULL;
- return (n);
- }
- int
- pack_send_buffer(caddr_t buffer, struct mbuf* mb){
- int count_to_copy;
- int total_count_copied = 0;
- int offset = 0;
- do {
- count_to_copy = mb->m_len;
- memcpy(buffer+offset, mtod(mb, caddr_t), count_to_copy);
- offset += count_to_copy;
- total_count_copied += count_to_copy;
- mb = mb->m_next;
- } while(mb);
- return (total_count_copied);
- }
|