mbufLib.c
上传用户:nvosite88
上传日期:2007-01-17
资源大小:4983k
文件大小:42k
源码类别:

VxWorks

开发平台:

C/C++

  1. /* mbufLib.c - BSD mbuf interface library */
  2. /* Copyright 1984 - 2001 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 01i,15oct01,rae  merge from truestack ver 01l, base 01h
  8. 01h,25aug98,n_s  corrected error handling of buffer allocate calls. spr #22104
  9. 01g,19sep97,vin  added clBlk specific code, changed pointers to refcounts
  10.  of clusters to refcounts since refcount has been moved to
  11.                  clBlk
  12. 01f,12aug97,vin  changed mBlkGet to take _pNetDpool
  13. 01e,22nov96,vin  added cluster support replaced m_get(..) with mBlkGet(..).
  14. 01d,29aug96,vin  made the code use only m_get.
  15. 01c,06jun96,vin  made compatible with BSD4.4 mbufs.
  16. 01b,13nov95,dzb  changed to validate mbufId.type off MBUF_VALID (SPR #4066).
  17. 01a,08nov94,dzb  written.
  18. */
  19. /*
  20. DESCRIPTION
  21. This library contains routines to create, build, manipulate, and
  22. delete BSD mbufs.  It serves as a back-end to the zbuf API provided
  23. by zbufLib.
  24. Note: The user should protect mbufs before calling these routines.  For many
  25.       operations, it may be appropriate to guard with the spl semaphore.
  26. NOMANUAL
  27. */
  28. /* includes */
  29. #include "vxWorks.h"
  30. #include "zbufLib.h"
  31. #include "mbufLib.h"
  32. #include "errnoLib.h"
  33. #include "intLib.h"
  34. #include "stdlib.h"
  35. #include "memPartLib.h"
  36. #ifdef VIRTUAL_STACK
  37. #include "netinet/vsLib.h"
  38. #endif
  39. /* globals */
  40. MBUF_ID _mbufIdHead = NULL; /* Head ID of free chain */
  41. /* locals */
  42. LOCAL BOOL mbufInit = FALSE; /* library initialized ? */
  43. LOCAL MBUF_DESC mbufDescHead = NULL; /* Head of free desc list */
  44. /* declare mbuf interface function table */
  45. LOCAL ZBUF_FUNC mbufFunc =
  46.     {
  47.     (FUNCPTR) _mbufCreate,
  48.     (FUNCPTR) _mbufDelete,
  49.     (FUNCPTR) _mbufInsert,
  50.     (FUNCPTR) _mbufInsertBuf,
  51.     (FUNCPTR) _mbufInsertCopy,
  52.     (FUNCPTR) _mbufExtractCopy,
  53.     (FUNCPTR) _mbufCut,
  54.     (FUNCPTR) _mbufSplit,
  55.     (FUNCPTR) _mbufDup,
  56.     (FUNCPTR) _mbufLength,
  57.     (FUNCPTR) _mbufSegFind,
  58.     (FUNCPTR) _mbufSegNext,
  59.     (FUNCPTR) _mbufSegPrev,
  60.     (FUNCPTR) _mbufSegData,
  61.     (FUNCPTR) _mbufSegLength
  62.     };
  63. /* static function declarations */
  64. LOCAL void _mbufBufFree (MBUF_DESC mbufDesc, VOIDFUNCPTR freeRtn,
  65.                             int freeArg);
  66. LOCAL MBUF_SEG * _mbufSegFindPrev (MBUF_ID mbufId, MBUF_SEG mbufSeg,
  67.             int *pOffset);
  68. /*******************************************************************************
  69. *
  70. * _mbufLibInit - initialize the BSD mbuf interface library
  71. *
  72. * This routine initializes the BSD mbuf interface library and publishes
  73. * the mbufLib API to the caller.  Lists of free ID structures and
  74. * free mbuf cluster descriptors are allocated in this routine.
  75. *
  76. * The mbufLib API func table "mbufFunc" is published to the caller upon
  77. * completion of initialization.  Typically, this func table is used by
  78. * the zbuf facility to call mbuf routines within this library to perform
  79. * buffering operations.  Even though the zbuf interface defines the ZBUF_FUNC
  80. * struct, it doesn't necessarily mean that zbufs must be present.  This
  81. * library may be used even if zbufs have been scaled out of the system.
  82. *
  83. * RETURNS:
  84. * A pointer to a func table containing the mbufLib API,
  85. * or NULL if the mbuf interface could not be initialized.
  86. *
  87. * NOMANUAL
  88. */
  89. void * _mbufLibInit (void)
  90.     {
  91.     int ix; /* counter for list init */
  92.     if (mbufInit == TRUE) /* already initialized ? */
  93.         return ((void *) &mbufFunc);
  94.     if ((_mbufIdHead = (MBUF_ID) KHEAP_ALLOC((sizeof (struct mbufId) *
  95. MBUF_ID_INC))) == NULL) /* alloc space for ID list */
  96.         return (NULL);
  97.     if ((mbufDescHead = (MBUF_DESC) KHEAP_ALLOC((sizeof (struct mbufDesc) *
  98. MBUF_DESC_INC))) == NULL) /* alloc space for desc list */
  99. {
  100. KHEAP_FREE((char *)_mbufIdHead);
  101.         return (NULL);
  102. }
  103.     /* divide up into an sll of free mbuf ID's, _mbufIdHead as the head */
  104.     for (ix = 0; ix < (MBUF_ID_INC - 1); ix++)
  105.         _mbufIdHead[ix].mbufIdNext = &_mbufIdHead[ix + 1];
  106.     _mbufIdHead[ix].mbufIdNext = NULL;
  107.     /* divide up into an sll of free buf desc, mbufDescHead as the head */
  108.     for (ix = 0; ix < (MBUF_DESC_INC - 1); ix++)
  109.         mbufDescHead[ix].mbufDescNext = &mbufDescHead[ix + 1];
  110.     mbufDescHead[ix].mbufDescNext = NULL;
  111.     mbufInit = TRUE; /* init successful */
  112.     return ((void *) &mbufFunc); /* return mbuf func table */
  113.     }
  114. /*******************************************************************************
  115. *
  116. * _mbufCreate - create an empty mbuf ID
  117. *
  118. * This routine creates an mbuf ID, which remains empty (i.e., does not
  119. * contain any mbufs) until mbufs are added by the mbuf insertion routines.
  120. * Operations performed on mbufs require an mbuf ID, which is returned by
  121. * this routine.
  122. *
  123. * RETURNS:
  124. * An mbuf ID, or NULL if an mbuf ID could not be created.
  125. *
  126. * SEE ALSO: _mbufCreate
  127. *
  128. * NOMANUAL
  129. */
  130. MBUF_ID _mbufCreate (void)
  131.     {
  132.     MBUF_ID mbufId; /* obtained mbuf ID */
  133.     int ix; /* counter for list init */
  134.     int lockKey = intLock (); /* int lock cookie */
  135.     if ((mbufId = _mbufIdHead) != NULL) /* free list empty ? */
  136.         {
  137.         _mbufIdHead = mbufId->mbufIdNext; /* pop first ID off list */
  138.         intUnlock (lockKey);
  139.         mbufId->type = MBUF_VALID; /* init new ID type */
  140.         mbufId->mbufHead = NULL; /* init new ID head */
  141.         }
  142.     else /* list is empty */
  143. {
  144.         intUnlock (lockKey);
  145.         if ((mbufId = (MBUF_ID) KHEAP_ALLOC((sizeof (struct mbufId) *
  146.             MBUF_ID_INC))) != NULL) /* alloc more IDs */
  147.             {
  148.             for (ix = 0; ix < (MBUF_ID_INC - 1); ix++) /* into an sll */
  149.                 mbufId[ix].mbufIdNext = &mbufId[ix + 1];
  150.             lockKey = intLock ();
  151.             mbufId[ix].mbufIdNext = _mbufIdHead;
  152.             _mbufIdHead = mbufId->mbufIdNext; /* hook head onto new list */
  153.             intUnlock (lockKey);
  154.             mbufId->type = MBUF_VALID; /* init new ID type */
  155.             mbufId->mbufHead = NULL; /* init new ID head */
  156.             }
  157.         }
  158.     return (mbufId); /* return new ID */
  159.     }
  160. /*******************************************************************************
  161. *
  162. * _mbufDelete - delete an mbuf ID and free any associated mbufs
  163. *
  164. * This routine will free any mbufs associated with <mbufId>, then
  165. * delete the mbuf ID itself.  <mbufId> should not be used after this
  166. * routine executes successfully.
  167. *
  168. * RETURNS:
  169. * OK, or ERROR if the mbuf ID could not be deleted.
  170. *
  171. * SEE ALSO: _mbufCreate
  172. *
  173. * NOMANUAL
  174. */
  175. STATUS _mbufDelete
  176.     (
  177.     MBUF_ID mbufId /* mbuf ID to free */
  178.     )
  179.     {
  180.     /* already free ? */
  181.     
  182.     if (mbufId == NULL || mbufId->type != MBUF_VALID)
  183. {
  184. errno = S_mbufLib_ID_INVALID; /* invalid if already free */
  185. return (ERROR);
  186. }
  187.     MBUF_ID_DELETE(mbufId); /* delete mbuf ID */
  188.     return (OK); /* return OK, always */
  189.     }
  190. /*******************************************************************************
  191. *
  192. * _mbufInsert - insert an mbuf chain into another mbuf chain
  193. *
  194. * This routine inserts all <mbufId2> mbufs into <mbufId1> at the
  195. * specified byte location
  196. *
  197. * The location of insertion is specified by <mbufSeg> and <offset>.  Note
  198. * that insertion within a chain occurs before the byte location specified
  199. * by <mbufSeg> and <offset>.  Additionally, note that <mbufSeg> and <offset>
  200. * must be "NULL" and "0", respectively, when inserting into an empty mbuf ID.
  201. *
  202. * After all the <mbufId2> mbufs are inserted into <mbufId1>, the mbuf ID
  203. * <mbufId2> is deleted.  <mbufId2> should not be used after this routine
  204. * executes successfully.
  205. *
  206. * RETURNS:
  207. * The mbuf pointer associated with the first inserted mbuf,
  208. * or NULL if the operation failed.
  209. *
  210. * NOMANUAL
  211. */
  212. MBUF_SEG _mbufInsert
  213.     (
  214.     MBUF_ID mbufId1, /* mbuf ID to insert <mbufId2> into */
  215.     MBUF_SEG mbufSeg, /* mbuf base for <offset> */
  216.     int offset, /* relative byte offset */
  217.     MBUF_ID mbufId2 /* mbuf ID to insert into <mbufId1> */
  218.     )
  219.     {
  220.     MBUF_ID mbufIdNew; /* dummy ID for dup operation */
  221.     MBUF_SEG * pMbufPrev; /* mbuf prev to insert */
  222.     MBUF_SEG mbufEnd; /* last Id2 mbuf */
  223.     int maxLen = MBUF_END; /* offset for last Id2 byte */
  224.     /* find the mbuf ptr previous to the point of insertion */
  225.     if ((pMbufPrev = _mbufSegFindPrev (mbufId1, mbufSeg, &offset)) == NULL)
  226.         return (NULL);
  227.     if ((mbufEnd = _mbufSegFind (mbufId2, NULL, &maxLen)) == NULL)
  228. return (NULL); /* find end mbuf of Id2 */
  229.     if (offset == 0) /* if prepend... */
  230. {
  231. mbufEnd->m_next = *pMbufPrev;
  232. *pMbufPrev = mbufId2->mbufHead;
  233.         }
  234.     else /* else insert... */
  235.         {
  236. mbufSeg = *pMbufPrev; /* find insertion mbuf */
  237.         if ((mbufIdNew = _mbufDup (mbufId1, mbufSeg, offset,
  238.             mbufSeg->m_len - offset)) == NULL)
  239.             return (NULL); /* dup later portion */
  240.         mbufSeg->m_len = offset; /* shorten to first portion */
  241.         mbufIdNew->mbufHead->m_next = mbufSeg->m_next;
  242.         mbufEnd->m_next = mbufIdNew->mbufHead; /* insert Id2 */
  243.         mbufSeg->m_next = mbufId2->mbufHead;
  244.         MBUF_ID_DELETE_EMPTY(mbufIdNew); /* delete dup ID */
  245. }
  246.     mbufEnd = mbufId2->mbufHead; /* save head for return */
  247.     if (mbufId2->type == MBUF_VALID)
  248. {
  249.         MBUF_ID_DELETE_EMPTY(mbufId2); /* delete ref to Id2 */
  250. }
  251.     return (mbufEnd); /* return inserted mbuf */
  252.     }
  253. /*******************************************************************************
  254. *
  255. * _mbufInsertBuf - create a cluster from a buffer and insert into an mbuf chain
  256. *
  257. * This routine creates an mbuf cluster from the user buffer <buf> and
  258. * inserts it at the specified byte location in <mbufId>.
  259. *
  260. * The location of insertion is specified by <mbufSeg> and <offset>.  Note
  261. * that insertion within a chain occurs before the byte location specified
  262. * by <mbufSeg> and <offset>.  Additionally, note that <mbufSeg> and <offset>
  263. * must be "NULL" and "0", respectively, when inserting into an empty mbuf ID.
  264. *
  265. * The user provided free routine <freeRtn> will be called when the mbuf
  266. * cluster created from <buf> is not being referenced by any more mbufs.
  267. * If <freeRtn> is NULL, the mbuf will function normally, except that the
  268. * user will not be notified when no more mbufs reference cluster containing
  269. * <buf>.  <freeRtn> will be called from the context of the task that last
  270. * references the cluster.  <freeRtn> should be declared as follows:
  271. * .CS
  272. *       void freeRtn
  273. *           (
  274. *           caddr_t     buf,    /@ pointer to user buffer @/
  275. *           int         freeArg /@ user provided argument to free routine @/
  276. *           )
  277. * .CE
  278. *
  279. * RETURNS:
  280. * The mbuf pointer associated with the inserted mbuf cluster,
  281. * or NULL if the operation failed.
  282. *
  283. * NOMANUAL
  284. */
  285. MBUF_SEG _mbufInsertBuf
  286.     (
  287.     MBUF_ID mbufId, /* mbuf ID which buffer is inserted */
  288.     MBUF_SEG mbufSeg, /* mbuf base for <offset> */
  289.     int offset, /* relative byte offset */
  290.     caddr_t buf, /* user buffer for mbuf cluster */
  291.     int len, /* number of bytes to insert */
  292.     VOIDFUNCPTR freeRtn, /* user free routine */
  293.     int freeArg /* argument to free routine */
  294.     )
  295.     {
  296.     MBUF_ID mbufIdNew; /* mbuf ID containing <buf> */
  297.     MBUF_DESC  mbufDesc; /* desc for <buf> cluster */
  298.     MBUF_SEG mbufNew; /* mbuf for <buf> cluster */
  299.     CL_BLK_ID pClBlk; /* pointer to cluster blk */
  300.     int lockKey; /* int lock cookie */
  301.     int ix; /* counter for list init */
  302.     if (len <= 0) /* have to insert some bytes */
  303.         {
  304. errno = S_mbufLib_LENGTH_INVALID;
  305. return (NULL);
  306. }
  307.     MBUF_ID_CREATE (mbufIdNew); /* create new mbuf ID for buf */
  308.     if (mbufIdNew == NULL)
  309. return (NULL);
  310.     lockKey = intLock ();
  311.     if ((mbufDesc = mbufDescHead) != NULL) /* free list empty ? */
  312.         {
  313.         mbufDescHead = mbufDesc->mbufDescNext; /* pop first desc off list */
  314.         intUnlock (lockKey);
  315. }
  316.     else /* list is empty */
  317. {
  318.         intUnlock (lockKey);
  319. if ((mbufDesc = (MBUF_DESC) KHEAP_ALLOC((sizeof (struct mbufDesc) *
  320.     MBUF_DESC_INC))) != NULL) /* alloc more desc's */
  321.             {
  322.             for (ix = 0; ix < (MBUF_DESC_INC - 1); ix++)
  323.                 mbufDesc[ix].mbufDescNext = &mbufDesc[ix + 1];
  324.             lockKey = intLock ();
  325.             mbufDesc[ix].mbufDescNext = mbufDescHead;
  326.             mbufDescHead = mbufDesc->mbufDescNext;/* hook head onto new list */
  327.             intUnlock (lockKey);
  328.     }
  329.         }
  330.     if (mbufDesc == NULL) /* able to get a new desc ? */
  331. {
  332.         MBUF_ID_DELETE_EMPTY(mbufIdNew);
  333. return (NULL);
  334. }
  335.     mbufDesc->buf = buf;
  336.     /* get mbuf for cluster */
  337.     
  338.     if ( (mbufNew = mBlkGet (_pNetDpool, M_WAIT, MT_DATA)) == NULL)
  339.         {
  340. /* release on fail */
  341. lockKey = intLock ();
  342. mbufDescHead = mbufDesc;
  343. intUnlock (lockKey);
  344. MBUF_ID_DELETE_EMPTY (mbufIdNew);
  345. return (NULL);
  346. }
  347.     pClBlk = clBlkGet (_pNetDpool, M_WAIT); 
  348.     
  349.     if (pClBlk == NULL) /* out of cl Blks */
  350.         {
  351.         m_free (mbufNew);
  352. lockKey = intLock ();
  353. mbufDescHead = mbufDesc;
  354. intUnlock (lockKey);
  355. MBUF_ID_DELETE_EMPTY (mbufIdNew);
  356. return (NULL);
  357.         }
  358.     mbufNew->pClBlk = pClBlk;
  359.     /* build <buf> into an mbuf cluster */
  360.     mbufNew->m_data = buf;
  361.     mbufNew->m_len = len;
  362.     mbufNew->m_flags |= M_EXT;
  363.     mbufNew->m_extBuf = buf;
  364.     mbufNew->m_extSize = len;
  365.     mbufNew->m_extFreeRtn = (FUNCPTR) _mbufBufFree;
  366.     mbufNew->m_extRefCnt = 1;
  367.     mbufNew->m_extArg1 = (int) mbufDesc;
  368.     mbufNew->m_extArg2 = (int) freeRtn;
  369.     mbufNew->m_extArg3 = freeArg;
  370.     mbufIdNew->mbufHead = mbufNew; /* put cluster into new ID */
  371.     /* insert the new mbuf ID with <buf> into <mbufId> */
  372.     if ((mbufSeg = _mbufInsert (mbufId, mbufSeg, offset, mbufIdNew)) == NULL)
  373. {
  374.         mbufNew->m_extArg2 = (int)NULL; /* don't call freeRtn on fail */
  375.         MBUF_ID_DELETE(mbufIdNew);
  376. }
  377.     return (mbufSeg); /* return inserted mbuf */
  378.     }
  379. /*******************************************************************************
  380. *
  381. * _mbufBufFree - free a user cluster buffer
  382. *
  383. * This routine is called when a cluster buffer is deleted, and no other
  384. * mbuf clusters share the buffer space.  This routine calls the user free
  385. * routine connected in _mbufInsertBuf(), then pushes the buffer decsriptor
  386. * back onto the desc free list.
  387. *
  388. * RETURNS:
  389. * N/A
  390. *
  391. * NOMANUAL
  392. */
  393. LOCAL void _mbufBufFree
  394.     (
  395.     MBUF_DESC mbufDesc, /* desc of mbuf to free */
  396.     VOIDFUNCPTR freeRtn, /* user free routine */
  397.     int freeArg /* argument to free routine */
  398.     )
  399.     {
  400.     int lockKey; /* int lock cookie */
  401.     if (freeRtn != NULL) /* call free rtn if present */
  402.         (*freeRtn) (mbufDesc->buf, freeArg);
  403.     lockKey = intLock ();
  404.     mbufDesc->mbufDescNext = mbufDescHead; /* push desc onto free list */
  405.     mbufDescHead = mbufDesc;
  406.     intUnlock (lockKey);
  407.     }
  408. /*******************************************************************************
  409. *
  410. * _mbufInsertCopy - copy buffer data into an mbuf chain
  411. *
  412. * This routine copies <len> bytes of data from the user buffer <buf> and
  413. * inserts it at the specified byte location in <mbufId>.  The user buffer
  414. * is in no way tied to the mbuf chain after this operation; a separate copy
  415. * of the data is made.
  416. *
  417. * The location of insertion is specified by <mbufSeg> and <offset>.  Note
  418. * that insertion within a chain occurs before the byte location specified
  419. * by <mbufSeg> and <offset>.  Additionally, note that <mbufSeg> and <offset>
  420. * must be "NULL" and "0", respectively, when inserting into an empty mbuf ID.
  421. *
  422. * RETURNS:
  423. * The mbuf pointer associated with the first inserted mbuf,
  424. * or NULL if the operation failed.
  425. *
  426. * NOMANUAL
  427. */
  428. MBUF_SEG _mbufInsertCopy
  429.     (
  430.     MBUF_ID mbufId, /* mbuf ID into which data is copied */
  431.     MBUF_SEG mbufSeg, /* mbuf base for <offset> */
  432.     int offset, /* relative byte offset */
  433.     caddr_t buf, /* buffer from which data is copied  */
  434.     int len /* number of byte to copy */
  435.     )
  436.     {
  437.     MBUF_ID mbufIdNew; /* dummy ID for dup operation */
  438.     MBUF_SEG mbufNew; /* mbuf for copy */
  439.     MBUF_SEG * pMbufPrev; /* mbuf previous to mbufNew */
  440.     int length; /* length of each copy */
  441.     if (len <= 0) /* have to copy some bytes */
  442.         {
  443. errno = S_mbufLib_LENGTH_INVALID;
  444. return (NULL);
  445. }
  446.     MBUF_ID_CREATE (mbufIdNew); /* create new ID for copy */
  447.     if (mbufIdNew == NULL)
  448. return (NULL);
  449.     pMbufPrev = &mbufIdNew->mbufHead; /* init prev ptr to head */
  450.     while (len) /* while more to copy */
  451. {
  452. /* obtain a new mbuf with a data buffer pointed */
  453. if ( (mbufNew = mBufClGet (M_WAIT, MT_DATA, len, FALSE)) == NULL)
  454.     {
  455.     /* release on fail */
  456.     MBUF_ID_DELETE(mbufIdNew);
  457.     return (NULL);
  458.     }
  459. length = min (len, mbufNew->m_extSize); /* num for copy */
  460.         bcopy (buf, mtod (mbufNew, char *), length);
  461.         buf += length; /* bump to new buf position */
  462. len -= length;
  463. mbufNew->m_len = length; /* set len to num copied */
  464.         *pMbufPrev = mbufNew;                   /* hook prev into new */
  465. pMbufPrev = &mbufNew->m_next;           /* update prev mbuf ptr */
  466. }
  467.     /* insert the new mbuf ID with copied data into <mbufId> */
  468.     if ((mbufSeg = _mbufInsert (mbufId, mbufSeg, offset, mbufIdNew)) == NULL)
  469.         {
  470. /* release on fail */
  471. MBUF_ID_DELETE(mbufIdNew);
  472. return (NULL);
  473. }
  474.     return (mbufSeg); /* return inserted mbuf */
  475.     }
  476. /*******************************************************************************
  477. *
  478. * _mbufExtractCopy - copy data from an mbuf chain to a buffer
  479. *
  480. * This routine copies <len> bytes of data from <mbufId> to the user
  481. * buffer <buf>.
  482. *
  483. * The starting location of the copy is specified by <mbufSeg> and <offset>.
  484. *
  485. * The number of bytes to be copied is given by <len>.  If this parameter
  486. * is negative, or is larger than the number of bytes in the chain after the
  487. * specified byte location, the rest of the chain will be copied. 
  488. * The bytes to be copied may span more than one mbuf.
  489. *
  490. * RETURNS:
  491. * The number of bytes copied from the mbuf chain to the buffer,
  492. * or ERROR if the operation failed.
  493. *
  494. * NOMANUAL
  495. */
  496. int _mbufExtractCopy
  497.     (
  498.     MBUF_ID mbufId, /* mbuf ID from which data is copied */
  499.     MBUF_SEG mbufSeg, /* mbuf base for <offset> */
  500.     int offset, /* relative byte offset */
  501.     caddr_t buf, /* buffer into which data is copied */
  502.     int len /* number of bytes to copy */
  503.     )
  504.     {
  505.     caddr_t buf0 = buf; /* save starting position */
  506.     int length; /* length of each copy */
  507.     /* find the starting location for copying */
  508.     if ((mbufSeg = _mbufSegFind (mbufId, mbufSeg, &offset)) == NULL)
  509. return (ERROR);
  510.     if (len < 0) /* negative = rest of chain */
  511. len = INT_MAX;
  512.     while (len && (mbufSeg != NULL)) /* while more to copy */
  513. {
  514.         length = min (len, (mbufSeg->m_len - offset)); /* num for copy */
  515.         bcopy (mtod (mbufSeg, char *) + offset, buf, length);
  516.         buf += length; /* bump to new buf position */
  517.         len -= length;
  518. mbufSeg = mbufSeg->m_next; /* bump to next mbuf in chain */
  519. offset = 0; /* no more offset */
  520. }
  521.     return ((int) buf - (int) buf0); /* return num bytes copied */
  522.     }
  523. /*******************************************************************************
  524. *
  525. * _mbufCut - cut bytes from an mbuf chain
  526. *
  527. * This routine deletes <len> bytes from <mbufId> starting at the specified
  528. * byte location.
  529. *
  530. * The starting location of deletion is specified by <mbufSeg> and <offset>.
  531. *
  532. * The number of bytes to be cut is given by <len>.  If this parameter
  533. * is negative, or is larger than the number of bytes in the chain after the
  534. * specified byte location, the rest of the chain will be deleted.
  535. * The bytes to be deleted may span more than one mbuf.  If all the bytes
  536. * in any one mbuf are deleted, then the mbuf will be returned to the
  537. * system.  No mbuf may have zero bytes left in it.  
  538. *
  539. * Deleting bytes out of the middle of an mbuf will cause the mbuf to
  540. * be split into two mbufs.  The first mbuf will contain the portion
  541. * of the mbuf before the deleted bytes, while the other mbuf will
  542. * contain the end portion that remains after <len> bytes are deleted.
  543. *
  544. * This routine returns the mbuf pointer associated with the mbuf just
  545. * after the deleted bytes.  In the case where bytes are cut off the end
  546. * of an mbuf chain, a value of MBUF_NONE is returned.
  547. *
  548. * RETURNS:
  549. * The mbuf pointer associated with the mbuf following the deleted bytes,
  550. * or NULL if the operation failed.
  551. *
  552. * NOMANUAL
  553. */
  554. MBUF_SEG _mbufCut
  555.     (
  556.     MBUF_ID mbufId, /* mbuf ID from which bytes are cut */
  557.     MBUF_SEG mbufSeg, /* mbuf base for <offset> */
  558.     int offset, /* relative byte offset */
  559.     int len /* number of bytes to cut */
  560.     )
  561.     {
  562.     MBUF_ID mbufIdNew; /* dummy ID for dup operation */
  563.     MBUF_SEG * pMbufPrev; /* mbuf prev deleted mbuf */
  564.     int length; /* length of each cut */
  565.     /* find the mbuf ptr previous to the cut */
  566.     if ((pMbufPrev = _mbufSegFindPrev (mbufId, mbufSeg, &offset)) == NULL)
  567.         return (NULL);
  568.     if ((mbufSeg = *pMbufPrev) == NULL) /* find cut mbuf */
  569. {
  570. errno = S_mbufLib_SEGMENT_NOT_FOUND;
  571. return (NULL);
  572. }
  573.     if (len < 0) /* negative = rest of chain */
  574. len = INT_MAX;
  575.     while (len && (mbufSeg != NULL)) /* while more to cut */
  576. {
  577.         length = min (len, (mbufSeg->m_len - offset)); /* num for cut */
  578.         len -= length;
  579.         if (offset != 0) /* if !cutting off front... */
  580.     {
  581.     if (mbufSeg->m_len != (offset + length))/* cut from middle*/
  582. {
  583.         /* duplicate portion remaining after bytes to be cut */
  584.                 if ((mbufIdNew = _mbufDup (mbufId, mbufSeg, offset + length,
  585.     mbufSeg->m_len - offset - length)) == NULL)
  586.             return (NULL);
  587.                 mbufIdNew->mbufHead->m_next = mbufSeg->m_next;
  588.                 mbufSeg->m_next = mbufIdNew->mbufHead;/* hook in saved data */
  589.                 mbufSeg->m_len = offset; /* shorten to later portion */
  590.                 MBUF_ID_DELETE_EMPTY(mbufIdNew);/* delete dup ID */
  591. return (mbufSeg->m_next); /* return next real mbuf */
  592. }
  593.             else /* cut to end */
  594.                 {
  595.                 mbufSeg->m_len -= length; /* decrease by len deleted */
  596. pMbufPrev = &mbufSeg->m_next; /* update previous */
  597. mbufSeg = mbufSeg->m_next; /* bump current mbuf to next */
  598. }
  599.     offset = 0; /* no more offset */
  600.     }
  601.         else /* cutting off front... */
  602.             {
  603.     if (length == mbufSeg->m_len) /* cutting whole mbuf ? */
  604. {
  605. mbufSeg = m_free (mbufSeg); /* free and get next mbuf */
  606. *pMbufPrev = mbufSeg; /* hook prev to next mbuf */
  607. }
  608.             else /* cut off front portion */
  609. {
  610. mbufSeg->m_data += length; /* bump up offset */
  611.         mbufSeg->m_len -= length; /* taken from front */
  612. }
  613.             }
  614.         }
  615.     if (mbufSeg == NULL) /* special case - cut off end */
  616. return (MBUF_NONE);
  617.     return (mbufSeg); /* return next real mbuf */
  618.     }
  619. /*******************************************************************************
  620. *
  621. * _mbufSplit - split an mbuf chain into two separate mbuf chains
  622. *
  623. * This routine splits <mbufId> into two separate chains at the specified
  624. * byte location.  The first portion remains in <mbufId>, while the end
  625. * portion is returned in a newly created mbuf ID.
  626. *
  627. * The location of the split is specified by <mbufSeg> and <offset>.
  628. *
  629. * RETURNS:
  630. * The mbuf ID of a newly created chain containing the end portion of <mbufId>,
  631. * or NULL if the operation failed.
  632. *
  633. * NOMANUAL
  634. */
  635. MBUF_ID _mbufSplit
  636.     (
  637.     MBUF_ID mbufId, /* mbuf ID to split into two */
  638.     MBUF_SEG mbufSeg, /* mbuf base for <offset> */
  639.     int offset /* relative byte offset */
  640.     )
  641.     {
  642.     MBUF_ID mbufIdNew; /* mbuf ID of later portion */
  643.     MBUF_SEG * pMbufPrev; /* mbuf prev to insert */
  644.     /* find the mbuf ptr previous to the split */
  645.     if ((pMbufPrev = _mbufSegFindPrev (mbufId, mbufSeg, &offset)) == NULL)
  646.         return (NULL);
  647.     if (offset == 0) /* in middle of mbuf */
  648. {
  649.         MBUF_ID_CREATE (mbufIdNew); /* create ID for end portion */
  650.         if (mbufIdNew == NULL)
  651.     return (NULL);
  652.         mbufIdNew->mbufHead = *pMbufPrev; /* hook in new head */
  653.         *pMbufPrev = NULL; /* tie off first portion */
  654. }
  655.     else /* split on mbuf boundary */
  656. {
  657.         mbufSeg = *pMbufPrev; /* find split mbuf */
  658.         if ((mbufIdNew = _mbufDup (mbufId, mbufSeg, offset,
  659.     mbufSeg->m_len - offset)) == NULL)
  660.     return (NULL); /* dup later portion */
  661.         mbufIdNew->mbufHead->m_next = mbufSeg->m_next;
  662.         mbufSeg->m_len = offset;
  663.         mbufSeg->m_next = NULL; /* tie off first portion */
  664. }
  665.     return (mbufIdNew); /* return ID for end */
  666.     }
  667. /*******************************************************************************
  668. *
  669. * _mbufDup - duplicate an mbuf chain
  670. *
  671. * This routine duplicates <len> bytes of <mbufId> starting at the specified
  672. * byte location, and returns the mbuf ID of the newly created duplicate mbuf.
  673. *
  674. * The starting location of duplication is specified by <mbufSeg> and <offset>.
  675. * The number of bytes to be duplicated is given by <len>.  If this
  676. * parameter is negative, or is larger than the than the number of bytes
  677. * in the chain after the specified byte location, the rest of the chain will
  678. * be duplicated.
  679. *
  680. * Duplication of mbuf data only involves copying of the data when the mbuf
  681. * is not a cluster.  If the mbuf to be duplicated is a cluster, the mbuf
  682. * pointer information is duplicated, while the data is not.  This implies
  683. * that that the mbuf data is shared among all clusters associated
  684. * with a particular cluster data buffer.
  685. *
  686. * RETURNS:
  687. * The mbuf ID of a newly created dupicate mbuf chain,
  688. * or NULL if the operation failed.
  689. *
  690. * NOMANUAL
  691. */
  692. MBUF_ID _mbufDup
  693.     (
  694.     MBUF_ID mbufId, /* mbuf ID to duplicate */
  695.     MBUF_SEG mbufSeg, /* mbuf base for <offset> */
  696.     int offset, /* relative byte offset */
  697.     int len /* number of bytes to duplicate */
  698.     )
  699.     {
  700.     MBUF_ID mbufIdNew; /* mbuf ID of duplicate */
  701.     MBUF_SEG mbufNew; /* mbuf for duplicate */
  702.     MBUF_SEG * pMbufPrev; /* mbuf prev to mbufNew */
  703.     /* find the starting location for duplicate */
  704.     if ((mbufSeg = _mbufSegFind (mbufId, mbufSeg, &offset)) == NULL)
  705.         return (NULL);
  706.     if (len < 0) /* negative = rest of chain */
  707. len = INT_MAX;
  708.     MBUF_ID_CREATE (mbufIdNew); /* get ID for duplicate */
  709.     if (mbufIdNew == NULL)
  710.         return (NULL);
  711.     pMbufPrev = &mbufIdNew->mbufHead; /* init prev ptr to head */
  712.     while (len && (mbufSeg != NULL)) /* while more to duplicate */
  713. {
  714. /* get mbuf for duplicate */
  715.         if ( (mbufNew = mBlkGet (_pNetDpool, M_WAIT, mbufSeg->m_type)) == NULL)
  716.     {
  717.     /* release on fail */
  718.     
  719.     MBUF_ID_DELETE(mbufIdNew);
  720.     return (NULL);
  721.     }
  722.         mbufNew->m_len = min (len, (mbufSeg->m_len - offset));
  723.         len -= mbufNew->m_len; /* num to duplicate */
  724. /* copy the cluster header mbuf info to duplicate */
  725. mbufNew->m_data = mtod (mbufSeg, char *)  + offset;
  726. mbufNew->m_flags = mbufSeg->m_flags;
  727. mbufNew->m_ext = mbufSeg->m_ext;
  728. /* bump share count */
  729. {
  730. int s = intLock ();
  731. ++(mbufNew->m_extRefCnt);
  732. intUnlock (s);
  733. }
  734.     
  735. *pMbufPrev = mbufNew; /* hook prev into duplicate */
  736.         pMbufPrev = &mbufNew->m_next; /* update prev mbuf ptr */
  737. mbufSeg = mbufSeg->m_next; /* bump original chain */
  738. offset = 0; /* no more offset */
  739. }
  740.     return (mbufIdNew); /* return ID of duplicate */
  741.     }
  742. /*******************************************************************************
  743. *
  744. * _mbufLength - determine the legnth in bytes of an mbuf chain
  745. *
  746. * This routine returns the number of bytes in the mbuf chain <mbufId>.
  747. *
  748. * RETURNS:
  749. * The number of bytes in the mbuf chain,
  750. * or ERROR if the operation failed
  751. *
  752. * NOMANUAL
  753. */
  754. int _mbufLength
  755.     (
  756.     MBUF_ID mbufId /* mbuf ID to find length of */
  757.     )
  758.     {
  759.     MBUF_SEG mbuf;
  760.     int length = 0; /* total length */
  761.     if (mbufId == NULL || 
  762. mbufId->type != MBUF_VALID) /* invalid ID ? */
  763. {
  764. errno = S_mbufLib_ID_INVALID;
  765. return (ERROR);
  766. }
  767.     for (mbuf = mbufId->mbufHead; mbuf != NULL; mbuf = mbuf->m_next)
  768.         length += mbuf->m_len;
  769.     return (length); /* return total length */
  770.     }
  771. #if FALSE
  772. /*******************************************************************************
  773. *
  774. * _mbufSegJoin - coalesce two adjacent mbuf cluster fragments.
  775. *
  776. * This routine combines two or more contiguous mbufs into a single
  777. * mbuf.  Such an operation is only feasible for joining mbufs
  778. * that have the same freeRtn and freeArg, and that follow eachother in
  779. * the chain.  This could be useful for coalescing mbufs fragmented
  780. * by split operations.
  781. * Not in service yet -> not clear that it is a useful routine.
  782. *
  783. * NOMANUAL
  784. */
  785. STATUS _mbufSegJoin
  786.     (
  787.     MBUF_ID mbufId, /* mbuf ID containing mbufs to join */
  788.     MBUF_SEG mbufSeg /* first mbuf to join */
  789.     )
  790.     {
  791.     MBUF_SEG mbufNext;
  792.     STATUS status = ERROR;
  793.     if (mbufId == NULL
  794. || mbufId->type != MBUF_VALID) /* invalid ID ? */
  795. {
  796. errno = S_mbufLib_ID_INVALID;
  797. return (ERROR);
  798. }
  799.     if (mbufId->mbufHead == NULL) /* is this chain empty ? */
  800.         {
  801. errno = S_mbufLib_ID_EMPTY;
  802. return (ERROR);
  803. }
  804.     if (mbufSeg == NULL) /* use head if mbuf NULL */
  805. mbufSeg = mbufId->mbufHead;
  806.     while ((mbufNext = mbufSeg->m_next) != NULL) /* join */
  807. {
  808.         if (!(M_HASCL(mbufSeg)) || !(M_HASCL(mbufNext)))
  809.     break; /* must be clusters */
  810. if ((mtod (mbufSeg, int) + mbufSeg->m_len) != (mtod (mbufNext, int)))
  811.     break; /* data must be adjacent */
  812.         /* check that mbuf params are the exact same */
  813.         if ((mbufSeg->m_type != mbufNext->m_type) ||
  814.            (mbufSeg->m_flags != mbufNext->m_flags) ||
  815.            (mbufSeg->m_extBuf != mbufNext->m_extBuf) ||
  816.            (mbufSeg->m_extRefCnt != mbufNext->m_extRefCnt) ||
  817.            (mbufSeg->m_extFreeRtn != mbufNext->m_extFreeRtn) ||
  818.            (mbufSeg->m_extArg1 != mbufNext->m_extArg1) ||
  819.            (mbufSeg->m_extArg2 != mbufNext->m_extArg2) ||
  820.            (mbufSeg->m_extArg3 != mbufNext->m_extArg3) ||
  821.            (mbufSeg->m_extSize != mbufNext->m_extSize))
  822.     break;
  823.         mbufSeg->m_len += mbufNext->m_len; /* join */
  824.         mbufSeg->m_next = m_free (mbufNext); /* bump */
  825.         status = OK;
  826. }
  827.     return (status);
  828.     }
  829. #endif /* FALSE */
  830. /*******************************************************************************
  831. *
  832. * _mbufSegFindPrev - find the mbuf prev to a specified byte location
  833. *
  834. * This routine finds the mbuf in <mbufId> that is previous to the byte
  835. * location specified by <mbufSeg> and <pOffset>.  Once found, a pointer
  836. * to the m_next pointer of that mbuf is returned by this routine,
  837. * and the offset to the specified location is returned in <pOffset>. 
  838. *
  839. * This routine is similar to _mbufSegFind(), except that a pointer to the
  840. * previous mbuf's m_next is returned by this routine, instead of the mbuf
  841. * itself.  Additionally, the end boundary case differs.  This routine will
  842. * return a valid pointer and offset when the specified byte is the byte just
  843. * past the end of the chain.  Return values for this "imaginary" byte
  844. * will also be returned when an offset of MBUF_END is passed in.
  845. *
  846. * RETURNS:
  847. * A pointer to the m_next pointer of the mbuf previous to the mbuf associated
  848. * with the mbuf containing the specified byte, or NULL if the operation failed.
  849. *
  850. * NOMANUAL
  851. */
  852. LOCAL MBUF_SEG * _mbufSegFindPrev
  853.     (
  854.     MBUF_ID mbufId, /* mbuf ID to examine */
  855.     MBUF_SEG mbufSeg, /* mbuf base for <pOffset> */
  856.     int *  pOffset /* relative byte offset */
  857.     )
  858.     {
  859.     MBUF_SEG * pMbufPrev; /* prev ptr for return */
  860.     MBUF_SEG mbuf; /* mbuf in chain */
  861.     int offset; /* offset in bytes */
  862.     int  length; /* length counter */
  863.     if (mbufId == NULL
  864. || mbufId->type != MBUF_VALID) /* invalid ID ? */
  865. {
  866. errno = S_mbufLib_ID_INVALID;
  867. return (NULL);
  868. }
  869.     pMbufPrev = &mbufId->mbufHead; /* init prev ptr to head */
  870.     if ((mbuf = mbufId->mbufHead) == NULL) /* is this chain empty ? */
  871. {
  872. if ((mbufSeg == NULL) && (*pOffset == 0))/* empty mbuf ID ? */
  873.     return (pMbufPrev); /* OK, if explicit */
  874.         else /* else error condition */
  875.     {
  876.     errno = S_mbufLib_ID_EMPTY;
  877.     return (NULL);
  878.     }
  879. }
  880.     if ((offset = *pOffset) == MBUF_BEGIN) /* shortcut to head of chain */
  881. {
  882. *pOffset = 0;
  883. return (pMbufPrev);
  884. }
  885.     else if (offset == MBUF_END) /* shortcut to end of chain */
  886. {
  887.         if (mbufSeg != NULL)
  888.     mbuf = mbufSeg; /* set base as <mbufSeg> */
  889.         for (; mbuf->m_next != NULL; mbuf = mbuf->m_next)
  890.     ; /* find last mbuf in chain */
  891.         *pOffset = 0; /* imaginary byte past mbuf */
  892.         return (&mbuf->m_next);
  893. }
  894.     else if (offset < 0) /* counting backwards ? */
  895. {
  896.         if ((mbufSeg == NULL) || (mbufSeg == mbufId->mbufHead))
  897.     {
  898.     errno = S_mbufLib_OFFSET_INVALID;
  899.     return (NULL); /* offset before head */
  900.     }
  901.         for (length = 0; (mbuf->m_next != NULL) && (mbuf->m_next != mbufSeg);
  902.     mbuf = mbuf->m_next)
  903.     {
  904.     length += mbuf->m_len; /* find length up to base */
  905.     pMbufPrev = &mbuf->m_next;
  906.     }
  907.         if (mbuf->m_next == NULL)
  908.     {
  909.     errno = S_mbufLib_SEGMENT_NOT_FOUND;
  910.     return (NULL); /* couldn't find base mbufSeg */
  911.     }
  912.         if (-(offset) < mbuf->m_len) /* within one mbuf */
  913.     {
  914.     *pOffset += mbuf->m_len;
  915.     return (pMbufPrev);
  916.     }
  917. if ((offset += length + mbuf->m_len) < 0)/* adjust to positive */
  918.     {
  919.     errno = S_mbufLib_OFFSET_INVALID;
  920.     return (NULL);
  921.     }
  922.         mbuf = mbufId->mbufHead;
  923.         pMbufPrev = &mbufId->mbufHead; /* init prev ptr to head */
  924. }
  925.     else if ((mbufSeg != NULL) && (mbufSeg != mbuf))/* new base, init head */
  926.         {
  927. if (offset < mbufSeg->m_len) /* dest within this base ? */
  928.     {
  929.     if ((mbuf = _mbufSegPrev (mbufId, mbufSeg)) != NULL)
  930.         return (&mbuf->m_next); /* located previous mbuf */
  931.             else
  932.         return (NULL);
  933.     }
  934. mbuf = mbufSeg; /* set base as <mbufSeg> */
  935. }
  936.     for (; (mbuf != NULL) && (offset >= mbuf->m_len); mbuf = mbuf->m_next)
  937. {
  938.         offset -= mbuf->m_len; /* find right mbuf in chain */
  939. pMbufPrev = &mbuf->m_next;
  940. }
  941.  
  942.     if ((mbuf == NULL) && (offset != 0))
  943. {
  944. errno = S_mbufLib_OFFSET_INVALID;
  945. return (NULL); /* too large offset */
  946. }
  947.     *pOffset = offset; /* return new offset */
  948.     return (pMbufPrev); /* return found mbuf */
  949.     }
  950. /*******************************************************************************
  951. *
  952. * _mbufSegFind - find the mbuf containing a specified byte location
  953. *
  954. * This routine finds the mbuf in <mbufId> that contains the byte location
  955. * specified by <mbufSeg> and <pOffset>.  Once found, the mbuf is returned
  956. * by this routine, and the offset to the specified location is returned
  957. * in <pOffset>. 
  958. *
  959. * <mbufSeg> determines the base from which <pOffset> is counted.
  960. * If <mbufSeg> is NULL, then <pOffset> starts from the beginning of <mbufId>.
  961. * If <mbufSeg> is not NULL, then <pOffset> starts relative to that
  962. * mbuf.  Byte locations after <mbufSeg> would be specified with a
  963. * positive offset, whereas locations previous to <mbufSeg> would be
  964. * accessed with a negative offset.
  965. *
  966. * <pOffset> is a pointer to a byte offset into the mbuf chain, with offset 0
  967. * being the first byte of data in the mbuf.  The offset does not reset
  968. * for each mbuf in the chain when counting through <mbufId>.  For example,
  969. * if offset 100 is the last byte in a particular mbuf, offset 101 will be
  970. * the first byte in the next mbuf.  Also, the offset may be a negative value.
  971. * An offset of -1 locates the last byte in the previous mbuf.  If offset -55
  972. * is the first byte in a mbuf, an offset -56 would be the last byte in the
  973. * preceding mbuf.
  974. *
  975. * The last byte in the mbuf chain may be specified by passing in an offset of
  976. * MBUF_END, which would cause this routine to return the last mbuf
  977. * in the chain, and return an offset to the last byte in that mbuf.
  978. * Likewise, an offset of MBUF_BEGIN may be passed in to specify the
  979. * first byte in the chain, causing the routine to return the first mbuf
  980. * in the chain, and return an offset of 0.
  981. *
  982. * If the <mbufSeg>, <pOffset> pair specify a byte location past the end
  983. * of the chain, or before the first byte in the chain, NULL is returned by
  984. * this routine.
  985. *
  986. * RETURNS:
  987. * An mbuf pointer associated with the mbuf containing the specified byte,
  988. * or NULL if the operation failed.
  989. *
  990. * NOMANUAL
  991. */
  992. MBUF_SEG _mbufSegFind
  993.     (
  994.     MBUF_ID mbufId, /* mbuf ID to examine */
  995.     MBUF_SEG mbufSeg, /* mbuf base for <pOffset> */
  996.     int *  pOffset /* relative byte offset */
  997.     )
  998.     {
  999.     MBUF_SEG mbuf; /* mbuf in chain */
  1000.     int offset; /* offset in bytes */
  1001.     int  length; /* length counter */
  1002.     if (mbufId == NULL
  1003. || mbufId->type != MBUF_VALID) /* invalid ID ? */
  1004. {
  1005. errno = S_mbufLib_ID_INVALID;
  1006. return (NULL);
  1007. }
  1008.     if ((mbuf = mbufId->mbufHead) == NULL) /* is this chain empty ? */
  1009. {
  1010. errno = S_mbufLib_ID_EMPTY;
  1011. return (NULL);
  1012. }
  1013.     if ((offset = *pOffset) == MBUF_BEGIN) /* shortcut to head of chain */
  1014. {
  1015. *pOffset = 0;
  1016. return (mbuf);
  1017. }
  1018.     else if (offset == MBUF_END) /* shortcut to end of chain */
  1019. {
  1020.         if (mbufSeg != NULL)
  1021.     mbuf = mbufSeg; /* set base as <mbufSeg> */
  1022.         for (; mbuf->m_next != NULL; mbuf = mbuf->m_next)
  1023.     ; /* find last mbuf in chain */
  1024.         *pOffset = mbuf->m_len - 1; /* stuff new offset */
  1025.         return (mbuf);
  1026. }
  1027.     else if (offset < 0) /* counting backwards ? */
  1028. {
  1029.         if ((mbufSeg == NULL) || (mbufSeg == mbufId->mbufHead))
  1030.     {
  1031.     errno = S_mbufLib_OFFSET_INVALID;
  1032.     return (NULL); /* offset before head */
  1033.     }
  1034.         for (length = 0; (mbuf->m_next != NULL) && (mbuf->m_next != mbufSeg);
  1035.     mbuf = mbuf->m_next)
  1036.     length += mbuf->m_len; /* find length up to base */
  1037.         if (mbuf->m_next == NULL)
  1038.     {
  1039.     errno = S_mbufLib_SEGMENT_NOT_FOUND;
  1040.     return (NULL); /* couldn't find base mbufSeg */
  1041.     }
  1042.         if (-(offset) < mbuf->m_len) /* within one mbuf */
  1043.     {
  1044.     *pOffset += mbuf->m_len;
  1045.     return (mbuf);
  1046.     }
  1047. if ((offset += length + mbuf->m_len) < 0)/* adjust to positive */
  1048.     {
  1049.     errno = S_mbufLib_OFFSET_INVALID;
  1050.     return (NULL);
  1051.     }
  1052.         mbuf = mbufId->mbufHead;
  1053. }
  1054.     else if (mbufSeg != NULL)
  1055. mbuf = mbufSeg; /* set base as <mbufSeg> */
  1056.     for (; (mbuf != NULL) && (offset >= mbuf->m_len); mbuf = mbuf->m_next)
  1057.         offset -= mbuf->m_len; /* find right mbuf in chain */
  1058.  
  1059.     if (mbuf == NULL)
  1060.         errno = S_mbufLib_OFFSET_INVALID;
  1061.     else
  1062.         *pOffset = offset; /* return new offset */
  1063.     return (mbuf); /* return found mbuf */
  1064.     }
  1065. /*******************************************************************************
  1066. *
  1067. * _mbufSegNext - get the next mbuf in an mbuf chain
  1068. *
  1069. * This routine finds the mbuf in <mbufId> that is just after the
  1070. * mbuf <mbufSeg>.  If <mbufSeg> is NULL, the mbuf after the first
  1071. * mbuf in <mbufId> is returned.  If <mbufSeg> is the last mbuf in
  1072. * <mbufId>, NULL is returned
  1073. *
  1074. * RETURNS:
  1075. * An mbuf pointer associated with the mbuf after <mbufSeg>, 
  1076. * or NULL if the operation failed.
  1077. *
  1078. * NOMANUAL
  1079. */
  1080. MBUF_SEG _mbufSegNext
  1081.     (
  1082.     MBUF_ID mbufId, /* mbuf ID to examine */
  1083.     MBUF_SEG mbufSeg /* mbuf to get next mbuf */
  1084.     )
  1085.     {
  1086.     if (mbufId == NULL
  1087. || mbufId->type != MBUF_VALID) /* invalid ID ? */
  1088. {
  1089. errno = S_mbufLib_ID_INVALID;
  1090. return (NULL);
  1091. }
  1092.     if (mbufId->mbufHead == NULL) /* is this chain empty ? */
  1093. {
  1094. errno = S_mbufLib_ID_EMPTY;
  1095. return (NULL);
  1096. }
  1097.     /* get mbuf after <mbufSeg> (or start of chain if <mbufSeg> is NULL) */
  1098.     if (mbufSeg == NULL)
  1099.         return (mbufId->mbufHead->m_next);
  1100.     else
  1101.         return (mbufSeg->m_next);
  1102.     }
  1103. /*******************************************************************************
  1104. *
  1105. * _mbufSegPrev - get the previous mbuf in an mbuf chain
  1106. *
  1107. * This routine finds the mbuf in <mbufId> that is just previous
  1108. * to the mbuf <mbufSeg>.  If <mbufSeg> is NULL, or is the first
  1109. * mbuf in <mbufId>, NULL will be returned.
  1110. *
  1111. * RETURNS:
  1112. * An mbuf pointer associated with the mbuf previous to <mbufSeg>,
  1113. * or NULL if the operation failed.
  1114. *
  1115. * NOMANUAL
  1116. */
  1117. MBUF_SEG _mbufSegPrev
  1118.     (
  1119.     MBUF_ID mbufId, /* mbuf ID to examine */
  1120.     MBUF_SEG mbufSeg /* mbuf to get previous mbuf */
  1121.     )
  1122.     {
  1123.     MBUF_SEG mbuf = mbufId->mbufHead;/* mbuf in chain */
  1124.     if (mbufId == NULL ||
  1125. mbufId->type != MBUF_VALID) /* invalid ID ? */
  1126. {
  1127. errno = S_mbufLib_ID_INVALID;
  1128. return (NULL);
  1129. }
  1130.     if ((mbufSeg == NULL) || (mbufSeg == mbuf))
  1131. return (NULL); /* no previous to first mbuf */
  1132.     /*
  1133.      * Find <mbufSeg> and return a pointer to the previous mbuf.
  1134.      * Note: OK if <mbufSeg> is not found... the return will be NULL anyway.
  1135.      */
  1136.     for (; (mbuf != NULL) && (mbuf->m_next != mbufSeg); mbuf = mbuf->m_next)
  1137. ;
  1138.     if (mbuf == NULL) /* could not find mbufSeg */
  1139. errno = S_mbufLib_SEGMENT_NOT_FOUND;
  1140.     return (mbuf);
  1141.     }
  1142. /*******************************************************************************
  1143. *
  1144. * _mbufSegData - determine the location of data in an mbuf
  1145. *
  1146. * This routine returns the location of the first byte of data in the mbuf
  1147. * <mbufSeg>.  If <mbufSeg> is NULL, the location of data in the first mbuf
  1148. * in <mbufId> is returned.
  1149. *
  1150. * RETURNS:
  1151. * A pointer to the first byte of data in the specified mbuf,
  1152. * or NULL if the mbuf chain is empty.
  1153. *
  1154. * NOMANUAL
  1155. */
  1156. caddr_t _mbufSegData
  1157.     (
  1158.     MBUF_ID mbufId, /* mbuf ID to examine  */
  1159.     MBUF_SEG mbufSeg /* mbuf to get pointer to data */
  1160.     )
  1161.     {
  1162.     if (mbufId == NULL 
  1163. || mbufId->type != MBUF_VALID) /* invalid ID ? */
  1164. {
  1165. errno = S_mbufLib_ID_INVALID;
  1166. return (NULL);
  1167. }
  1168.     if (mbufId->mbufHead == NULL) /* is this chain empty ? */
  1169. {
  1170. errno = S_mbufLib_ID_EMPTY;
  1171. return (NULL);
  1172. }
  1173.     /* get data location <mbufSeg> (or start of chain if <mbufSeg> is NULL) */
  1174.     if (mbufSeg == NULL)
  1175.         return (mtod (mbufId->mbufHead, caddr_t));
  1176.     else
  1177.         return (mtod (mbufSeg, caddr_t));
  1178.     }
  1179. /*******************************************************************************
  1180. *
  1181. * _mbufSegLength - determine the length of an mbuf
  1182. *
  1183. * This routine returns the number of bytes in the mbuf <mbufSeg>.   
  1184. * If <mbufSeg> is NULL, the length of the first mbuf in <mbufId> is
  1185. * returned. 
  1186. *
  1187. * RETURNS:
  1188. * The number of bytes in the specified mbuf, or ERROR if incorrect parameters.
  1189. *
  1190. * NOMANUAL
  1191. */
  1192. int _mbufSegLength
  1193.     (
  1194.     MBUF_ID mbufId, /* mbuf ID to examine  */
  1195.     MBUF_SEG mbufSeg /* mbuf to determine length of */
  1196.     )
  1197.     {
  1198.     if (mbufId == NULL 
  1199. || mbufId->type != MBUF_VALID) /* invalid ID ? */
  1200. {
  1201. errno = S_mbufLib_ID_INVALID;
  1202. return (ERROR);
  1203. }
  1204.     if (mbufId->mbufHead == NULL) /* is this chain empty ? */
  1205. {
  1206. if (mbufSeg == NULL) /* empty mbuf chain */
  1207.     return (0);
  1208. errno = S_mbufLib_SEGMENT_NOT_FOUND;
  1209. return (ERROR);
  1210.         }
  1211.     /* get length of <mbufSeg> (or start of chain if <mbufSeg> is NULL) */
  1212.     if (mbufSeg == NULL)
  1213. return (mbufId->mbufHead->m_len);
  1214.     else
  1215.         return (mbufSeg->m_len);
  1216.     }