endLib.c
上传用户:luoyougen
上传日期:2008-05-12
资源大小:23136k
文件大小:18k
源码类别:

VxWorks

开发平台:

C/C++

  1. /* endLib.c - support library for END-based drivers */
  2. /* Copyright 1984 - 2002 Wind River Systems, Inc.  */
  3. /*
  4. modification history
  5. --------------------
  6. 01z,21jun02,wap  avoid bcopy() in endEtherAddressForm()
  7. 01y,21may02,vvv  updated mib2ErrorAdd doc (SPR #75064)
  8. 01x,17may02,rcs  added endMibIfInit() for initializing the MIB-II callback
  9.                  pointers. SPR# 77478
  10. 01w,26oct01,brk  added cast to stop compile warnings (SPR #65332)
  11. 01v,27jun01,rcs  Merg tor2.0.2 to Tornado-Comp-Drv
  12. 01u,06feb01,spm  fixed detection of 802.3 Ethernet packets (SPR #27844)
  13. 01t,16oct00,spm  merged version 01u from tor3_0_x branch (base version 01r):
  14.  adds support for link-level broadcasts and multiple snarf
  15.  protocols, and code cleanup; removes etherLib.h dependency
  16. 01s,29apr99,pul  Upgraded NPT phase3 code to tor2.0.0
  17. 01r,16mar99,spm  recovered orphaned code from tor2_0_x branch (SPR #25770)
  18. 01q,09dec98,n_s  fixed endEtherPacketDataGet to handle M_BLK chains. spr 23895
  19. 01p,18nov98,n_s  fixed end8023AddressForm. spr 22976.
  20. 01o,10dec97,gnn  made minor man page fixes
  21. 01n,08dec97,gnn  END code review fixes.
  22. 01m,17oct97,vin  changed prototypes, fixed endEtherPacketDataGet.
  23. 01k,25sep97,gnn  SENS beta feedback fixes
  24. 01j,27aug97,gnn  doc fixes and clean up.
  25. 01i,25aug97,vin  added netMblkDup in endEtherPacketDataGet().
  26. 01h,22aug97,gnn  cleaned up and improved endEtherAddrGet.
  27. 01g,19aug97,gnn  changes due to new buffering scheme.
  28.  added routine to get addresses from a packet.
  29. 01f,12aug97,gnn  changes necessitated by MUX/END update.
  30. 01e,jul3197,kbw  fixed man page problems found in beta review
  31. 01d,26feb97,gnn  Set the type of a returned M_BLK_ID correctly.
  32. 01c,05feb97,gnn  Added a check for NULL on allocation.
  33. 01b,03feb97,gnn  Added default memory management routines.
  34. 01a,26dec96,gnn  written.
  35. */
  36.   
  37. /*
  38. DESCRIPTION
  39. This library contains support routines for Enhanced Network Drivers.
  40. These routines are common to ALL ENDs.  Specialized routines should only
  41. appear in the drivers themselves.
  42. INCLUDE FILES:
  43. */
  44. /* includes */
  45. #include "vxWorks.h"
  46. #include "memLib.h"
  47. #include "netBufLib.h"
  48. #include "endLib.h"
  49. #include "end.h"
  50. #include "etherMultiLib.h"
  51. #include "bufLib.h"
  52. #include "netinet/if_ether.h"
  53. #include "memLib.h"
  54. #include "stdlib.h"
  55. /* defints */
  56. /* typedefs */
  57. /* globals */
  58. MIB_ROUTINES *  pMibRtn;    /* structure to hold MIB-II callback pointers */ 
  59. /* locals */
  60. /* forward declarations */
  61. void endRcvRtnCall
  62.     (
  63.     END_OBJ* pEnd,
  64.     M_BLK_ID pData
  65.     )
  66.     {
  67.     if (pEnd->receiveRtn) 
  68. pEnd->receiveRtn ((pEnd), pData);
  69. }
  70.     }
  71. void tkRcvRtnCall
  72.     (
  73.     END_OBJ* pEnd,
  74.     M_BLK_ID pData,
  75.     long netSvcOffset,
  76.     long netSvcType,
  77.     BOOL wrongDstInt,
  78.     void* pAsyncData
  79.     )
  80.     {
  81.     if (pEnd->receiveRtn)
  82. {
  83. pEnd->receiveRtn ((pEnd), pData, netSvcOffset , netSvcType, 
  84.   wrongDstInt, pAsyncData);
  85. }
  86.     }
  87. void endTxSemTake
  88.     (
  89.     END_OBJ* pEnd,
  90.     int tmout
  91.     ) 
  92.     {
  93.     semTake(pEnd->txSem,tmout);
  94.     }
  95. void endTxSemGive
  96.     (
  97.     END_OBJ* pEnd
  98.     )
  99.     {
  100.     semGive (pEnd->txSem);
  101.     }
  102. void endFlagsClr
  103.     (
  104.     END_OBJ* pEnd,
  105.     int clrBits
  106.     ) 
  107.     {
  108.     pEnd->flags &= ~clrBits;
  109.     }
  110. void endFlagsSet
  111.     (
  112.     END_OBJ* pEnd,
  113.     int setBits
  114.     )
  115.     {
  116.     pEnd->flags |= (setBits);
  117.     }
  118. int endFlagsGet
  119.     (
  120.     END_OBJ* pEnd
  121.     ) 
  122.     {
  123.     return(pEnd->flags);
  124.     }
  125. int endMultiLstCnt
  126.     (
  127.     END_OBJ* pEnd
  128.     )
  129.     {
  130.     return (lstCount(&pEnd->multiList));
  131.     }
  132. ETHER_MULTI* endMultiLstFirst
  133.     (
  134.     END_OBJ *pEnd
  135.     ) 
  136.     {
  137.     return ((ETHER_MULTI *)(lstFirst(&pEnd->multiList)));
  138.     }
  139. ETHER_MULTI* endMultiLstNext
  140.     (
  141.     ETHER_MULTI* pCurrent
  142.     ) 
  143.     {
  144.     return ((ETHER_MULTI *)(lstNext(&pCurrent->node)));
  145.     }
  146. char* endDevName
  147.     (
  148.     END_OBJ* pEnd
  149.     ) 
  150.     {
  151.     return(pEnd->devObject.name);
  152.     }
  153. void endObjectUnload
  154.     (
  155.     END_OBJ* pEnd
  156.     )
  157.     { 
  158.     lstFree (&pEnd->multiList); 
  159.     lstFree (&pEnd->protocols); 
  160.     }
  161. /******************************************************************************
  162. *
  163. * endMibIfInit - Initialize the MIB-II callback pointers
  164. *
  165. * This routine initializes the MIB-II pointers used by the callback macros.
  166. *
  167. * RETURNS: OK or ERROR.
  168. *
  169. * NOMANUAL
  170. */
  171. STATUS endMibIfInit
  172.     (
  173.     FUNCPTR pMibAllocRtn,
  174.     FUNCPTR pMibFreeRtn,
  175.     FUNCPTR pMibCtrUpdate,
  176.     FUNCPTR pMibVarUpdate
  177.     )
  178.     {
  179.     if ((pMibAllocRtn != NULL) && (pMibFreeRtn != NULL) && 
  180.         (pMibCtrUpdate != NULL) && (pMibVarUpdate != NULL))
  181.         {
  182.         if (pMibRtn == NULL)
  183.             {
  184.             if ((pMibRtn = (MIB_ROUTINES *)malloc (sizeof (MIB_ROUTINES))) == 
  185.                  NULL)
  186.                 {
  187.                 return(ERROR);
  188.                 }
  189.             }
  190.         pMibRtn->mibAlloc = (FUNCPTR)pMibAllocRtn;
  191.         pMibRtn->mibFree = (FUNCPTR)pMibFreeRtn;
  192.         pMibRtn->mibCntUpdate = (FUNCPTR)pMibCtrUpdate;
  193.         pMibRtn->mibVarUpdate = (FUNCPTR)pMibVarUpdate;
  194.         return(OK);
  195.         }
  196.     else
  197.         {
  198.         return(ERROR);
  199.         }
  200.     }
  201. /******************************************************************************
  202. *
  203. * mib2Init - initialize a MIB-II structure
  204. *
  205. * Initialize a MIB-II structure.  Set all error counts to zero.  Assume
  206. * a 10Mbps Ethernet device.
  207. *
  208. * RETURNS: OK or ERROR.
  209. */
  210. STATUS mib2Init
  211.     (
  212.     M2_INTERFACETBL *pMib,      /* struct to be initialized */
  213.     long ifType,                /* ifType from m2Lib.h */
  214.     UCHAR * phyAddr,            /* MAC/PHY address */
  215.     int addrLength,             /* MAC/PHY address length */
  216.     int mtuSize,                /* MTU size */
  217.     int speed                   /* interface speed */
  218.     )
  219.     {
  220.     /* Clear out our statistics. */
  221.     bzero ((char *)pMib, sizeof (*pMib));
  222.     pMib->ifPhysAddress.addrLength = addrLength;
  223.     
  224.     /* Obtain our Ethernet address and save it */
  225.     bcopy ((char *) phyAddr, (char *)pMib->ifPhysAddress.phyAddress,
  226.     pMib->ifPhysAddress.addrLength);
  227.     /* Set static statistics. assume ethernet */
  228.     pMib->ifType = ifType;
  229.     pMib->ifMtu =  mtuSize;
  230.     pMib->ifSpeed = speed;
  231.     return OK;
  232.     }
  233. /******************************************************************************
  234. *
  235. * mib2ErrorAdd - change a MIB-II error count
  236. *
  237. * This function adds a specified value to one of the MIB-II error counters in a 
  238. * MIB-II interface table.  The counter to be altered is specified by the 
  239. * errCode argument. errCode can be MIB2_IN_ERRS, MIB2_IN_UCAST, MIB2_OUT_ERRS 
  240. * or MIB2_OUT_UCAST. Specifying a negative value reduces the error count, a 
  241. * positive value increases the error count.
  242. *
  243. * RETURNS: OK or ERROR.
  244. */
  245. STATUS mib2ErrorAdd
  246.     (
  247.     M2_INTERFACETBL * pMib,
  248.     int errCode,
  249.     int value
  250.     )
  251.     {
  252.     switch (errCode)
  253. {
  254. default:
  255. case MIB2_IN_ERRS:
  256.     pMib->ifInErrors += value;
  257.     break;
  258. case MIB2_IN_UCAST:
  259.     pMib->ifInUcastPkts += value;
  260.     break;
  261. case MIB2_OUT_ERRS:
  262.     pMib->ifOutErrors += value;
  263.     break;
  264. case MIB2_OUT_UCAST:
  265.     pMib->ifOutUcastPkts += value;
  266.     break;
  267. }
  268.     
  269.     return OK;
  270.     }
  271. /*******************************************************************************
  272. *
  273. * endObjInit - initialize an END_OBJ structure
  274. *
  275. * This routine initializes an END_OBJ structure and fills it with data from 
  276. * the argument list.  It also creates and initializes semaphores and 
  277. * protocol list.
  278. *
  279. * RETURNS: OK or ERROR.
  280. */
  281. STATUS endObjInit
  282.     (
  283.     END_OBJ *   pEndObj,        /* object to be initialized */
  284.     DEV_OBJ*    pDevice,        /* ptr to device struct */
  285.     char *      pBaseName,      /* device base name, for example, "ln" */
  286.     int         unit,           /* unit number */
  287.     NET_FUNCS * pFuncTable,     /* END device functions */
  288.     char*       pDescription
  289.     )
  290.     {
  291.     pEndObj->devObject.pDevice = pDevice;
  292.     /* Create the transmit semaphore. */
  293.     pEndObj->txSem = semMCreate ( SEM_Q_PRIORITY |
  294.   SEM_DELETE_SAFE |
  295.   SEM_INVERSION_SAFE);
  296.     if (pEndObj->txSem == NULL)
  297. {
  298. return (ERROR);
  299. }
  300.     /* Install data and functions into the network node. */
  301.     pEndObj->flags = 0;
  302.     lstInit (&pEndObj->protocols);      /* Head of protocol list, */
  303. /* none yet. */
  304.     /* Check and control the length of the name string. */
  305.     if (strlen(pBaseName) > sizeof(pEndObj->devObject.name))
  306. pBaseName[sizeof(pEndObj->devObject.name - 1)] = EOS;
  307.     strcpy (pEndObj->devObject.name, pBaseName);
  308.     /* Check and control the length of the description string. */
  309.     if (strlen(pDescription) > sizeof(pEndObj->devObject.description))
  310. pDescription[sizeof(pEndObj->devObject.description - 1)] = EOS;
  311.     strcpy (pEndObj->devObject.description, pDescription);
  312.     pEndObj->devObject.unit = unit;
  313.     
  314.     pEndObj->pFuncTable = pFuncTable;
  315.     /* Clear multicast info. */
  316.     lstInit (&pEndObj->multiList);
  317.     pEndObj->nMulti = 0;
  318.     pEndObj->snarfCount = 0;
  319.     
  320.     return OK;
  321.     }
  322. /*******************************************************************************
  323. *
  324. * endObjFlagSet - set the `flags' member of an END_OBJ structure
  325. *
  326. * As input, this routine expects a pointer to an END_OBJ structure 
  327. * (the <pEnd> parameter) and a flags value (the <flags> parameter).
  328. * This routine sets the 'flags' member of the END_OBJ structure
  329. * to the value of the <flags> parameter. 
  330. *
  331. * Because this routine assumes that the driver interface is now up,  
  332. * this routine also sets the 'attached' member of the referenced END_OBJ
  333. * structure to TRUE. 
  334. *
  335. * RETURNS: OK
  336. */
  337. STATUS endObjFlagSet
  338.     (
  339.     END_OBJ * pEnd,
  340.     UINT        flags
  341.     )
  342.     {
  343.     pEnd->attached = TRUE;
  344.     pEnd->flags = flags;
  345.     return OK;
  346.     }
  347. /******************************************************************************
  348. *
  349. * end8023AddressForm - form an 802.3 address into a packet
  350. *
  351. * This routine accepts the source and destination addressing information
  352. * through <pSrcAddr> and <pDstAddr> mBlks and returns an M_BLK_ID to the
  353. * assembled link level header.  If the <bcastFlag> argument is TRUE, it
  354. * sets the destination address to the link-level broadcast address and
  355. * ignores the <pDstAddr> contents. This routine prepends the link level header
  356. * into <pMblk> if there is enough space available or it allocates a new
  357. * mBlk/clBlk/cluster and prepends the new mBlk to the mBlk chain passed in
  358. * <pMblk>.  This routine returns a pointer to an mBlk which contains the
  359. * link level header information.
  360. *
  361. * RETURNS: M_BLK_ID or NULL.
  362. *
  363. * NOMANUAL
  364. */
  365. M_BLK_ID end8023AddressForm
  366.     (
  367.     M_BLK_ID pMblk,
  368.     M_BLK_ID pSrcAddr,
  369.     M_BLK_ID pDstAddr,
  370.     BOOL bcastFlag
  371.     )
  372.     {
  373.     short dataLen;     /* length of data including LLC */
  374.     short etherType;   /* Ethernet network type code */
  375.     struct llc * pLlc; /* link layer control header */
  376.     dataLen = pMblk->mBlkPktHdr.len + LLC_SNAP_FRAMELEN;
  377.     dataLen = htons (dataLen);
  378.  
  379.     M_PREPEND(pMblk, SIZEOF_ETHERHEADER + LLC_SNAP_FRAMELEN, M_DONTWAIT);
  380.     if (pMblk != NULL)
  381. {
  382. if (bcastFlag)
  383.     bcopy ((char *)etherbroadcastaddr, pMblk->m_data, 6);
  384. else
  385.     bcopy (pDstAddr->m_data, pMblk->m_data, pDstAddr->m_len);
  386. bcopy (pSrcAddr->m_data, pMblk->m_data + pDstAddr->m_len,
  387.        pSrcAddr->m_len);
  388. bcopy ((char *) &dataLen, pMblk->m_data + pDstAddr->m_len + 
  389.        pSrcAddr->m_len, sizeof (short));
  390. /* Fill in LLC using SNAP values */
  391. pLlc = (struct llc *) (pMblk->m_data + pDstAddr->m_len + 
  392.        pSrcAddr->m_len + sizeof (short));
  393.   
  394. pLlc->llc_dsap = LLC_SNAP_LSAP;
  395. pLlc->llc_ssap = LLC_SNAP_LSAP; 
  396. pLlc->llc_un.type_snap.control = LLC_UI;
  397. bzero ((char *)pLlc->llc_un.type_snap.org_code, 
  398.        sizeof (pLlc->llc_un.type_snap.org_code));
  399. /* Enter ethernet network type code into the LLC snap field */
  400. etherType = htons (pDstAddr->mBlkHdr.reserved);
  401. bcopy ((char *) &etherType, 
  402.        (char *) &(pLlc->llc_un.type_snap.ether_type), 
  403.        sizeof (short));
  404. }
  405.     return (pMblk);
  406.     }
  407. /******************************************************************************
  408. *
  409. * endEtherAddressForm - form an Ethernet address into a packet
  410. *
  411. * This routine accepts the source and destination addressing information 
  412. * through <pSrcAddr> and <pDstAddr> and returns an 'M_BLK_ID' that points 
  413. * to the assembled link-level header.  To do this, this routine prepends 
  414. * the link-level header into the cluster associated with <pMblk> if there 
  415. * is enough space available in the cluster.  It then returns a pointer to 
  416. * the pointer referenced in <pMblk>.  However, if there is not enough space 
  417. * in the cluster associated with <pMblk>, this routine reserves a 
  418. * new 'mBlk'-'clBlk'-cluster construct for the header information. 
  419. * It then prepends the new 'mBlk' to the 'mBlk' passed in <pMblk>.  As the 
  420. * function value, this routine then returns a pointer to the new 'mBlk', 
  421. * which the head of a chain of 'mBlk' structures.  The second element of this 
  422. * chain is the 'mBlk' referenced in <pMblk>. 
  423. *
  424. * RETURNS: M_BLK_ID or NULL.
  425. */
  426. M_BLK_ID endEtherAddressForm
  427.     (
  428.     M_BLK_ID pMblk,     /* pointer to packet mBlk */
  429.     M_BLK_ID pSrcAddr,  /* pointer to source address */
  430.     M_BLK_ID pDstAddr,  /* pointer to destination address */
  431.     BOOL bcastFlag      /* use link-level broadcast? */
  432.     )
  433.     {
  434.     USHORT *pDst;
  435.     USHORT *pSrc;
  436.     M_PREPEND(pMblk, SIZEOF_ETHERHEADER, M_DONTWAIT);
  437.     /*
  438.      * This routine has been optimized somewhat in order to avoid
  439.      * the use of bcopy(). On some architectures, a bcopy() could
  440.      * result in a call into (allegedly) optimized architecture-
  441.      * specific routines. This may be fine for copying large chunks
  442.      * of data, but we're only copying 6 bytes. It's simpler just
  443.      * to open code some 16-bit assignments. The compiler would be
  444.      * hard-pressed to produce sub-optimal code for this, and it
  445.      * avoids at least one function call (possibly several).
  446.      */
  447.     if (pMblk != NULL)
  448. {
  449.         pDst = (USHORT *)pMblk->m_data;
  450. if (bcastFlag)
  451.             {
  452.             pDst[0] = 0xFFFF;
  453.             pDst[1] = 0xFFFF;
  454.             pDst[2] = 0xFFFF;
  455.             }
  456. else
  457.             {
  458.             pSrc = (USHORT *)pDstAddr->m_data;
  459.             pDst[0] = pSrc[0];
  460.             pDst[1] = pSrc[1];
  461.             pDst[2] = pSrc[2];
  462.             }
  463. /* Advance to the source address field, fill it in. */
  464.         pDst += 3;
  465.         pSrc = (USHORT *)pSrcAddr->m_data;
  466.         pDst[0] = pSrc[0];
  467.         pDst[1] = pSrc[1];
  468.         pDst[2] = pSrc[2];
  469. ((struct ether_header *)pMblk->m_data)->ether_type =
  470.     pDstAddr->mBlkHdr.reserved;
  471. }
  472.     return (pMblk);
  473.     }
  474. /******************************************************************************
  475. *
  476. * endEtherPacketDataGet - return the beginning of the packet data
  477. *
  478. * This routine fills the given <pLinkHdrInfo> with the appropriate offsets.
  479. *
  480. * RETURNS: OK or ERROR.
  481. */
  482. STATUS endEtherPacketDataGet
  483.     (
  484.     M_BLK_ID            pMblk,
  485.     LL_HDR_INFO *       pLinkHdrInfo
  486.     )
  487.     {
  488.     struct ether_header *  pEnetHdr;
  489.     struct ether_header    enetHdr;
  490.     struct llc *           pLLCHdr;
  491.     struct llc             llcHdr;
  492.     USHORT                 etherType;
  493.     pLinkHdrInfo->destAddrOffset        = 0;
  494.     pLinkHdrInfo->destSize              = 6;
  495.     pLinkHdrInfo->srcAddrOffset         = 6;
  496.     pLinkHdrInfo->srcSize               = 6;
  497.     /* Try for RFC 894 first as it's the most common. */
  498.     /* 
  499.      * make sure entire ether_header is in first M_BLK 
  500.      * if not then copy the data to a temporary buffer 
  501.      */
  502.     if (pMblk->mBlkHdr.mLen < SIZEOF_ETHERHEADER) 
  503. {
  504. pEnetHdr = &enetHdr;
  505. if (netMblkOffsetToBufCopy (pMblk, 0, (char *) pEnetHdr, 
  506.     SIZEOF_ETHERHEADER, (FUNCPTR) bcopy) 
  507.     < SIZEOF_ETHERHEADER)
  508.     {
  509.     return (ERROR);
  510.     }
  511. }
  512.     else
  513. pEnetHdr = (struct ether_header *)pMblk->mBlkHdr.mData;
  514.     etherType = ntohs(pEnetHdr->ether_type);
  515.     /* Deal with 802.3 addressing. */
  516.     /* Here is the algorithm. */
  517.     /* If the etherType is less than the MTU then we know that */
  518.     /* this is an 802.x address from RFC 1700. */
  519.     if (etherType <= ETHERMTU)
  520. {
  521. /* 
  522.  * make sure entire ether_header + llc_hdr is in first M_BLK 
  523.  * if not then copy the data to a temporary buffer 
  524.  */
  525. if (pMblk->mBlkHdr.mLen < SIZEOF_ETHERHEADER + LLC_SNAP_FRAMELEN)
  526.     {
  527.     pLLCHdr = &llcHdr;
  528.     if (netMblkOffsetToBufCopy (pMblk, SIZEOF_ETHERHEADER, 
  529. (char *) pLLCHdr, LLC_SNAP_FRAMELEN,
  530. (FUNCPTR) bcopy)
  531. < LLC_SNAP_FRAMELEN)
  532. {
  533. return (ERROR);
  534. }
  535.     }
  536. else
  537.     pLLCHdr = (struct llc *)((char *)pEnetHdr + SIZEOF_ETHERHEADER);
  538. /* Now it may be IP over 802.x so we check to see if the */
  539. /* destination SAP is IP, if so we snag the ethertype from the */
  540. /* proper place. */
  541. /* Now if it's NOT IP over 802.x then we just used the DSAP as */
  542. /* the etherType.  */
  543. if (pLLCHdr->llc_dsap == LLC_SNAP_LSAP)
  544.     {
  545.     etherType = ntohs(pLLCHdr->llc_un.type_snap.ether_type);
  546.     pLinkHdrInfo->dataOffset = SIZEOF_ETHERHEADER + 8;
  547.     }
  548. else
  549.     { /* no SNAP header */
  550.     pLinkHdrInfo->dataOffset = SIZEOF_ETHERHEADER + 3;
  551.     etherType = pLLCHdr->llc_dsap;
  552.     }
  553. }
  554.     else
  555. {
  556. pLinkHdrInfo->dataOffset        = SIZEOF_ETHERHEADER;
  557. }
  558.     pLinkHdrInfo->pktType               = etherType;
  559.     return (OK);
  560.     }
  561. /******************************************************************************
  562. *
  563. * endEtherPacketAddrGet - locate the addresses in a packet
  564. *
  565. * This routine takes a 'M_BLK_ID', locates the address information, and 
  566. * adjusts the M_BLK_ID structures referenced in <pSrc>, <pDst>, <pESrc>, 
  567. * and <pEDst> so that their pData members point to the addressing 
  568. * information in the packet.  The addressing information is not copied. 
  569. * All 'mBlk' structures share the same cluster.
  570. *
  571. * RETURNS: OK or ERROR.
  572. */
  573. STATUS endEtherPacketAddrGet
  574.     (
  575.     M_BLK_ID pMblk, /* pointer to packet */
  576.     M_BLK_ID pSrc,  /* pointer to local source address */
  577.     M_BLK_ID pDst,  /* pointer to local destination address */
  578.     M_BLK_ID pESrc, /* pointer to remote source address (if any) */
  579.     M_BLK_ID pEDst  /* pointer to remote destination address (if any) */
  580.     )
  581.     {
  582.     if (pSrc != NULL)
  583. {
  584. pSrc = netMblkDup (pMblk, pSrc);
  585. pSrc->mBlkHdr.mData += 6;
  586. pSrc->mBlkHdr.mLen = 6;
  587. }
  588.     if (pDst != NULL)
  589. {
  590. pDst = netMblkDup (pMblk, pDst);
  591. pDst->mBlkHdr.mLen = 6;
  592. }
  593.     if (pESrc != NULL)
  594. {
  595. pESrc = netMblkDup (pMblk, pESrc);
  596. pESrc->mBlkHdr.mData += 6;
  597. pESrc->mBlkHdr.mLen = 6;
  598. }
  599.     if (pEDst != NULL)
  600. {
  601. pEDst = netMblkDup (pMblk, pEDst);
  602. pEDst->mBlkHdr.mLen = 6;
  603. }
  604.     
  605.     return (OK);
  606.     }