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

VxWorks

开发平台:

C/C++

  1. /* loopEnd.c - software loopback END */
  2. /* Copyright 1984-1996 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /* $NetBSD: loopEnd.c,v 1.13 1994/10/30 21:48:50 cgd Exp $ */
  5. /*
  6.  * Copyright (c) 1982, 1986, 1993
  7.  * The Regents of the University of California.  All rights reserved.
  8.  *
  9.  * Redistribution and use in source and binary forms, with or without
  10.  * modification, are permitted provided that the following conditions
  11.  * are met:
  12.  * 1. Redistributions of source code must retain the above copyright
  13.  *    notice, this list of conditions and the following disclaimer.
  14.  * 2. Redistributions in binary form must reproduce the above copyright
  15.  *    notice, this list of conditions and the following disclaimer in the
  16.  *    documentation and/or other materials provided with the distribution.
  17.  * 3. All advertising materials mentioning features or use of this software
  18.  *    must display the following acknowledgement:
  19.  * This product includes software developed by the University of
  20.  * California, Berkeley and its contributors.
  21.  * 4. Neither the name of the University nor the names of its contributors
  22.  *    may be used to endorse or promote products derived from this software
  23.  *    without specific prior written permission.
  24.  *
  25.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  26.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  27.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  28.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  29.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  30.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  31.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  32.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  33.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  34.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  35.  * SUCH DAMAGE.
  36.  *
  37.  * @(#)loopEnd.c 8.1 (Berkeley) 6/10/93
  38.  */
  39. /*
  40. modification history
  41. --------------------
  42. 01k,14jan99,sut  prepended protocol information
  43. 01j,14jan99,sut  moved to tor2_0_0, renamed to loopEnd.c
  44. 01i,14jan99,sut  added routines loAddressForm, loPacketDataGet, loPacketAddrGet
  45. 01h,13jan99,sut  revoved loPollStart and loPollEnd
  46. 01g,13jan99,sut  put back again multicast support
  47. 01f,13jan99,sut  added more documentation
  48. 01e,12jan99,sut  removed ether address storage
  49. 01d,12jan99,sut  added debug routines
  50. 01c,11jan99,sut  removed multicast support
  51. 01b,11jan99,sut  converted into END driver
  52. 01a,07jan99,sut  started with netif/if_loop.c
  53. */
  54. /*
  55. DESCRIPTION
  56. This module implements the software loopback Enhanced Network  Driver (END).
  57. The only external routine is loEndLoad(), which can only be called from mux
  58. interface.
  59. The driver does not support polled mode operations. Even though the polled
  60. mode interfaces are exported to mux layer, just returns ERROR for polled mode
  61. operations.
  62. BOARD LAYOUT
  63. This device is "software only."  A jumpering diagram is not applicable.
  64. EXTERNAL INTERFACE
  65. The only external interface is the loEndLoad() routine, which expects
  66. the <initString> parameter as input.  At present this rouine expects only
  67. <unit> from this string. This parameter passes in a colon-delimited string of
  68. the format:
  69. <unit>
  70. The loEndLoad() function uses strtok() to parse the string
  71. TARGET-SPECIFIC PARAMETERS
  72. .IP <unit>
  73. A convenient holdover from the former model.  This parameter is used only
  74. in the string name for the driver.
  75. SEE ALSO: ifLib
  76. */
  77. #include "vxWorks.h"
  78. #include "stdlib.h"
  79. #include "end.h"
  80. #include "endLib.h"
  81. #include "lstLib.h"
  82. #include "wdLib.h"
  83. #include "iv.h"
  84. #include "semLib.h"
  85. #include "etherLib.h"
  86. #include "logLib.h"
  87. #include "netLib.h"
  88. #include "stdio.h"
  89. #include "sysLib.h"
  90. #include "errno.h"
  91. #include "errnoLib.h"
  92. #include "memLib.h"
  93. #include "iosLib.h"
  94. #undef ETHER_MAP_IP_MULTICAST
  95. #include "etherMultiLib.h" /* multicast stuff. */
  96. #include "net/mbuf.h"
  97. #include "net/unixLib.h"
  98. #include "net/protosw.h"
  99. #include "net/systm.h"
  100. #include "net/if_subr.h"
  101. #include "net/route.h"
  102. #include "sys/socket.h"
  103. #include "sys/ioctl.h"
  104. #include "sys/times.h"
  105. /* maximum packet size */
  106. #define LO_SPEED 10000000
  107. #define LO_MIN_FBUF 0 /* Minimum size of the first buffer in a */
  108.                          /* chain. */
  109. #define LO_ADDR_LEN 0 /* address length */
  110. #define LO_HDR_LEN  0 /* header length */
  111. /* Naming items */
  112. #define LO_DEV_NAME "lo"
  113. #define LO_DEV_NAME_LEN 3
  114. /* device states */
  115. #define LO_ST_STOPPED 0x80
  116. #define LO_IS_DEV_STOPPED(pDrvCtrl)
  117.    ((pDrvCtrl->state & LO_ST_STOPPED) == LO_ST_STOPPED)
  118. #define LO_DEV_STOP(pDrvCtrl) (pDrvCtrl->state |= LO_ST_STOPPED)
  119. #define LO_DEV_START(pDrvCtrl) (pDrvCtrl->state &= (!LO_ST_STOPPED))
  120. #define LO_PROTOCOL_LEN sizeof(USHORT)
  121. #undef DRV_DEBUG
  122. #ifdef DRV_DEBUG
  123. #define DRV_DEBUG_OFF 0x0000
  124. #define DRV_DEBUG_POLL 0x0001
  125. #define DRV_DEBUG_LOAD 0x0002
  126. #define DRV_DEBUG_IOCTL 0x0004
  127. #define DRV_DEBUG_LOG_NVRAM 0x0008
  128. #ifdef LOCAL
  129. #undef LOCAL
  130. #endif /* LOCAL */
  131. #define LOCAL ;
  132. int loDebug = DRV_DEBUG_OFF; /* Turn it off initially. */
  133. #include "nvLogLib.h"
  134. #define DRV_LOG(FLG, X0, X1, X2, X3, X4, X5, X6)                    
  135. if ((loDebug & FLG)&&(FLG & DRV_DEBUG_POLL))                
  136.             nvLogMsg(X0, X1, X2, X3, X4, X5, X6);                   
  137.         else if (loDebug & FLG)                                     
  138.             logMsg(X0, X1, X2, X3, X4, X5, X6);
  139. #define DRV_PRINT(FLG,X)                                            
  140. if (loDebug & FLG) printf X;
  141. #else /*DRV_DEBUG*/
  142. #define DRV_LOG(DBG_SW, X0, X1, X2, X3, X4, X5, X6)
  143. #define DRV_PRINT(DBG_SW,X)
  144. #endif /*DRV_DEBUG*/
  145. /* The definition of the driver control structure */
  146. #define U16 unsigned short int
  147. typedef struct lo_device
  148.     {
  149.     END_OBJ     end; /* The class we inherit from. */
  150.     int unit; /* unit number */
  151.     U16 state;
  152.     u_short     errorStat;              /* error status */
  153.     } LOEND_DEVICE;
  154. /* forward declarations */
  155. /* This is the only externally visible interface. */
  156. END_OBJ*  loEndLoad (char* initString);
  157. /* END interfaces */
  158. LOCAL STATUS loUnload (LOEND_DEVICE* pDrvCtrl);
  159. LOCAL STATUS loIoctl (LOEND_DEVICE* pDrvCtrl, int cmd, caddr_t data);
  160. LOCAL STATUS loSend (LOEND_DEVICE* pDrvCtrl, M_BLK_ID pBuf);
  161. LOCAL STATUS loStart (LOEND_DEVICE* pDrvCtrl);
  162. LOCAL STATUS loStop (LOEND_DEVICE* pDrvCtrl);
  163. LOCAL STATUS loMCastAddrAdd (LOEND_DEVICE* pDrvCtrl, char* pAddress);
  164. LOCAL STATUS loMCastAddrDel (LOEND_DEVICE* pDrvCtrl, char* pAddress);
  165. LOCAL STATUS loMCastAddrGet (LOEND_DEVICE* pDrvCtrl,
  166.     MULTI_TABLE* pTable);
  167. LOCAL STATUS loPollSend (LOEND_DEVICE* pDrvCtrl, M_BLK_ID pBuf);
  168. LOCAL STATUS loPollReceive (LOEND_DEVICE* pDrvCtrl, M_BLK_ID pBuf);
  169. M_BLK_ID loAddressForm (M_BLK_ID pMblk, M_BLK_ID pSrcAddr, M_BLK_ID pDstAddr);
  170. STATUS loPacketDataGet (M_BLK_ID pMblk, LL_HDR_INFO* pLinkHdrInfo);
  171. STATUS loPacketAddrGet (M_BLK_ID pMblk, M_BLK_ID pSrc, M_BLK_ID pDst,
  172.                         M_BLK_ID pESrc, M_BLK_ID pEDst);
  173. LOCAL STATUS loInitStringParse ();
  174. /*
  175.  * Declare our function table.  This is static across all driver
  176.  * instances.
  177.  */
  178. LOCAL NET_FUNCS loFuncTable =
  179.     {
  180.     (FUNCPTR)loStart, /* Function to start the device. */
  181.     (FUNCPTR)loStop, /* Function to stop the device. */
  182.     (FUNCPTR)loUnload, /* Unloading function for the driver. */
  183.     (FUNCPTR)loIoctl, /* Ioctl function for the driver. */
  184.     (FUNCPTR)loSend, /* Send function for the driver. */
  185.     (FUNCPTR)loMCastAddrAdd, /* Multicast address add */
  186.     (FUNCPTR)loMCastAddrDel,  /* Multicast address delete */
  187.     (FUNCPTR)loMCastAddrGet,  /* Multicast table retrieve */
  188.     (FUNCPTR)loPollSend, /* Polling send function for the driver. */
  189.     (FUNCPTR)loPollReceive, /* Polling receive function for the driver. */
  190.     loAddressForm, /* Put address info into a packet.  */
  191.     loPacketDataGet, /* Get a pointer to packet data.   */
  192.     loPacketAddrGet /* Get packet addresses.  */
  193.     };
  194. /******************************************************************************
  195. *
  196. * loEndLoad - initialize the driver and device
  197. *
  198. * This routine initializes the driver and the device to the operational state.
  199. * All of the device-specific parameters are passed in <initString>, which
  200. * expects a string of the following format:
  201. *
  202. * <unit>
  203. *
  204. * This routine can be called in two modes. If it is called with an empty but
  205. * allocated string, it places the name of this device (that is, "lo") into 
  206. * the <initString> and returns 0.
  207. *
  208. * If the string is allocated and not empty, the routine attempts to load
  209. * the driver using the values specified in the string.
  210. *
  211. * RETURNS: An END object pointer, or NULL on error, or 0 and the name of the
  212. * device if the <initString> was NULL.
  213. */
  214. END_OBJ* loEndLoad
  215.     (
  216.     char* initString /* string to be parse by the driver */
  217.     )
  218.     {
  219.     LOEND_DEVICE  *pDrvCtrl;
  220.     DRV_LOG (DRV_DEBUG_LOAD, "Loading lo...n", 1, 2, 3, 4, 5, 6);
  221.     if (initString == NULL)
  222.         return (NULL);
  223.     
  224.     if (initString[0] == NULL)
  225.         {
  226.         bcopy((char *)LO_DEV_NAME, initString, LO_DEV_NAME_LEN);
  227.         return (0);
  228.         }
  229.     
  230.     /* allocate the device structure */
  231.     pDrvCtrl = (LOEND_DEVICE *)calloc (sizeof (LOEND_DEVICE), 1);
  232.     
  233.     if (pDrvCtrl == NULL)
  234. goto errorExit;
  235.     /* parse the init string, filling in the device structure */
  236.     if (loInitStringParse (pDrvCtrl, initString) == ERROR)
  237. goto errorExit;
  238.     /* initialize the END and MIB2 parts of the structure */
  239.     if (END_OBJ_INIT (&pDrvCtrl->end, (DEV_OBJ *)pDrvCtrl, LO_DEV_NAME,
  240.     pDrvCtrl->unit, &loFuncTable,
  241.                       "Loopback Enhanced Network Driver") == ERROR
  242.      || END_MIB_INIT (&pDrvCtrl->end, M2_ifType_softwareLoopback, NULL,
  243.                       LO_ADDR_LEN, 0, LO_SPEED)
  244.                     == ERROR)
  245. goto errorExit;
  246.     /* set the flags to indicate readiness */
  247.     END_OBJ_READY (&pDrvCtrl->end,
  248.     IFF_UP | IFF_RUNNING | IFF_LOOPBACK | IFF_MULTICAST);
  249.     
  250.     DRV_LOG (DRV_DEBUG_LOAD, "Done loading lo...n", 1, 2, 3, 4, 5, 6);
  251.     return (&pDrvCtrl->end);
  252. errorExit:
  253.     if (pDrvCtrl != NULL)
  254. free ((char *)pDrvCtrl);
  255.     return NULL;
  256.     }
  257. /******************************************************************************
  258. *
  259. * loUnload - unload a driver from the system
  260. *
  261. * This function first brings down the device, and then frees any
  262. * stuff that was allocated by the driver in the load function.
  263. */
  264. LOCAL STATUS loUnload
  265.     (
  266.     LOEND_DEVICE* pDrvCtrl
  267.     )
  268.     {
  269.     END_OBJECT_UNLOAD (&pDrvCtrl->end);
  270.     return (OK);
  271.     }
  272. /*******************************************************************************
  273. *
  274. * loStart - start the device
  275. *
  276. * This function calls BSP functions to connect interrupts and start the
  277. * device running in interrupt mode.
  278. *
  279. * RETURNS: OK or ERROR
  280. *
  281. */
  282. LOCAL STATUS loStart
  283.     (
  284.     LOEND_DEVICE *pDrvCtrl
  285.     )
  286.     {
  287.     LO_DEV_START(pDrvCtrl);
  288.     return OK;
  289.     }
  290. /*******************************************************************************
  291. *
  292. * loStop - stop the device
  293. *
  294. * This function calls BSP functions to disconnect interrupts and stop
  295. * the device from operating in interrupt mode.
  296. *
  297. * RETURNS: OK or ERROR
  298. */
  299. LOCAL STATUS loStop
  300.     (
  301.     LOEND_DEVICE *pDrvCtrl
  302.     )
  303.     {
  304.     LO_DEV_STOP(pDrvCtrl);    
  305.     return OK;    
  306.     }
  307. /*******************************************************************************
  308. *
  309. * loIoctl - the driver I/O control routine
  310. *
  311. * Process an ioctl request.
  312. */
  313. LOCAL STATUS loIoctl
  314.     (
  315.     LOEND_DEVICE *pDrvCtrl,
  316.     int cmd,
  317.     caddr_t data
  318.     )
  319.     {
  320.     STATUS error = OK;
  321.     long value;
  322.     if (LO_IS_DEV_STOPPED(pDrvCtrl))
  323.         return ERROR;
  324.     switch (cmd)
  325.         {
  326.         case EIOCSADDR:
  327. return (ERROR);
  328.             break;
  329.         case EIOCGADDR:
  330. return (ERROR);
  331.             break;
  332.         case EIOCSFLAGS:
  333.     value = (long)data;
  334.     if (value < 0)
  335. {
  336. value = -value;
  337. value--; /* HELP: WHY ??? */
  338. END_FLAGS_CLR (&pDrvCtrl->end, value);
  339. }
  340.     else
  341. {
  342. END_FLAGS_SET (&pDrvCtrl->end, value);
  343. }
  344.             break;
  345.             
  346.         case EIOCGFLAGS:
  347.     *(int *)data = END_FLAGS_GET(&pDrvCtrl->end);
  348.             break;
  349. case EIOCPOLLSTART: /* fall through */ 
  350. case EIOCPOLLSTOP:
  351.     error = ERROR;            
  352.     break;
  353.         case EIOCGMIB2:
  354.             if (data == NULL)
  355.                 return (EINVAL);
  356.             bcopy((char *)&pDrvCtrl->end.mib2Tbl, (char *)data,
  357.                   sizeof(pDrvCtrl->end.mib2Tbl));
  358.             break;
  359.             
  360.         case EIOCGFBUF:
  361.             if (data == NULL)
  362.                 return (EINVAL);
  363.             *(int *)data = LO_MIN_FBUF;
  364.             break;
  365.             
  366.         case EIOCGMWIDTH:
  367.             if (data == NULL)
  368.                 return (EINVAL);
  369.             *(int *)data = 0;
  370.             break;
  371.             
  372.         case EIOCGHDRLEN:
  373.             if (data == NULL)
  374.                 return (EINVAL);
  375.             *(int *)data = LO_HDR_LEN;
  376.             break;
  377.         case EIOCMULTIADD:
  378.         case EIOCMULTIDEL:
  379.         case EIOCMULTIGET:
  380.             error = EINVAL;
  381.             break;
  382.             
  383.         default:
  384.             error = EINVAL;
  385.         }
  386.     return (error);
  387.     }
  388. /*******************************************************************************
  389. *
  390. * loSend - the driver send routine
  391. *
  392. * This routine takes a M_BLK_ID sends off the data in the M_BLK_ID.
  393. * The buffer must already have the addressing information properly installed
  394. * in it.  This is done by a higher layer.  The last arguments are a free
  395. * routine to be called when the device is done with the buffer and a pointer
  396. * to the argument to pass to the free routine.  
  397. *
  398. * RETURNS: OK or ERROR.
  399. */
  400. LOCAL STATUS loSend
  401.     (
  402.     LOEND_DEVICE *pDrvCtrl, /* device ptr */
  403.     M_BLK_ID pMblk /* data to send */
  404.     )
  405.     {
  406.     
  407.     STATUS retValue = OK;
  408.     
  409.     if (LO_IS_DEV_STOPPED(pDrvCtrl))
  410.         retValue = ERROR;
  411.     else
  412.         {
  413.         /* Bump the statistic counter. */
  414.         END_ERR_ADD (&pDrvCtrl->end, MIB2_OUT_UCAST, +1);
  415.         END_ERR_ADD (&pDrvCtrl->end, MIB2_IN_UCAST, +1);
  416.         /* Call the upper layer's receive routine. */
  417.         END_RCV_RTN_CALL(&pDrvCtrl->end, pMblk);
  418.         }
  419.         return (retValue);    
  420.     }
  421. /*******************************************************************************
  422. *
  423. * loInitStringParse - parse the initialization string
  424. *
  425. * Parse the input string.  Fill in values in the driver control structure.
  426. * The initialization string format is:
  427. * <unit>
  428. *
  429. * .IP <unit>
  430. * Device unit number, a small integer.
  431. *
  432. * RETURNS: OK, or ERROR if any arguments are invalid.
  433. */
  434. STATUS loInitStringParse
  435.     (
  436.     LOEND_DEVICE* pDrvCtrl,
  437.     char* initString
  438.     )
  439.     {
  440.     char * tok;
  441.     char * pHolder = NULL;
  442.     
  443.     /* Parse the initString */
  444.     /* Unit number. */
  445.     tok = strtok_r (initString, ":", &pHolder);
  446.     if (tok == NULL)
  447. return ERROR;
  448.     
  449.     pDrvCtrl->unit = atoi (tok);
  450.     return OK;
  451.     }
  452. /*****************************************************************************
  453. *
  454. * loMCastAddrAdd - add a multicast address for the device
  455. *
  456. * This routine adds a multicast address to whatever the driver
  457. * is already listening for.  It then resets the address filter.
  458. *
  459. * RETURNS: OK, or ERROR if fails to add
  460. */
  461. LOCAL STATUS loMCastAddrAdd
  462.     (
  463.     LOEND_DEVICE *pDrvCtrl,
  464.     char* pAddress
  465.     )
  466.     {
  467.     int error;
  468.     
  469.     error = etherMultiAdd (&pDrvCtrl->end.multiList, pAddress);
  470.     
  471.     return (error);
  472.     }
  473. /*****************************************************************************
  474. *
  475. * loMCastAddrDel - delete a multicast address for the device
  476. *
  477. * This routine removes a multicast address from whatever the driver
  478. * is listening for.  It then resets the address filter.
  479. *
  480. * RETURNS: OK, or ERROR if fails to delete
  481. */
  482. LOCAL STATUS loMCastAddrDel
  483.     (
  484.     LOEND_DEVICE* pDrvCtrl,
  485.     char* pAddress
  486.     )
  487.     {
  488.     int error;
  489.     
  490.     error = etherMultiDel (&pDrvCtrl->end.multiList, pAddress);
  491.     
  492.     return (error);
  493.     }
  494. /*****************************************************************************
  495. *
  496. * loMCastAddrGet - get the multicast address list for the device
  497. *
  498. * This routine gets the multicast list of whatever the driver
  499. * is already listening for.
  500. *
  501. * RETURNS: OK, or ERROR if fails to get
  502. *
  503. */
  504. LOCAL STATUS loMCastAddrGet
  505.     (
  506.     LOEND_DEVICE* pDrvCtrl,
  507.     MULTI_TABLE* pTable
  508.     )
  509.     {
  510.     int error;
  511.     
  512.     error = etherMultiGet (&pDrvCtrl->end.multiList, pTable);
  513.     
  514.     return (error);
  515.     }
  516. /*******************************************************************************
  517. *
  518. * loPollSend - routine to send a packet in polled mode.
  519. *
  520. * This routine is called by a user to try and send a packet on the
  521. * device.
  522. *
  523. * RETURNS: ERROR always
  524. */
  525. LOCAL STATUS loPollSend
  526.     (
  527.     LOEND_DEVICE* pDrvCtrl,
  528.     M_BLK_ID pMblk
  529.     )
  530.     {
  531.     return ERROR;    
  532.     }
  533. /*******************************************************************************
  534. *
  535. * loPollReceive - routine to receive a packet in polled mode.
  536. *
  537. * This routine is called by a user to try and get a packet from the
  538. * device.
  539. *
  540. * RETURNS: ERROR always
  541. */
  542. LOCAL STATUS loPollReceive
  543.     (
  544.     LOEND_DEVICE *pDrvCtrl,
  545.     M_BLK_ID pMblk
  546.     )
  547.     {
  548.     return ERROR;
  549.     }
  550. /******************************************************************************
  551. *
  552. * loAddressForm - form an Ethernet address into a packet
  553. *
  554. * This routine accepts the source and destination addressing information 
  555. * through <pSrcAddr> and <pDstAddr> and returns an 'M_BLK_ID' that points 
  556. * to the assembled link-level header.  To do this, this routine prepends 
  557. * the link-level header into the cluster associated with <pMblk> if there 
  558. * is enough space available in the cluster.  It then returns a pointer to 
  559. * the pointer referenced in <pMblk>.  However, if there is not enough space 
  560. * in the cluster associated with <pMblk>, this routine reserves a 
  561. * new 'mBlk'-'clBlk'-cluster construct for the header information. 
  562. * It then prepends the new 'mBlk' to the 'mBlk' passed in <pMblk>.  As the 
  563. * function value, this routine then returns a pointer to the new 'mBlk', 
  564. * which the head of a chain of 'mBlk' structures.  The second element of this 
  565. * chain is the 'mBlk' referenced in <pMblk>. 
  566. *
  567. * RETURNS: M_BLK_ID or NULL.
  568. */
  569. M_BLK_ID loAddressForm
  570.     (
  571.     M_BLK_ID pMblk,     /* pointer to packet mBlk */
  572.     M_BLK_ID pSrcAddr,  /* pointer to source address */
  573.     M_BLK_ID pDstAddr   /* pointer to destination address */
  574.     )
  575.     {
  576.     
  577.     M_PREPEND(pMblk, LO_PROTOCOL_LEN, M_DONTWAIT);
  578.     if (pMblk != NULL)
  579.         bcopy ((char *)&pDstAddr->mBlkHdr.reserved,
  580.                pMblk->m_data, LO_PROTOCOL_LEN);
  581.     return (pMblk); 
  582.     }
  583. /******************************************************************************
  584. *
  585. * loPacketDataGet - return the beginning of the packet data
  586. *
  587. * This routine fills the given <pLinkHdrInfo> with the appropriate offsets.
  588. *
  589. * RETURNS: OK or ERROR.
  590. */
  591. STATUS loPacketDataGet
  592.     (
  593.     M_BLK_ID  pMblk,
  594.     LL_HDR_INFO *  pLinkHdrInfo
  595.     )
  596.     {
  597.     pLinkHdrInfo->destAddrOffset = 0;
  598.     pLinkHdrInfo->destSize  = 0;
  599.     pLinkHdrInfo->srcAddrOffset = 0;
  600.     pLinkHdrInfo->srcSize = 0;
  601.     pLinkHdrInfo->dataOffset = LO_PROTOCOL_LEN;
  602.     bcopy (pMblk->m_data, (char *)&pLinkHdrInfo->pktType, LO_PROTOCOL_LEN);
  603.     return (OK);
  604.     }
  605. /******************************************************************************
  606. *
  607. * loPacketAddrGet - locate the addresses in a packet
  608. *
  609. * This routine takes a 'M_BLK_ID', locates the address information, and 
  610. * adjusts the M_BLK_ID structures referenced in <pSrc>, <pDst>, <pESrc>, 
  611. * and <pEDst> so that their pData members point to the addressing 
  612. * information in the packet.  The addressing information is not copied. 
  613. * All 'mBlk' structures share the same cluster.
  614. *
  615. * RETURNS: OK or ERROR.
  616. */
  617. STATUS loPacketAddrGet
  618.     (
  619.     M_BLK_ID pMblk, /* pointer to packet */
  620.     M_BLK_ID pSrc,  /* pointer to local source address */
  621.     M_BLK_ID pDst,  /* pointer to local destination address */
  622.     M_BLK_ID pESrc, /* pointer to remote source address (if any) */
  623.     M_BLK_ID pEDst  /* pointer to remote destination address (if any) */
  624.     )
  625.     {
  626.     if (pSrc != NULL)
  627.         {
  628.         pSrc->mBlkHdr.mData = NULL;
  629.         pSrc->mBlkHdr.mLen = 0;
  630.         }
  631.     if (pDst != NULL)
  632.         {
  633.         pDst->mBlkHdr.mLen = 0;
  634.         }
  635.     if (pESrc != NULL)
  636.         {
  637.         pESrc->mBlkHdr.mData = NULL;
  638.         pESrc->mBlkHdr.mLen = 0;
  639.         }
  640.     if (pEDst != NULL)
  641.         {
  642.         pEDst->mBlkHdr.mLen = 0;
  643.         }
  644.     
  645.     return (OK);
  646.     }