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

VxWorks

开发平台:

C/C++

  1. /* muxLib.c - MUX network interface library */
  2. /* Copyright 1984 - 2002 Wind River Systems, Inc. */
  3. /*
  4. modification history
  5. --------------------
  6. 03z,10may02,wap  Remove unnecessary redeclaration of endList (SPR #74201)
  7. 03y,07may02,kbw  man page edits
  8. 03x,25apr02,vvv  return on muxTkBindUpdate error in muxBind (SPR #74042)
  9. 03w,22apr02,wap  Don't call muxTkUnbindUpdate() on invalid/free()'ed pointer
  10.                  (SPR #74861)
  11. 03v,05nov01,vvv  fixed compilation warnings
  12. 03u,26oct01,vvv  added NULL check for END object in muxEndFlagsNotify
  13.  (SPR #69540)
  14. 03t,15oct01,rae  merge from truestack ver 03o, base 02n(?) (SPRs 69573,70722,
  15.                  64471, 64473, 64406, 32626, ROUTER_STACK, etc.)
  16. 03s,14jun01,vvv  fixed compilation warnings
  17. 03r,08jun01,vvv  added missing closing for-loop closing bracket in 
  18.  muxReceive
  19. 03q,10apr01,rae  muxReceive only calls interested protocols (SPR #65557)
  20. 03p,09nov00,spm  removed pNptCookie from END_OBJ for binary compatibility
  21. 03o,07nov00,spm  removed nptFlag from END_OBJ for T2 END binary compatibility
  22. 03n,30oct00,kbw  putting back the NOMANUAL per request of dgross
  23. 03m,30oct00,kbw  removing NOMANUAL assignemnt to muxReceive, OK'd by GNN
  24. 03m,24oct00,niq  Merging in RFC2233 changes fron tor2_0.open_stack-f1 branch
  25.                  03n,24oct00,ann  fixed a bug in the EIOCGMCASTLIST part of
  26.                  muxIoctl
  27.                  03m,16may00,ann  merging from post R1 on openstack branch to
  28.                  incorporate RFC2233 implementation
  29.                  03k,10mar00,ead  fixed MIB-2 counter updates to use new 
  30.                  RFC 2233 m2IfLib
  31. 03l,17oct00,niq  Update pEnd->snarfCount only when protocol addition is
  32.                  complete
  33. 03k,16oct00,spm  merged from version 03a of tor3_0_x branch (base version 02n):
  34.                  adds multiple SNARF protocol support, bug fixes and cleanup,
  35.                  and backward compatibility fixes
  36. 03i,07jul99,pul  modify description for man page generation
  37. 03h,30apr99,pul  muxIoctl: check for error before calling muxEndFlagsNotify 
  38. 03g,29apr99,pul  muxPollSend: Call endpacketDataGet directly instead of 
  39.  muxPacketDataGet 
  40. 03f,29apr99,pul  Upgraded NPT phase3 code to tor2.0.0
  41. 03e,31mar99,spm  removed 40 codes from muxMCastAddrGet() entry (SPR #26268)
  42. 03d,30mar99,pul  removed all references to muxSvcFunc and muxMCastFunc
  43. 03c,25mar99,sj   detect if the end.flags actually changed before notifying all
  44. 03b,25mar99,sj   muxDevUnload does not free pEnd->devObject.pDevice + misc
  45. 03a,24mar99,sj   before calling Error,Restart or Shutdown callbacks check for
  46.                 MUX_BIND or MUX_TK_BIND
  47. 02z,19mar99,sj   no need to notify the protocol that changed the END flags
  48. 02y,18mar99,sj   in muxLibInit return status returned by muxTkBibInit
  49. 02x,18mar99,sj   added notification to protocols when END flags change
  50. 02w,05mar99,sj   eliminated hooks; not cleanly though. next version will do that
  51. 02v,03mar99,pul  fix for SPR# 24285
  52. 02u,02mar99,pul  fixed the return value for muxUnbind(): SPR# 24293
  53. 02t,13nov98,n_s  added muxDevStopAll function.  Added reboot hook in
  54.                  muxLibInit so that muxDevStop all is called prior to reboot. 
  55.                  spr #23229
  56. 02s,10nov98,sj   more doc changes for NPT
  57. 02r,03nov98,sj   added check for NPT driver in muxSend + doc fixes
  58. 02q,12oct98,pul  modified the NPT hooks for compatibility with SENS 
  59. 02p,08oct98,sj   making DOC fixes for NPT
  60. 02o,07oct98,sj   added npt hooks
  61. 02n,09sep98,ham  corrected the comprison of ifTypes and MUX_MAX_IFTYPE.
  62. 02m,09sep98,ham  cont'd SPR#22298.
  63. 02l,08sep98,ham  moved MUX_MAX_TYPE to h/muxLib.h, SPR#22298.
  64. 02k,21aug98,n_s  fixed ifInUnknownProtos update in muxReceive, ifOutNUcastPkts
  65.                  update in muxSend (). spr 21074.
  66. 02j,16jul98,n_s  Added semGive () to ERROR condition for driver unload call in
  67.                  muxDevUnload ().
  68. 02i,13jul98,n_s  fixed muxDevLoad () to limit device name strcpy () to 
  69.                  END_NAME_MAX.  spr # 21642
  70. 02h,13jul98,n_s  fixed muxBind () to clear malloc'd NET_PROTOCOL. spr # 21644
  71. 02g,24jun98,n_s  fixed muxUnbind () to check NET_PROTOCOL node for type 
  72. 02f,15jun98,n_s  fixed muxDevUnload () and muxUnbind (). spr # 21542
  73. 02e,13feb98,n_s  fixed endFindByName () to handle multiple devices. 
  74.                  spr # 21055.
  75. 02d,02feb98,spm  removed unneeded '&' operator and corrected spacing
  76. 02c,17jan98,gnn  fixed a bug in the output filter with passing LL_HDR_INFO.
  77. 02b,17jan98,gnn  changed output routines so they can be BOOL like receive
  78.                  routines.
  79. 02a,17jan98,kbw  made man page fixes
  80. 01z,14dec97,kbw  made man page fixes
  81. 01y,10dec97,kbw  made man page fixes
  82. 01x,08dec97,gnn  END code review fixes.
  83. 01w,21oct97,kbw  made man page fixes
  84. 01v,08oct97,vin  fixed muxPacketAddrGet().
  85. 01u,07oct97,vin  fixed a problem with calling muxIoctl, removed IFF_LOAN
  86. 01t,03oct97,gnn  added error routine and cleaned up function prototypes
  87. 01s,25sep97,gnn  SENS beta feedback fixes
  88. 01r,25aug97,gnn  documenatation changs to make mangen happy.
  89. 01q,25aug97,gnn  fixed a bug in the restart routine.
  90. 01p,22aug97,gnn  updated polled mode support.
  91. 01o,19aug97,gnn  changes due to new buffering scheme.
  92. 01n,12aug97,gnn  changes necessitated by MUX/END update.
  93. 01m,31jul97,kbw  fixed man page bug that broke build, comment in comment
  94. 01l,31jul97,kbw  fixed man page problems found in beta review
  95. 01k,15may97,gnn  removed many warnings.
  96.                  added code to handle MUX_PROTO_OUTPUT.
  97. 01j,30apr97,jag  man edits for funtion muxBufInit()
  98. 01i,17apr97,gnn  removed muxDevStart from muxDevLoad.
  99. 01h,07apr97,gnn  added errnoSet calls
  100.                  added muxDevNameGet.
  101.                  modified the way muxDevLoad works.
  102. 01g,12mar97,gnn  fixed a bug in muxReceive's calling API.
  103. 01f,03feb97,gnn  Modified muxBuf code to be more generic and support other,
  104.                  non-TMD systems.
  105. 01e,29jan97,gnn  Removed the code to start the tNetTask.
  106. 01d,21jan97,gnn  Added muxBuf* code to handle buffering system.
  107.                  Added code to handle the new SNARF option.
  108.                  Removed all loaning and reference counting stuff.
  109.                  Removed TxBuf stuff.
  110. 01e,23oct96,gnn  name changes to follow coding standards.
  111.                  removed some compiler warnings.
  112. 01d,22oct96,gnn  added routines to start and stop drivers.
  113.                  added code to handle buffer loaning startup requests on
  114.                  both the protocol and device side.
  115.                  replaced netVectors with netBuffers.
  116. 01c,23sep96,gnn  moved some generic code to here from the driver.
  117. 01b,22Apr96,gnn  filling in with real code.
  118. 01a,21Mar96,gnn  written.
  119. */
  120.  
  121. /*
  122. DESCRIPTION
  123. This library provides the routines that define the MUX interface, a facility
  124. that handles communication between the data link layer and the network
  125. protocol layer.  Using the MUX, the VxWorks network stack has decoupled the
  126. data link and network layers.  Drivers and services no longer need 
  127. knowledge of each other's internals.  This independence makes it much easier 
  128. to add new drivers or services.  For example, if you add a new MUX-based 
  129. "END" driver, all existing MUX-based services can use the new driver.  
  130. Likewise, if you add a new MUX-based service, any existing END can use the 
  131. MUX to access the new service.  
  132. INCLUDE FILES: errno.h, lstLib.h, logLib.h, string.h, m2Lib.h, bufLib.h, if.h,
  133. end.h, muxLib.h, vxWorks.h, taskLib.h, stdio.h, errnoLib.h, if_ether.h,
  134. netLib.h, semLib.h, rebootLib.h
  135. To use this feature, include the following component:
  136. INCLUDE_MUX
  137. SEE ALSO
  138. .I "VxWorks AE Network Programmer's Guide"
  139. */
  140. /* includes */
  141. #include "vxWorks.h"
  142. #include "taskLib.h"
  143. #include "stdio.h"
  144. #include "errno.h"
  145. #include "errnoLib.h"
  146. #include "lstLib.h"
  147. #include "logLib.h"
  148. #include "string.h"
  149. #include "m2Lib.h"
  150. #include "net/if.h" /* Needed for IFF_LOAN flag. */
  151. #include "netinet/if_ether.h"
  152. #include "netLib.h" /* Needed for netJobAdd */
  153. #include "bufLib.h"
  154. #include "semLib.h"
  155. #include "end.h"                /* Necessary for any END as well as the MUX */
  156. #include "muxLib.h"
  157. #include "muxTkLib.h"
  158. #include "private/muxLibP.h"
  159. #include "rebootLib.h"
  160. #include "memPartLib.h"
  161. #ifdef VIRTUAL_STACK 
  162. #include "netinet/vsLib.h"
  163. #endif    /* VIRTUAL_STACK */
  164. /* defines */
  165. #define STREQ(A, B) (strcmp(A, B) == 0 ? 1 : 0)
  166. #define NET_TASK_NAME "tNetTask"
  167. #define TK_DRV_CHECK(pBib) ((((MUX_ID)pBib)->flags & BIB_TK_DRV) ? TRUE : FALSE)
  168. #define GET_IFMTU(a) (((a)->flags & END_MIB_2233) ? 
  169.     (a)->pMib2Tbl->m2Data.mibIfTbl.ifMtu : (a)->mib2Tbl.ifMtu)
  170. /* externs */
  171. /* globals */
  172. /* locals */
  173. LOCAL muxLib muxLibState;
  174. LOCAL LIST endList;
  175. #ifndef STANDALONE_AGENT
  176. LOCAL LIST addrResList[MUX_MAX_IFTYPE + 1]; /* IFT_xxx begins from 1 */
  177. #endif /* STANDALONE_AGENT */
  178. /* forward declarations */
  179. LOCAL M_BLK_ID  *pMuxPollMblkRing;
  180. LOCAL void  **ppMuxPollDevices;
  181. LOCAL int  muxPollDevCount;
  182. LOCAL int  muxPollDevMax;
  183. IMPORT STATUS muxTkReceive (void *, M_BLK_ID, long, long, BOOL, void *);
  184. LOCAL void    muxEndFlagsNotify (void * pCookie, long endFlags); 
  185. LOCAL STATUS  muxDevStopAllImmediate (void);
  186. /*******************************************************************************
  187. *
  188. * muxLibInit - initialize global state for the MUX
  189. *
  190. * This routine initializes all global states for the MUX.
  191. *
  192. * RETURNS: OK or ERROR.
  193. */
  194. STATUS muxLibInit (void)
  195.     {
  196. #ifndef STANDALONE_AGENT
  197.     int count;
  198. #endif  /* STANDALONE_AGENT */
  199.     STATUS status = OK;
  200.     if (muxLibState.lock != NULL)
  201.         return (OK);
  202.     muxLibState.debug = FALSE;
  203.     muxLibState.lock = NULL;
  204.     muxLibState.mode = MUX_MODE_NORM;
  205.     muxLibState.priority = MUX_POLL_TASK_PRIORITY; /* Lame */
  206.     muxLibState.taskDelay = MUX_POLL_TASK_DELAY; /* Lame */
  207.     muxLibState.taskID = 0;
  208.     muxLibState.lock = semBCreate(SEM_Q_PRIORITY, SEM_FULL);
  209.     if (muxLibState.lock == NULL)
  210.         return (ERROR);
  211. #ifndef STANDALONE_AGENT
  212.     /*
  213.      * Initialize our lists to empty.
  214.      * addrResList[0] will not be used because IFT_xxx begins from 1
  215.      */
  216.     for (count = 0; count <= MUX_MAX_IFTYPE; count++)
  217.         lstInit (&addrResList[count]);
  218. #endif  /* STANDALONE_AGENT */
  219.     
  220.     /* initialize END list */
  221.     lstInit (&endList);
  222.     
  223.     /* Add hook to stop all ENDs when the system reboots */
  224.     if (rebootHookAdd ((FUNCPTR) muxDevStopAllImmediate) != OK)
  225. {
  226. return (ERROR);
  227. }
  228.     /* Initialize BIB. */
  229.     status = muxTkBibInit();
  230.     if (muxLibState.debug)
  231.         logMsg ("End of muxLibInitn", 0, 0, 0, 0, 0, 0);
  232.     return (status);
  233.     }
  234.     
  235. /******************************************************************************
  236. * muxDevLoad - load a driver into the MUX
  237. * The muxDevLoad() routine loads a network driver into the MUX.  Internally, 
  238. * this routine calls the specified <endLoad> routine to initialize the
  239. * software state of the device.  After the device is initialized,
  240. * you must call muxDevStart() to start the device. 
  241. * .IP <unit> 15
  242. * Expects the unit number of the device. 
  243. * .IP <endLoad> 
  244. * Expects a pointer to the network driver's endLoad() or nptLoad() entry
  245. * point. 
  246. * .IP <pInitString> 
  247. * Expects a pointer to an initialization string, typically a colon-delimited
  248. * list of options.  The muxDevLoad() routine passes this along blindly to 
  249. * the <endLoad> function.
  250. * .IP <loaning> 
  251. * Currently unused.
  252. * .IP <pBSP>
  253. * The MUX blindly passes this argument to the driver, which may or may not 
  254. * use it.  Some BSPs use this parameter to pass in tables of functions that 
  255. * the diver can use to deal with the particulars of the BSP. 
  256. *
  257. * VXWORKS AE PROTECTION DOMAINS
  258. * Under VxWorks AE, you can call muxDevLoad() from within the kernel 
  259. * protection domain only, and the data referenced in the <endLoad> and  
  260. * <pBSP> parameters must reside in the kernel protection domain.  In 
  261. * addition, the returned void pointer is valid in the kernel protection 
  262. * domain only. This restriction does not apply under non-AE versions of 
  263. * VxWorks.  
  264. * RETURNS: A cookie representing the new device, or NULL if an error occurred.
  265. *
  266. * ERRNO: S_muxLib_LOAD_FAILED
  267. */
  268. void * muxDevLoad
  269.     (
  270.     int       unit,                      /* unit number of device */
  271.     END_OBJ * (*endLoad) (char*, void*), /* load function of the driver  */
  272.     char *    pInitString,  /* init string for this driver  */
  273.     BOOL      loaning,          /* we loan buffers  */
  274.     void *    pBSP                       /* for BSP group  */
  275.     )
  276.     {
  277.     END_OBJ *     pNew;
  278.     END_TBL_ROW * pNode;
  279.     char          initString [END_INIT_STR_MAX];
  280.     char          devName [END_NAME_MAX];
  281.     BOOL          found = FALSE;
  282.     void *        pCookie = NULL;
  283.     if (muxLibState.debug)
  284.         logMsg ("Start of muxDevLoadn", 0, 0, 0, 0, 0, 0);
  285.     bzero ( (char *)initString, END_INIT_STR_MAX);
  286.     bzero ( (char *)devName, END_NAME_MAX);
  287.     /* Let's mutually exclude here, wouldn't you say? */
  288.     semTake (muxLibState.lock, WAIT_FOREVER);
  289.     
  290.     /*
  291.      * Loading a device is a two pass algorithm.
  292.      *
  293.      * This is Pass 1.
  294.      *
  295.      * In the first pass we ask the device what its name is.  If that name
  296.      * exists in our table then we add the new node to the end of the
  297.      * already existing list.  If not then we create a new row in the
  298.      * table, and place the new node as the zero'th (0) element in the node's
  299.      * list.
  300.      */
  301.     if (endLoad ( (char *)devName, NULL) != 0)
  302.         {
  303.         goto muxLoadErr;
  304.         }
  305.     if (endFindByName ( (char *)devName, unit) != NULL)
  306.         {
  307.         goto muxLoadErr;
  308.         }
  309.     for (pNode = (END_TBL_ROW *)lstFirst(&endList); pNode != NULL; 
  310. pNode = (END_TBL_ROW *)lstNext(&pNode->node))
  311. {
  312. if (STREQ (pNode->name, (char *)devName))
  313.             {
  314.             found = TRUE;
  315.             break;
  316.             }
  317. }
  318.     /*  If there is no row for this device then add it. */
  319.     
  320.     if (!found)
  321.         {
  322.         pNode = KHEAP_ALLOC (sizeof(END_TBL_ROW));
  323.         if (pNode == NULL)
  324.             {
  325.             goto muxLoadErr;
  326.             }
  327.         bzero ((char *)pNode, sizeof(END_TBL_ROW));
  328.         strncpy(pNode->name, devName, END_NAME_MAX - 1);
  329. pNode->name [END_NAME_MAX - 1] = EOS;
  330.         lstAdd(&endList, &pNode->node);
  331.         }
  332.     /*
  333.      * This is Pass 2.
  334.      *
  335.      * Now that we can determine a unique number we assign that number to
  336.      * the device and actually load it.
  337.      */
  338.     
  339.     sprintf ( (char *)initString, "%d:%s", unit, pInitString);
  340.     pNew = (END_OBJ *)endLoad ( (char *)initString, pBSP);
  341.     if (pNew == NULL)
  342.         {
  343.         goto muxLoadErr;
  344.         }
  345.     /* 
  346.      * Leave this stuff last to prevent a race condition.  The condition
  347.      * would be that the driver could call the receive routine 
  348.      * (it should always of course check to make sure there is one)
  349.      * before the buffer pool was set up.  This would be Bad.
  350.      */
  351.     lstAdd(&pNode->units, &pNew->node);
  352. #ifndef STANDALONE_AGENT
  353.     /*
  354.      * no receive routine for standalone agent (only polling mode
  355.      * is supported).
  356.      */
  357.     /* Determine if driver uses END or NPT interface. Default is END. */
  358.     pNew->receiveRtn = muxReceive;
  359.  
  360.     if (pNew->pFuncTable->ioctl)
  361.         {
  362.         if ( (pNew->pFuncTable->ioctl (pNew, EIOCGNPT, NULL)) == OK)
  363.             {
  364.             /* NPT device. */
  365.             pNew->receiveRtn = (FUNCPTR)muxTkReceive;
  366.              }
  367.         }
  368. #endif /* STANDALONE_AGENT */
  369.     pCookie = muxTkDevLoadUpdate (pNew);
  370.     if (pCookie == NULL)
  371.         {
  372.         goto muxLoadErr;
  373.         }
  374.     semGive (muxLibState.lock);
  375.     return (pCookie);
  376.     muxLoadErr:
  377.     errnoSet (S_muxLib_LOAD_FAILED);
  378.     semGive (muxLibState.lock);
  379.     return (NULL);
  380.     }
  381. /*****************************************************************************
  382. * muxDevStart - start a device by calling its start routine
  383. *
  384. * This routine starts a device that has already been initialized and loaded
  385. * into the MUX with muxDevLoad().  muxDevStart() activates the network
  386. * interfaces for a device, and calls the device's endStart() or nptStart()
  387. * routine, which registers the driver's interrupt service routine and does
  388. * whatever else is needed to allow the device to handle receiving and
  389. * transmitting.  This call to endStart() or nptStart() puts the device into
  390. * a running state. 
  391. * .IP <pCookie>
  392. * Expects the pointer returned as the function value of the muxDevLoad()
  393. * call for this device.  This pointer identifies the device.
  394. * .LP
  395. *
  396. * VXWORKS AE PROTECTION DOMAINS
  397. * Under VxWorks AE, you can call muxDevStart() from within the kernel 
  398. * protection domain only, and the data referenced in the <pCookie> 
  399. * parameter must reside in the kernel protection domain.  
  400. * This restriction does not apply under non-AE versions of VxWorks.  
  401. *
  402. * RETURNS: OK; ENETDOWN, if <pCookie> does not represent a valid device;
  403. * or ERROR, if the start routine for the device fails.
  404. *
  405. * ERRNO: S_muxLib_NO_DEVICE
  406. */
  407. STATUS muxDevStart
  408.     (
  409.     void * pCookie    /* device identifier from muxDevLoad() routine */
  410.     )
  411.     {
  412.     int       error;
  413.     END_OBJ * pEnd = PCOOKIE_TO_ENDOBJ(pCookie);
  414.     if (pEnd == NULL)
  415. {
  416.         errnoSet (S_muxLib_NO_DEVICE);
  417. error = ENETDOWN;
  418. }
  419.     else
  420. {
  421. error = pEnd->pFuncTable->start(pEnd);
  422. }
  423.     if (error == OK)
  424.         {
  425.         if (pEnd->flags & END_MIB_2233)
  426.             {
  427.             if ((pEnd->pMib2Tbl != NULL) &&
  428.                 (pEnd->pMib2Tbl->m2VarUpdateRtn != NULL))
  429.                 {
  430.                 pEnd->pMib2Tbl->m2VarUpdateRtn(pEnd->pMib2Tbl,
  431.                                                M2_varId_ifAdminStatus,
  432.                                                (void *)M2_ifAdminStatus_up);
  433.                 pEnd->pMib2Tbl->m2VarUpdateRtn(pEnd->pMib2Tbl,
  434.                                                M2_varId_ifOperStatus,
  435.                                                (void *)M2_ifOperStatus_up);
  436.                 }
  437.             }
  438.         else /* (RFC1213 style of counters is supported) XXX */
  439.             {
  440.             pEnd->mib2Tbl.ifAdminStatus = M2_ifAdminStatus_up;
  441.             pEnd->mib2Tbl.ifOperStatus = M2_ifOperStatus_up;
  442.             }
  443.         }
  444.     
  445.     return (error);
  446.     }
  447. #ifndef STANDALONE_AGENT
  448. /*****************************************************************************
  449. * muxDevStop - stop a device by calling its stop routine
  450. *
  451. * This routine stops the device specified in <pCookie>.
  452. * muxDevStop() calls the device's endStop() or nptStop() routine.
  453. * .IP <pCookie> 
  454. * Expects the cookie returned as the function value of the muxDevLoad() 
  455. * call for this device.  This cookie identifies the device.
  456. * .LP
  457. *
  458. * VXWORKS AE PROTECTION DOMAINS
  459. * Under VxWorks AE, you can call muxDevStop() from within the kernel 
  460. * protection domain only, and the data referenced in the <pCookie> 
  461. * parameter must reside in the kernel protection domain.  
  462. * This restriction does not apply under non-AE versions of VxWorks.  
  463. *
  464. * RETURNS: OK; ENETDOWN, if <pCookie> does not represent a valid device; or
  465. * ERROR, if the endStop() or nptStop() routine for the device fails.
  466. *
  467. * ERRNO: S_muxLib_NO_DEVICE
  468. */
  469. STATUS muxDevStop
  470.     (
  471.     void * pCookie    /* device identifier from muxDevLoad() routine */
  472.     )
  473.     {
  474.     int error;
  475.     END_OBJ * pEnd = PCOOKIE_TO_ENDOBJ(pCookie);
  476.     if (pEnd == NULL)
  477. {
  478.         errnoSet (S_muxLib_NO_DEVICE);
  479. error = ENETDOWN;
  480. }
  481.     else
  482. {
  483. error = pEnd->pFuncTable->stop(pEnd);
  484. }
  485.     return (error);
  486.     }
  487. /******************************************************************************
  488. *
  489. * muxShow - display configuration of devices registered with the MUX
  490. *
  491. * If the <pDevName> and <unit> arguments specify an existing device, this
  492. * routine reports the name and type of each protocol bound to it. Otherwise,
  493. * if <pDevName> is NULL, the routine displays the entire list of existing
  494. * devices and their associated protocols.
  495. *
  496. * .IP <pDevName> 
  497. * A string that contains the name of the device, or a null pointer to 
  498. * indicate "all devices."
  499. * .IP <unit> 
  500. * Specifies the unit number of the device (if <pDevName> is not a null 
  501. * pointer).
  502. *
  503. * RETURNS: N/A
  504. */
  505. void muxShow
  506.     (
  507.     char *  pDevName,  /* pointer to device name, or NULL for all */
  508.     int  unit  /* unit number for a single device */
  509.     )
  510.     {
  511.     int curr;
  512.     NET_PROTOCOL* pProto;
  513.     END_OBJ* pEnd; 
  514.     END_TBL_ROW* pNode;
  515.     
  516.     /* Display the current packet handling mode. */
  517.     printf("Current mode: ");
  518.     switch (muxLibState.mode)
  519.         {
  520.         case MUX_MODE_POLL:
  521.             printf ("POLLINGn");
  522.             break;
  523.         case MUX_MODE_NORM:
  524.             printf ("NORMALn");
  525.             break;
  526.         default:
  527.             printf ("ERROR UNKNOWN MODEn");
  528.             break;
  529.         }
  530.     
  531.     /* If the name is not NULL then find the specific interface to show. */
  532.     if (pDevName != NULL)
  533. {
  534. pEnd = endFindByName (pDevName, unit);
  535. if (pEnd == NULL)
  536.     {
  537.     printf ("Device %s unit %d not found.n", pDevName, unit);
  538.     return;
  539.     }
  540. printf ("Device: %s Unit: %dn", pEnd->devObject.name,
  541.                 pEnd->devObject.unit);
  542.         printf ("Description: %sn", pEnd->devObject.description);
  543.         /* See if there is an output protocol. */
  544.         if (pEnd->outputFilter != NULL)
  545.             {
  546.     printf ("Output protocol: Recv 0x%lxn",
  547.                     (unsigned long)pEnd->outputFilter->stackRcvRtn);
  548.             }
  549.         /* List the rest of the regular protocols for the device. */
  550. curr = 0;
  551. for (pProto = (NET_PROTOCOL *)lstFirst (&pEnd->protocols);
  552.      pProto != NULL; 
  553.      pProto = (NET_PROTOCOL *)lstNext(&pProto->node))
  554.     {
  555.     FUNCPTR netStackRcvRtn = NULL;
  556.             if (pProto->type == MUX_PROTO_OUTPUT)
  557.                 continue;
  558.     if (pProto->nptFlag)
  559.                 {
  560.                 MUX_ID muxId = (MUX_ID)pProto->pSpare;
  561.                 if (muxId)
  562.                     netStackRcvRtn = muxId->netStackRcvRtn;
  563.                 }
  564.             else
  565.                 netStackRcvRtn = pProto->stackRcvRtn;
  566.     printf ("Protocol: %stType: %ldtRecv 0x%lxtShutdown 0x%lxn", 
  567.                     pProto->name, pProto->type,
  568.                     (unsigned long)netStackRcvRtn,
  569.     (unsigned long)pProto->stackShutdownRtn);
  570.     curr++;
  571.     }
  572. }
  573.     else  /* Show ALL configured ENDs. */
  574. {
  575. for (pNode = (END_TBL_ROW *)lstFirst (&endList); pNode != NULL; 
  576.              pNode = (END_TBL_ROW *)lstNext (&pNode->node))
  577.             {
  578.             for (pEnd = (END_OBJ *)lstFirst(&pNode->units); pEnd != NULL; 
  579.                  pEnd = (END_OBJ *)lstNext(&pEnd->node))
  580.                 {
  581.                 printf ("Device: %s Unit: %dn", pEnd->devObject.name,
  582.                         pEnd->devObject.unit);
  583.                 printf ("Description: %sn", pEnd->devObject.description);
  584.                 if (pEnd->outputFilter != NULL)
  585.                     {
  586.                     printf ("Output protocol: Recv 0x%lxn",
  587.                             (unsigned long)pEnd->outputFilter->stackRcvRtn);
  588.                     }
  589.                 curr = 0;
  590.                 for (pProto = (NET_PROTOCOL *)lstFirst (&pEnd->protocols);
  591.                      pProto != NULL; 
  592.                      pProto = (NET_PROTOCOL *)lstNext (&pProto->node))
  593.                     {
  594.     FUNCPTR netStackRcvRtn = NULL;
  595.                     if (pProto->type == MUX_PROTO_OUTPUT)
  596.                         continue;
  597.             if (pProto->nptFlag)
  598.                         {
  599.                         MUX_ID muxId = (MUX_ID)pProto->pSpare;
  600.                         if (muxId)
  601.                             netStackRcvRtn = muxId->netStackRcvRtn;
  602.                         }
  603.                     else
  604.                         netStackRcvRtn = pProto->stackRcvRtn;
  605.                     printf ("Protocol: %stType: %ldtRecv 0x%lxtShutdown 0x%lxn", 
  606.                             pProto->name, pProto->type,
  607.     (unsigned long)netStackRcvRtn, 
  608.                             (unsigned long)pProto->stackShutdownRtn);
  609.                     curr++;
  610.                     }
  611.                 }
  612.     }
  613. }
  614.     }
  615. /******************************************************************************
  616. *
  617. * muxBind - create a binding between a network service and an END
  618. *
  619. * A network service uses this routine to bind to an END specified by the
  620. * <pName> and <unit> arguments (for example, ln and 0, ln and 1, or ei and 0).
  621. *
  622. * NOTE: This routine should only be used to bind to drivers that use the
  623. * old END driver callback function prototypes.  NPT drivers, or END drivers
  624. * that use the newer callback function prototypes, should use muxTkBind()
  625. * instead.  See the
  626. * .I "Network Protocol Toolkit Programmer's Guide"
  627. * for more information on when to use muxBind() and muxTkBind().
  628. *
  629. * The <type> argument assigns a network service to one of several classes.
  630. * Standard services receive the portion of incoming data associated
  631. * with <type> values from RFC 1700.  Only one service for each RFC 1700
  632. * type value may be bound to an END.
  633. *
  634. * Services with <type> MUX_PROTO_SNARF provide a mechanism for bypassing
  635. * the standard services for purposes such as firewalls. These services
  636. * will get incoming packets before any of the standard services.
  637. *
  638. * Promiscuous services with <type> MUX_PROTO_PROMISC receive any packets
  639. * not consumed by the snarf or standard services. 
  640. *
  641. * The MUX allows multiple snarf and promiscuous services but does not
  642. * coordinate between them. It simply delivers available packets to each
  643. * service in FIFO order. Services that consume packets may prevent
  644. * "downstream" services from receiving data if the desired packets overlap.
  645. *
  646. * An output service (with <type> MUX_PROTO_OUTPUT) receives outgoing data
  647. * before it is sent to the device. This service type allows two network
  648. * services to communicate directly and provides a mechanism for loop-back
  649. * testing. Only one output service is supported for each driver.
  650. *
  651. * The MUX calls the registered <stackRcvRtn> whenever it receives a packet
  652. * of the appropriate type. If that routine returns TRUE, the packet is
  653. * not offered to any remaining services (or to the driver in the case of
  654. * output services). A service (including an output service) may return
  655. * FALSE to examine a packet without consuming it. See the description of a
  656. * stackRcvRtn() in the
  657. * .I "Network Protocol Toolkit Programmer's Guide"
  658. * for additional information about the expected behavior of that routine.
  659. *
  660. * The <stackShutdownRtn> argument provides a function that the MUX can use
  661. * to shut down the service.  See the
  662. * .I "Network Protocol Toolkit Programmer's Guide"
  663. * for a description of how to write such a routine.
  664. * The <pProtoName> argument provides the name of the service as a character
  665. * string.  A service name is assigned internally if the argument is NULL.
  666. *
  667. * The <pSpare> argument registers a pointer to data defined by the service.
  668. * The MUX includes this argument in calls to the call back routines from 
  669. * this service.
  670. *
  671. * VXWORKS AE PROTECTION DOMAINS
  672. * Under VxWorks AE, you can call muxBind() from within the kernel protection 
  673. * domain only, and the data referenced in the <stackRcvRtn>, 
  674. * <stackShutdownRtn>, <stackTxRestartRtn>, <stackErrorRtn> and <pSpare> 
  675. * parameters must reside in the kernel protection domain.  In addition, the 
  676. * returned void pointer is valid in the kernel protection domain only. This 
  677. * restriction does not apply under non-AE versions of VxWorks.  
  678. *
  679. * RETURNS: A cookie identifying the binding between the service and driver;
  680. * or NULL, if an error occurred.
  681. *
  682. * ERRNO: S_muxLib_NO_DEVICE, S_muxLib_ALREADY_BOUND, S_muxLib_ALLOC_FAILED
  683. */
  684. void * muxBind
  685.     (
  686.     char * pName, /* interface name, for example, ln, ei,... */
  687.     int    unit,                /* unit number */
  688.     BOOL   (*stackRcvRtn) (void*, long, M_BLK_ID, LL_HDR_INFO *, void*),
  689.                                 /* receive function to be called. */
  690.     STATUS (*stackShutdownRtn) (void*, void*),
  691.                                 /* routine to call to shutdown the stack */
  692.     STATUS (*stackTxRestartRtn) (void*, void*),
  693.                                 /* routine to tell the stack it can transmit */
  694.     void   (*stackErrorRtn) (END_OBJ*, END_ERR*, void*),
  695.                                 /* routine to call on an error. */
  696.     long   type, /* protocol type from RFC1700 and many */
  697.         /* other sources (for example, 0x800 is IP) */
  698.     char * pProtoName, /* string name for protocol  */
  699.     void * pSpare               /* per protocol spare pointer  */
  700.     )
  701.     {
  702.     NET_PROTOCOL * pNew;
  703.     NET_PROTOCOL * pNode = NULL;
  704.     NODE *         pFinal = NULL;    /* Last snarf protocol, if any. */
  705.     END_OBJ *      pEnd; 
  706.     void *         pCookie = NULL;
  707.     /* Check to see if we have a valid device. */
  708.     pEnd = endFindByName(pName, unit);
  709.     if (pEnd == NULL)
  710.         {
  711.         errnoSet(S_muxLib_NO_DEVICE);
  712. return (NULL);
  713.         }
  714.     /* 
  715.      * Check to see if an output protocol already exists. */
  716.     if (type == MUX_PROTO_OUTPUT)
  717.         {
  718.         if (pEnd->outputFilter)
  719.             {
  720.             errnoSet(S_muxLib_ALREADY_BOUND);
  721.             return (NULL);
  722.             }
  723.         }
  724.     /*
  725.      * Get the appropriate place in the protocol list if necessary.
  726.      * For standard protocols, also check if the protocol number
  727.      * is available.
  728.      */
  729.     if (type != MUX_PROTO_PROMISC && type != MUX_PROTO_OUTPUT)
  730.         {
  731.         /* Get the first standard protocol and last snarf protocol, if any. */
  732.         if (pEnd->snarfCount)
  733.             {
  734.             pFinal = lstNth (&pEnd->protocols, pEnd->snarfCount);
  735.             pNode = (NET_PROTOCOL *)lstNext (pFinal);
  736.             }
  737.         else
  738.             pNode = (NET_PROTOCOL *)lstFirst (&pEnd->protocols);
  739.         }
  740.     if (type != MUX_PROTO_SNARF && type != MUX_PROTO_PROMISC && 
  741.             type != MUX_PROTO_OUTPUT)
  742.         {
  743.         for ( ; pNode != NULL; pNode = (NET_PROTOCOL *)lstNext (&pNode->node))
  744.             {
  745.             if (pNode->type == type)
  746.                 {
  747.                 errnoSet (S_muxLib_ALREADY_BOUND);
  748.                 return (NULL);
  749.                 }
  750.             }
  751.         }
  752.     /* Now we can allocate a new protocol structure. */
  753.     pNew = (NET_PROTOCOL *) KHEAP_ALLOC (sizeof (NET_PROTOCOL));
  754.     if (pNew == NULL)
  755. {
  756.         if (muxLibState.debug)
  757.     logMsg ("muxBind cannot allocate protocol node", 0, 0, 0, 0, 0, 0);
  758.         errnoSet (S_muxLib_ALLOC_FAILED);
  759. return (NULL);
  760. }
  761.     bzero ( (char *)pNew, sizeof (NET_PROTOCOL));
  762.     pNew->stackRcvRtn = stackRcvRtn;
  763.     if (type != MUX_PROTO_OUTPUT)
  764.         {
  765.         pNew->stackShutdownRtn = stackShutdownRtn;
  766.         pNew->stackTxRestartRtn = stackTxRestartRtn;
  767.         pNew->stackErrorRtn = stackErrorRtn;
  768.         }
  769.     pNew->pEnd = pEnd;
  770.     pNew->type = type;
  771.     pNew->nptFlag = FALSE;      /* Protocol uses original MUX prototypes. */ 
  772.     pNew->pSpare = pSpare;
  773.     
  774.     if (type != MUX_PROTO_OUTPUT)
  775.         {
  776.         if (pProtoName != NULL)
  777.     {
  778.     strncpy(pNew->name, pProtoName, 32);
  779.     }
  780.         else 
  781.     {
  782.     sprintf(pNew->name, "Protocol %d", lstCount(&pEnd->protocols));
  783.     }
  784.         }
  785.     switch (type)
  786.         {
  787.         case MUX_PROTO_OUTPUT:
  788.         case MUX_PROTO_PROMISC:
  789.             lstAdd(&pEnd->protocols, &pNew->node);
  790.             break;
  791.         default:
  792.              /* Add a standard or snarf protocol after any existing ones. */
  793.             if (pEnd->snarfCount)
  794.                 {
  795.                 lstInsert(&pEnd->protocols, pFinal, &pNew->node);
  796.                 }
  797.             else
  798.                 {
  799.                 lstInsert(&pEnd->protocols, NULL, &pNew->node);
  800.                 }
  801.             break;
  802.         }
  803.     /* update the BIB. */
  804.     if((pCookie = muxTkBindUpdate(pEnd,pNew)) == NULL)
  805. {
  806. /* unbind the protocol */
  807. lstDelete(&pEnd->protocols, &pNew->node);
  808. KHEAP_FREE((char *)pNew);
  809. return (NULL);
  810. }
  811.     else if (type == MUX_PROTO_SNARF)     /* Increase the count. */
  812.         (pEnd->snarfCount)++;
  813.     if (type == MUX_PROTO_OUTPUT)
  814.         {
  815.         pEnd->outputFilter = pNew;
  816.         pEnd->pOutputFilterSpare = pSpare;
  817.         }
  818.     pNew->pNptCookie = pCookie;
  819.     return (pCookie);
  820.     }
  821. /*****************************************************************************
  822. * muxSend - send a packet out on a network interface
  823. *
  824. * This routine transmits a packet for the service specified by <pCookie>.
  825. * You got this cookie from a previous bind call that bound the service to 
  826. * a particular interface. This muxSend() call uses this bound interface to 
  827. * transmit the packet.
  828. *
  829. * .IP <pCookie>
  830. * Expects the cookie returned from muxBind().  This cookie identifies a
  831. * particular service-to-interface binding.
  832. * .IP <pNBuff>
  833. * Expects a pointer to the buffer that contains the packet you want 
  834. * to transmit.  Before you call muxSend(), you need to put the 
  835. * addressing information at the head of the buffer.  To do this, call 
  836. * muxAddressForm(). 
  837. *
  838. * VXWORKS AE PROTECTION DOMAINS
  839. * Under VxWorks AE, you can call muxSend() from within the kernel 
  840. * protection domain only, and the data referenced in the <pCookie> and  
  841. * <pNBuff> parameters must reside in the kernel protection domain.  
  842. * This restriction does not apply under non-AE versions of VxWorks.  
  843. *
  844. * RETURNS: OK; ENETDOWN, if <pCookie> does not represent a valid binding;
  845. * or ERROR, if the driver's endSend() routine fails.
  846. *
  847. * ERRNO: S_muxLib_NO_DEVICE
  848. */
  849. STATUS muxSend
  850.     (
  851.     void *   pCookie,  /* protocol/device binding from muxBind() */
  852.     M_BLK_ID pNBuff /* data to be sent */
  853.     )
  854.     {
  855.     int            error;
  856.     END_OBJ *      pEnd;
  857.     LL_HDR_INFO    llHdrInfo; 
  858.     long           type;
  859.     NET_PROTOCOL * pOut = NULL;
  860.     pEnd = PCOOKIE_TO_ENDOBJ (pCookie);
  861.     if (pEnd == NULL)
  862. {
  863.         errnoSet (S_muxLib_NO_DEVICE);
  864. error = ENETDOWN;
  865. }
  866.     else
  867. {
  868. if (pNBuff != NULL && 
  869.     (pNBuff->mBlkHdr.mFlags & M_BCAST 
  870.      || pNBuff->mBlkHdr.mFlags & M_MCAST))
  871.     {
  872.             if (pEnd->flags & END_MIB_2233)
  873.                 {
  874.                 /*
  875.                  * Do nothing as ifOutNUcastPkts is updated by the
  876.                  * m2PktCountRtn function specified in the END object's M2_ID.
  877.                  */
  878.                 }
  879.             else /* RFC1213 style counters supported) XXX */
  880.                 {
  881.         ++(pEnd->mib2Tbl.ifOutNUcastPkts);
  882.                 }
  883.     }
  884.         if (pEnd->outputFilter)
  885.             {
  886.             pOut = pEnd->outputFilter;
  887.             if (muxPacketDataGet (pCookie, pNBuff, &llHdrInfo) == ERROR)
  888.                 return (ERROR);
  889.             type = llHdrInfo.pktType;
  890.             if (pOut->stackRcvRtn (pOut->pNptCookie, type, pNBuff, &llHdrInfo,
  891.                                    pEnd->pOutputFilterSpare) == TRUE)
  892. {
  893. return (OK);
  894. }
  895.             }
  896. error = pEnd->pFuncTable->send (pEnd, pNBuff);
  897. }
  898.     return (error);
  899.     }
  900. /*****************************************************************************
  901. * muxReceive - handle a packet from a device driver
  902. *
  903. * An END calls this routine to transfer a packet to one or more bound
  904. * services.
  905. *
  906. * NOTE: The stack receive routine installed by a protocol must not alter
  907. * the packet if it returns FALSE.
  908. *
  909. * VXWORKS AE PROTECTION DOMAINS
  910. * Under VxWorks AE, you can call muxReceive() from within the kernel 
  911. * protection domain only, and the data referenced in the <pCookie> and  
  912. * <pMblk> parameters must reside in the kernel protection domain.  
  913. * This restriction does not apply under non-AE versions of VxWorks.  
  914. *
  915. * RETURNS: OK or ERROR.
  916. *
  917. * ERRNO: S_muxLib_NO_DEVICE
  918. *
  919. * NOMANUAL
  920. */
  921. STATUS muxReceive
  922.     (
  923.     void *   pCookie,  /* device identifier from driver's load routine */
  924.     M_BLK_ID pMblk  /* buffer containing received frame */
  925.     )
  926.     {
  927.     NET_PROTOCOL *  pProto;
  928.     END_OBJ *  pEnd;
  929.     long  type;
  930.     LL_HDR_INFO   llHdrInfo; 
  931.     int  count;
  932.     pEnd = (END_OBJ *)pCookie;
  933.     if (pEnd == NULL)
  934.         {
  935.         errnoSet(S_muxLib_NO_DEVICE);
  936.         if (pMblk)
  937.             netMblkClChainFree (pMblk);
  938.         return (ERROR);
  939.         }
  940.     /* Grab a new block and parse out the header information. */
  941.     count = lstCount (&pEnd->protocols);
  942.     if (count <= 0)
  943.         {
  944.         if (pMblk)
  945.             netMblkClChainFree (pMblk);
  946.         return (ERROR);
  947.         }
  948.     pProto = (NET_PROTOCOL *)lstFirst (&pEnd->protocols); 
  949.     if (pProto == NULL)
  950.         {
  951.         if (pMblk)
  952.             netMblkClChainFree (pMblk);
  953.         return (ERROR);
  954.         }
  955.     /* Ignore incoming data if an output protocol is the only entry. */
  956.     if (count == 1 && pProto->type == MUX_PROTO_OUTPUT)
  957.         {
  958.         if (pMblk)
  959.             netMblkClChainFree (pMblk);
  960.         return (ERROR);
  961.         }
  962.     if (muxPacketDataGet (pProto->pNptCookie, pMblk, &llHdrInfo) == ERROR)
  963.         {
  964.         if (pEnd->flags & END_MIB_2233)
  965.             {
  966.             if ((pEnd->pMib2Tbl != NULL) &&
  967.                 (pEnd->pMib2Tbl->m2CtrUpdateRtn != NULL))
  968.                 {
  969.                 pEnd->pMib2Tbl->m2CtrUpdateRtn(pEnd->pMib2Tbl,
  970.                                                M2_ctrId_ifInErrors, 1);
  971.                 }
  972.             }
  973.         else /* (RFC1213 style of counters supported) */
  974.             {
  975.             pEnd->mib2Tbl.ifInErrors++;
  976.             }
  977.         if (pMblk)
  978.             netMblkClChainFree (pMblk);
  979.         return (ERROR);
  980.         }
  981.     type = llHdrInfo.pktType;
  982.     /*
  983.      * Loop through the protocol list.
  984.      * If a service's receive routine returns TRUE, it has consumed the
  985.      * packet. The receive routine must return FALSE for other services
  986.      * to see the packet.
  987.      *
  988.      * The order of services in the list (established during the bind)
  989.      * determines their priority. SNARF services have the priority over
  990.      * every other service type. PROMISC services have the lowest priority.
  991.      * If multiple SNARF or PROMISC services exist, the order is first-come,
  992.      * first-served, which could prevent some services from seeing matching
  993.      * data if an earlier entry consumes it.
  994.      */
  995.     for (;pProto != NULL; pProto = (NET_PROTOCOL *)lstNext (&pProto->node))
  996. {
  997.         if (pProto->type == MUX_PROTO_OUTPUT)    /* Ignore output service. */
  998.             continue;
  999.         /*
  1000.          * Handoff the data to any SNARF or promiscuous protocols, or to
  1001.          * a standard protocol which registered for the frame type.
  1002.          */
  1003.         if (pProto->type == MUX_PROTO_SNARF ||
  1004.             pProto->type == MUX_PROTO_PROMISC ||
  1005.             pProto->type == type)
  1006.             {
  1007.             if ( (*pProto->stackRcvRtn) (pProto->pNptCookie, type, pMblk,
  1008.                                          &llHdrInfo, pProto->pSpare) == TRUE)
  1009.                 return (OK);
  1010.             }
  1011.         }
  1012.     /* Unknown service. Free the packet. */
  1013.     if (pEnd->flags & END_MIB_2233)
  1014.         {
  1015.         if ((pEnd->pMib2Tbl != NULL) &&
  1016.             (pEnd->pMib2Tbl->m2CtrUpdateRtn != NULL))
  1017.             {
  1018.             pEnd->pMib2Tbl->m2CtrUpdateRtn(pEnd->pMib2Tbl,
  1019.                                            M2_ctrId_ifInUnknownProtos, 1);
  1020.             }
  1021.         }
  1022.     else /* (RFC1213 style counters supported) XXX */
  1023.         {
  1024.         pEnd->mib2Tbl.ifInUnknownProtos++;
  1025.         }
  1026.     
  1027.     if (pMblk)
  1028.         netMblkClChainFree (pMblk);
  1029.     
  1030.     return OK;
  1031.     }
  1032. #endif /* STANDALONE_AGENT */
  1033. /*****************************************************************************
  1034. * muxPollSend - now 'deprecated', see muxTkPollSend()
  1035. *
  1036. * This routine transmits a packet for the service specified by <pCookie>.
  1037. * You got this cookie from a previous bind call that bound the service to 
  1038. * a particular interface. This muxPollSend() call uses this bound interface 
  1039. * to transmit the packet.  The <pNBuff> argument is a buffer ('mBlk') chain 
  1040. * that contains the packet to be sent.
  1041. *
  1042. * RETURNS: OK; ENETDOWN, if <pCookie> does not represent a valid device;
  1043. * ERROR, if the device type is not recognized; or an error value from the 
  1044. * device's registered endPollSend() routine. 
  1045. *
  1046. * ERRNO: S_muxLib_NO_DEVICE
  1047. */
  1048. STATUS muxPollSend
  1049.     (
  1050.     void *   pCookie,  /* binding instance from muxBind() */
  1051.     M_BLK_ID pNBuff /* data to be sent */
  1052.     )
  1053.     {
  1054.     int            error;
  1055.     END_OBJ *      pEnd;
  1056.     LL_HDR_INFO    llHdrInfo; 
  1057.     long           type;
  1058.     NET_PROTOCOL * pOut;
  1059.     pEnd = PCOOKIE_TO_ENDOBJ (pCookie);
  1060.     if (pEnd == NULL)
  1061. {
  1062.         errnoSet (S_muxLib_NO_DEVICE);
  1063. error = ENETDOWN;
  1064. }
  1065.     else
  1066. {
  1067.         if (pEnd->outputFilter)
  1068.             {
  1069.             pOut = pEnd->outputFilter;
  1070.             if (muxPacketDataGet (pCookie, pNBuff, &llHdrInfo) == ERROR)
  1071.                 return (ERROR);
  1072.             type = llHdrInfo.pktType;
  1073.             if (pOut->stackRcvRtn (pOut->pNptCookie, type, pNBuff, &llHdrInfo,
  1074.                                    pEnd->pOutputFilterSpare) == TRUE)
  1075.                 {
  1076.                 return (OK);
  1077.                 }
  1078.             }
  1079. error = pEnd->pFuncTable->pollSend (pEnd, pNBuff);
  1080. }
  1081.     return (error);
  1082.     }
  1083. /*****************************************************************************
  1084. * muxPollReceive - now 'deprecated', see muxTkPollReceive()
  1085. *
  1086. * NOTE: This routine has been deprecated in favor of muxTkPollReceive()
  1087. *
  1088. * Upper layers can call this routine to poll for a packet.
  1089. *
  1090. * .IP <pCookie>
  1091. * Expects the cookie that was returned from muxBind().
  1092. * This cookie indicates which driver to query for available data.
  1093. *
  1094. * .IP <pNBuff>
  1095. * Expects a pointer to a buffer chain into which to receive data.
  1096. *
  1097. * VXWORKS AE PROTECTION DOMAINS
  1098. * Under VxWorks AE, you can call muxPollReceive() from within the kernel 
  1099. * protection domain only, and the data referenced in the <pCookie> and  
  1100. * <pNBuff> parameters must reside in the kernel protection domain.  
  1101. * This restriction does not apply under non-AE versions of VxWorks.  
  1102. *
  1103. * RETURNS: OK; ENETDOWN, if the <pCookie> argument does not represent a 
  1104. * loaded driver; or an error value returned from the driver's registered 
  1105. * endPollReceive() function.
  1106. *
  1107. * ERRNO: S_muxLib_NO_DEVICE
  1108. */
  1109. STATUS muxPollReceive
  1110.     (
  1111.     void *   pCookie,  /* binding instance from muxBind() */
  1112.     M_BLK_ID pNBuff /* a vector of buffers passed to us */
  1113.     )
  1114.     {
  1115.     int       error;
  1116.     END_OBJ * pEnd;
  1117.     pEnd = PCOOKIE_TO_ENDOBJ (pCookie);
  1118.     if (pEnd == NULL)
  1119. {
  1120.         errnoSet(S_muxLib_NO_DEVICE);
  1121. error = ENETDOWN;
  1122. }
  1123.     else
  1124. {
  1125. error = pEnd->pFuncTable->pollRcv (pEnd, pNBuff);
  1126. }
  1127.     return (error);
  1128.     }
  1129. /******************************************************************************
  1130. *
  1131. * muxIoctl - send control information to the MUX or to a device
  1132. *
  1133. * This routine gives the service access to the network driver's control 
  1134. * functions.  The MUX itself can implement some of the standard control
  1135. * functions, so not all commands necessarily pass down to the device.  
  1136. * Otherwise, both command and data pass to the device without modification.
  1137. *
  1138. * Typical uses of muxIoctl() include commands to start, stop, or reset the
  1139. * network interface, or to add or configure MAC and network addresses.
  1140. *
  1141. * .IP <pCookie>
  1142. * Expects the cookie returned from muxBind() or muxTkBind().  This
  1143. * cookie indicates the device to which this service is bound. 
  1144. * .IP <cmd>
  1145. * Expects a value indicating the control command you want to execute. 
  1146. * For valid <cmd> values, see the description of the endIoctl() and
  1147. * nptIoctl() routines provided in the
  1148. * .I "Network Protocol Toolkit Programmer's Guide".
  1149. * .IP <data>
  1150. * Expects the data or a pointer to the data needed to carry out the command
  1151. * specified in <cmd>. 
  1152. * VXWORKS AE PROTECTION DOMAINS
  1153. * Under VxWorks AE, you can call muxIoctl() from within the kernel 
  1154. * protection domain only, and the data referenced in the <pCookie> and  
  1155. * <data> parameters must reside in the kernel protection domain.  
  1156. * This restriction does not apply under non-AE versions of VxWorks.  
  1157. *
  1158. * RETURNS: OK; ENETDOWN, if <pCookie> does not represent a bound device;
  1159. * or ERROR, if the command fails.
  1160. *
  1161. * ERRNO: S_muxLib_NO_DEVICE
  1162. */
  1163. STATUS muxIoctl
  1164.     (
  1165.     void *  pCookie,  /* service/device binding from muxBind()/muxTkBind() */
  1166.     int     cmd, /* command to pass to ioctl */
  1167.     caddr_t data /* data need for command in cmd */
  1168.     )
  1169.     {
  1170.     int           error;
  1171.     END_OBJ *     pEnd;
  1172.     IF_SETENTRY * pIfSetentry;
  1173.     UINT32 endFlags = 0;    /* Current flag settings (before any change). */
  1174.     pEnd = PCOOKIE_TO_ENDOBJ (pCookie);
  1175.     if (pEnd == NULL)
  1176. {
  1177.         errnoSet (S_muxLib_NO_DEVICE);
  1178. error = ENETDOWN;
  1179. }
  1180.     else
  1181. {
  1182. switch ((u_int) cmd)
  1183.     {
  1184.     case EIOCMULTIADD:
  1185. error = pEnd->pFuncTable->mCastAddrAdd (pEnd, (char *)data);
  1186. break;
  1187.     case EIOCMULTIDEL:
  1188. error =
  1189.                     pEnd->pFuncTable->mCastAddrDel (pEnd, (char *)data);
  1190. break;
  1191.     case EIOCMULTIGET:
  1192. error =
  1193.                     pEnd->pFuncTable->mCastAddrGet (pEnd, (MULTI_TABLE *)data);
  1194. break;
  1195.             case EIOCGMCASTLIST:
  1196.                 *(LIST **)data = &pEnd->multiList;
  1197. error = OK;
  1198.                 break;
  1199.             case EIOCSMIB2233:
  1200.                 {
  1201.                 pIfSetentry = (IF_SETENTRY *)data;
  1202.                 /* check the four possible IF variable to set */
  1203.                 if (pIfSetentry->varToSet & M2_varId_ifAdminStatus)
  1204.                     {
  1205.                     if (pEnd->flags & END_MIB_2233)
  1206.                         {
  1207.                         if ((pEnd->pMib2Tbl != NULL) &&
  1208.                             (pEnd->pMib2Tbl->m2VarUpdateRtn != NULL))
  1209.                             {
  1210.                             pEnd->pMib2Tbl->m2VarUpdateRtn(pEnd->pMib2Tbl,
  1211.                                            M2_varId_ifAdminStatus,
  1212.                                            (void *)pIfSetentry->ifAdminStatus);
  1213.                             pEnd->pMib2Tbl->m2VarUpdateRtn(pEnd->pMib2Tbl,
  1214.                                            M2_varId_ifOperStatus,
  1215.                                            (void *)pIfSetentry->ifAdminStatus);
  1216.                             }
  1217.                         }
  1218.                     else /* (RFC1213 style of counters supported) XXX */
  1219.                         {
  1220.                         pEnd->mib2Tbl.ifAdminStatus =
  1221.                             pIfSetentry->ifAdminStatus;
  1222.                         pEnd->mib2Tbl.ifOperStatus =
  1223.                             pIfSetentry->ifAdminStatus;
  1224.                         }
  1225.                     }
  1226.                 if ((pEnd->flags & END_MIB_2233) &&
  1227.                     (pEnd->pMib2Tbl != NULL) &&
  1228.                     (pEnd->pMib2Tbl->m2VarUpdateRtn != NULL) &&
  1229.                     (pIfSetentry->varToSet & M2_varId_ifLinkUpDownTrapEnable))
  1230.                     {
  1231.                     pEnd->pMib2Tbl->m2VarUpdateRtn(pEnd->pMib2Tbl,
  1232.                                   M2_varId_ifLinkUpDownTrapEnable,
  1233.                                   (void *)pIfSetentry->ifLinkUpDownTrapEnable);
  1234.                     }
  1235.                 if ((pEnd->flags & END_MIB_2233) &&
  1236.                     (pEnd->pMib2Tbl != NULL) &&
  1237.                     (pEnd->pMib2Tbl->m2VarUpdateRtn != NULL) &&
  1238.                     (pIfSetentry->varToSet & M2_varId_ifPromiscuousMode))
  1239.                     {
  1240.                     pEnd->pMib2Tbl->m2VarUpdateRtn(pEnd->pMib2Tbl,
  1241.                                   M2_varId_ifLinkUpDownTrapEnable,
  1242.                                   (void *)pIfSetentry->ifLinkUpDownTrapEnable);
  1243.                     }
  1244.                 if ((pEnd->flags & END_MIB_2233) &&
  1245.                     (pEnd->pMib2Tbl != NULL) &&
  1246.                     (pEnd->pMib2Tbl->m2VarUpdateRtn != NULL) &&
  1247.                     (pIfSetentry->varToSet & M2_varId_ifAlias))
  1248.                     {
  1249.                     pEnd->pMib2Tbl->m2VarUpdateRtn(pEnd->pMib2Tbl,
  1250.                                                  M2_varId_ifAlias,
  1251.                                                  (void *)pIfSetentry->ifAlias);
  1252.                     }
  1253.                 error = OK;
  1254.                 break;
  1255.                 }
  1256.     case EIOCSFLAGS:
  1257. endFlags = pEnd->flags;
  1258. /* fall-through */
  1259.     default:
  1260. error = pEnd->pFuncTable->ioctl (pEnd, cmd, data);
  1261.                 break;
  1262.     }
  1263.         /* All services must be notified if the device flags change. */
  1264.         if (cmd == (int) EIOCSFLAGS && error == OK && (endFlags ^ pEnd->flags))
  1265.             {
  1266.             netJobAdd ( (FUNCPTR)muxEndFlagsNotify, (int)pCookie,
  1267.                        (int)pEnd->flags, 0, 0, 0);
  1268.             }
  1269.         }
  1270.     return (error);
  1271.     }
  1272. #ifndef STANDALONE_AGENT
  1273. /******************************************************************************
  1274. *
  1275. * muxMCastAddrAdd - add a multicast address to a device's multicast table 
  1276. *
  1277. * This routine adds an address to the multicast table maintained by a device. 
  1278. * This routine calls the driver's endMCastAddrAdd() or nptMCastAddrAdd()
  1279. * routine to accomplish this.
  1280. * If the device does not support multicasting, muxMCastAddrAdd() will return
  1281. * ERROR and 'errno' will be set to ENOTSUP (assuming the driver has been
  1282. * written properly).
  1283. *
  1284. * .IP <pCookie> 13
  1285. * Expects the cookie returned from the muxBind() or muxTkBind() call.  This
  1286. * cookie identifies the device to which the MUX has bound this service. 
  1287. *
  1288. * .IP <pAddress>
  1289. * Expects a pointer to a character string containing the address you 
  1290. * want to add. 
  1291. * VXWORKS AE PROTECTION DOMAINS
  1292. * Under VxWorks AE, you can call muxMCastAddrAdd() from within the kernel 
  1293. * protection domain only, and the data referenced in the <pCookie> 
  1294. * parameter must reside in the kernel protection domain.  
  1295. * This restriction does not apply under non-AE versions of VxWorks.  
  1296. *
  1297. * RETURNS: OK; ENETDOWN, if <pCookie> does not represent a valid device;
  1298. * or ERROR, if the device's endMCastAddrAdd() function fails.
  1299. *
  1300. * ERRNO: S_muxLib_NO_DEVICE
  1301. *
  1302. */
  1303. STATUS muxMCastAddrAdd
  1304.     (
  1305.     void * pCookie,  /* binding instance from muxBind() or muxTkBind() */
  1306.     char * pAddress /* address to add to the table */
  1307.     )
  1308.     {
  1309.     int       error;
  1310.     END_OBJ * pEnd;
  1311.     pEnd = PCOOKIE_TO_ENDOBJ (pCookie);
  1312.     if (pEnd == NULL)
  1313. {
  1314.         errnoSet (S_muxLib_NO_DEVICE);
  1315. error = ENETDOWN;
  1316. }
  1317.     else 
  1318. {
  1319. error = pEnd->pFuncTable->mCastAddrAdd (pEnd, pAddress);
  1320. }
  1321.     return (error);
  1322.     }
  1323. /******************************************************************************
  1324. *
  1325. * muxMCastAddrDel - delete a multicast address from a device's multicast table
  1326. *
  1327. * This routine deletes an address from the multicast table maintained by a 
  1328. * device by calling that device's endMCastAddrDel() or nptMCastAddrDel()
  1329. * routine.
  1330. *
  1331. * If the device does not support multicasting, muxMCastAddrAdd() will return
  1332. * ERROR and 'errno' will be set to ENOTSUP (assuming the driver has been
  1333. * written properly).
  1334. *
  1335. * .IP <pCookie> 13
  1336. * Expects the cookie returned from muxBind() or muxTkBind() call.  This
  1337. * cookie identifies the device to which the MUX bound this service. 
  1338. * .IP <pAddress>
  1339. * Expects a pointer to a character string containing the address you 
  1340. * want to delete. 
  1341. *
  1342. * VXWORKS AE PROTECTION DOMAINS
  1343. * Under VxWorks AE, you can call muxMCastAddrDell() from within the kernel 
  1344. * protection domain only, and the data referenced in the <pCookie> 
  1345. * parameter must reside in the kernel protection domain.  
  1346. * This restriction does not apply under non-AE versions of VxWorks.  
  1347. *
  1348. * RETURNS: OK; ENETDOWN, if <pCookie> does not represent a valid driver;
  1349. * or ERROR, if the driver's registered endMCastAddrDel() or nptMCastAddrDel() 
  1350. * functions fail.
  1351. *
  1352. * ERRNO: S_muxLib_NO_DEVICE
  1353. */
  1354. STATUS muxMCastAddrDel
  1355.     (
  1356.     void * pCookie,  /* binding instance from muxBind() or muxTkBind() */
  1357.     char * pAddress     /* Address to delete from the table. */
  1358.     )
  1359.     {
  1360.     int       error;
  1361.     END_OBJ * pEnd;
  1362.     pEnd = PCOOKIE_TO_ENDOBJ (pCookie);
  1363.     if (pEnd == NULL)
  1364. {
  1365.         errnoSet (S_muxLib_NO_DEVICE);
  1366. error = ENETDOWN;
  1367. }
  1368.     else 
  1369. {
  1370. error = pEnd->pFuncTable->mCastAddrDel (pEnd, pAddress);
  1371. }
  1372.     return (error);
  1373.     }
  1374. /******************************************************************************
  1375. *
  1376. * muxMCastAddrGet - get the multicast address table from the MUX/Driver
  1377. *
  1378. * This routine writes the list of multicast addresses for a specified
  1379. * device into a buffer.  To get this list, it calls the driver's own
  1380. * endMCastAddrGet() or nptMCastAddrGet() routine. 
  1381. *
  1382. * .IP <pCookie>
  1383. * Expects the cookie returned from muxBind() or muxTkBind()
  1384. * call.  This cookie indicates the device to which the MUX
  1385. * has bound this service. 
  1386. * .IP <pTable>
  1387. * Expects a pointer to a MULTI_TABLE structure.  You must have allocated 
  1388. * this structure at some time before the call to muxMCastAddrGet(). 
  1389. * The MULTI_TABLE structure is defined in end.h as: 
  1390. * .CS
  1391. *    typedef struct multi_table
  1392. *        {
  1393. *        int     tableLen;  /@ length of table in bytes @/
  1394. *        char *  pTable;    /@ pointer to entries @/
  1395. *        } MULTI_TABLE;
  1396. * .CE
  1397. *
  1398. * VXWORKS AE PROTECTION DOMAINS
  1399. * Under VxWorks AE, you can call muxMCastAddrGet() from within the kernel 
  1400. * protection domain only, and the data referenced in the <pCookie> 
  1401. * parameter must reside in the kernel protection domain.  
  1402. * This restriction does not apply under non-AE versions of VxWorks.  
  1403. *
  1404. * RETURNS: OK; ENETDOWN, if <pCookie> does not represent a valid driver;
  1405. * or ERROR, if the driver's registered endMCastAddrGet() or nptMCastAddrGet() 
  1406. * routines fail.
  1407. *
  1408. * ERRNO: S_muxLib_NO_DEVICE
  1409. */
  1410. int muxMCastAddrGet
  1411.     (
  1412.     void *        pCookie, /* binding instance from muxBind() or muxTkBind() */
  1413.     MULTI_TABLE * pTable   /* pointer to a table to be filled and returned. */
  1414.     )
  1415.     {
  1416.     int       error;
  1417.     END_OBJ * pEnd;
  1418.     pEnd = PCOOKIE_TO_ENDOBJ (pCookie);
  1419.     if (pEnd == NULL)
  1420. {
  1421.         errnoSet(S_muxLib_NO_DEVICE);
  1422. error = ENETDOWN;
  1423. }
  1424.     else 
  1425. {
  1426. error = pEnd->pFuncTable->mCastAddrGet(pEnd, pTable);
  1427. }
  1428.     return (error);
  1429.     }
  1430. /******************************************************************************
  1431. *
  1432. * muxUnbind - detach a network service from the specified device
  1433. *
  1434. * This routine disconnects a network service from the specified device.  The
  1435. * <pCookie> argument indicates the service/device binding returned by the
  1436. * muxBind() or muxTkBind() routine. The <type> and <stackRcvRtn> arguments
  1437. * must also match the values given to the original muxBind() or muxTkBind()
  1438. * call.
  1439. *
  1440. * NOTE: If muxUnbind() returns ERROR, and 'errno' is set to EINVAL, this
  1441. * indicates that the device is not bound to the service.
  1442. *
  1443. * RETURNS: OK; or ERROR, if muxUnbind() fails.
  1444. * VXWORKS AE PROTECTION DOMAINS
  1445. * Under VxWorks AE, you can call muxUnBind() from within the kernel 
  1446. * protection domain only, and the data referenced in the <stackRcvRtn> and  
  1447. * <pCookie> parameters must reside in the kernel protection domain.  
  1448. * This restriction does not apply under non-AE versions of VxWorks.  
  1449. *
  1450. * ERRNO: EINVAL, S_muxLib_NO_DEVICE
  1451. */
  1452. STATUS muxUnbind
  1453.     (
  1454.     void *  pCookie,  /* binding instance from muxBind() or muxTkBind() */
  1455.     long    type,  /* type passed to muxBind() or muxTkBind() call */
  1456.     FUNCPTR stackRcvRtn /* pointer to stack receive routine */
  1457.     )
  1458.     {
  1459.     int error;
  1460.     END_OBJ *     pEnd;
  1461.     NET_PROTOCOL * pNode;
  1462.     FUNCPTR        netStackRcvRtn = NULL;
  1463.     pEnd = PCOOKIE_TO_ENDOBJ (pCookie);
  1464.     if (pEnd == NULL)
  1465. {
  1466.         errnoSet (S_muxLib_NO_DEVICE);
  1467. error = EINVAL;
  1468. return error;
  1469. }
  1470.     else 
  1471.         {
  1472.         /* Find and remove the matching binding. */
  1473. for (pNode = (NET_PROTOCOL *)lstFirst (&pEnd->protocols); 
  1474.      pNode != NULL; 
  1475.      pNode = (NET_PROTOCOL *)lstNext(&pNode->node))
  1476.     {
  1477.             if (pNode->pNptCookie != pCookie)
  1478.                 continue;
  1479.             /*
  1480.              * If necessary, fetch the actual stack receive routine
  1481.              * instead of the wrapper installed for END devices.
  1482.              */
  1483.             if (pNode->nptFlag)
  1484.                 {
  1485.                 MUX_ID muxId = (MUX_ID)pNode->pSpare;
  1486.                 if (muxId)
  1487.                     netStackRcvRtn = muxId->netStackRcvRtn;
  1488.                 }
  1489.             else
  1490.                 netStackRcvRtn = pNode->stackRcvRtn;
  1491.             /* This test should always succeed since the entry matches. */
  1492.             if (netStackRcvRtn == stackRcvRtn && pNode->type == type)
  1493.                 {
  1494.                 if (pNode->type == MUX_PROTO_SNARF)
  1495.                     (pEnd->snarfCount)--;
  1496.                 if (pNode->type == MUX_PROTO_OUTPUT)
  1497.                     pEnd->outputFilter = NULL;
  1498.                 lstDelete (&pEnd->protocols, &pNode->node);
  1499.                 muxTkUnbindUpdate (pNode->pNptCookie);
  1500.                 KHEAP_FREE( (char *)pNode);
  1501.                 return (OK);
  1502.                 }
  1503.             }
  1504.         }
  1505.     errnoSet (EINVAL);
  1506.     return (ERROR);
  1507.     }
  1508.     
  1509. /******************************************************************************
  1510. *
  1511. * muxDevUnload - unloads a device from the MUX
  1512. *
  1513. * This routine unloads a device from the MUX.  This breaks any network
  1514. * connections that use the device.  When this routine is called, each service
  1515. * bound to the device disconnects from it with the stackShutdownRtn() routine
  1516. * that was registered by the service.  The stackShutdownRtn() should call
  1517. * muxUnbind() to detach from the device.  Then, muxDevUnload() calls the
  1518. * device's endUnload() or nptUnload() routine.
  1519. *
  1520. * .IP <pName>
  1521. * Expects a pointer to a string containing the name of the device, for example
  1522. * 'ln' or 'ei'
  1523. *
  1524. * .IP <unit>
  1525. * Expects the unit number of the device indicated by <pName>
  1526. *
  1527. * VXWORKS AE PROTECTION DOMAINS
  1528. * Under VxWorks AE, you can call muxDevUnLoad() from within the kernel 
  1529. * protection domain only. This restriction does not apply under non-AE 
  1530. * versions of VxWorks.  
  1531. *
  1532. * RETURNS: OK, on success; ERROR, if the specified device was not found
  1533. * or some other error occurred; or the error value returned by the driver's
  1534. * unload() routine.
  1535. *
  1536. * ERRNO: S_muxLib_UNLOAD_FAILED, S_muxLib_NO_DEVICE
  1537. *
  1538. */
  1539. STATUS muxDevUnload
  1540.     (
  1541.     char * pName,  /* a string containing the name of the device */
  1542. /* for example, ln or ei */
  1543.     int    unit         /* the unit number */
  1544.     )
  1545.     {
  1546.     int            error;
  1547.     END_OBJ *      pEnd = NULL;
  1548.     NET_PROTOCOL * pNetNode;
  1549.     NET_PROTOCOL * pNetNodeNext;
  1550.     END_TBL_ROW *  pNode;
  1551.     void * pTemp = NULL;
  1552.     pEnd = endFindByName (pName, unit);
  1553.     if (pEnd != NULL)
  1554. {
  1555.         semTake (muxLibState.lock, WAIT_FOREVER);
  1556.         /* 
  1557.          * Find which row we're in. We know it's here because 
  1558.          * the endFindByName() routine was successful.
  1559.          */
  1560.         for (pNode = (END_TBL_ROW *)lstFirst (&endList); pNode != NULL; 
  1561.              pNode = (END_TBL_ROW *)lstNext (&pNode->node))
  1562.             {
  1563.             if (STREQ(pNode->name, pName))
  1564.                 break;
  1565.             }
  1566.         /* First we shutdown all of the protocols. */
  1567.         for (pNetNode = (NET_PROTOCOL *) lstFirst (&pEnd->protocols);
  1568.      pNetNode != NULL; pNetNode = pNetNodeNext) 
  1569.             {
  1570.     /* Save pointer to next node as shutdown rtn will free pNetNode */
  1571.     pNetNodeNext = (NET_PROTOCOL *) lstNext (&pNetNode->node);
  1572.             if (pNetNode->stackShutdownRtn != NULL)
  1573. {
  1574. /*
  1575.  * stackShutdownRtn() is expected to call muxUnbind() which 
  1576.  * will free the NET_PROTOCOL node, so that operation is not
  1577.                  * necessary here. The END and NPT devices use different
  1578.                  * shutdown prototypes. Select the appropriate format.
  1579.                  */
  1580.                 if (pNetNode->nptFlag)
  1581.                     {
  1582.                     MUX_ID muxId = (MUX_ID)pNetNode->pSpare;
  1583.                     void * pSpare = NULL;
  1584.                     pSpare = (muxId) ? muxId->pNetCallbackId : NULL;
  1585.                     pNetNode->stackShutdownRtn(pSpare);
  1586.                     }
  1587.                 else
  1588.                     pNetNode->stackShutdownRtn (pEnd, pNetNode->pSpare);
  1589. }
  1590.     else
  1591. {
  1592. /*
  1593.  * If no shutdown rtn then muxUnbind () will not be called and
  1594.  * we need to free the pNetNode ourselves.
  1595.  */
  1596. lstDelete (&pEnd->protocols, &pNetNode->node);
  1597. KHEAP_FREE ((char *)pNetNode);
  1598. }
  1599.     }
  1600.    
  1601. /* Release BIB and delete node before unloading device driver */
  1602.         muxTkUnloadUpdate (pEnd);
  1603.         lstDelete (&pNode->units, &pEnd->node);
  1604.  
  1605. /* remember the device specific value for backward compatibility purpose */
  1606. pTemp = pEnd->devObject.pDevice;
  1607.         /* Unload (destroy) the end object */
  1608. error = pEnd->pFuncTable->unload (pEnd);
  1609.  
  1610. /*
  1611.  * XXX Freeing END_OBJ(or DRV_CTRL) should be done by END, not here.
  1612.          * In futre, this code will be removed.
  1613.  */
  1614. if (pTemp == pEnd)
  1615.             {
  1616.             /* for backward compatibility, free the end_object */
  1617.             KHEAP_FREE ((char *)pTemp);
  1618.             }
  1619.  
  1620.        /*
  1621.         * XXX I don't see how 'unload' can really fail. There's nothing the mux
  1622. * can do to recover or continue using the END_OBJ.  All the protocols are
  1623. * already gone.
  1624.         */
  1625.         if (error != OK)
  1626.             {
  1627.             errnoSet (S_muxLib_UNLOAD_FAILED);
  1628.             semGive (muxLibState.lock);
  1629.             return (ERROR);
  1630.             }
  1631.  
  1632.         /* Is this row empty?  If so, remove it. */
  1633.         if (lstCount (&pNode->units) == 0)
  1634.             {
  1635.             lstDelete (&endList, &pNode->node);
  1636.             KHEAP_FREE ((char *)pNode);
  1637.             }
  1638.         error = OK;
  1639.         semGive (muxLibState.lock);
  1640.         }
  1641.     else
  1642.         {
  1643.         errnoSet (S_muxLib_NO_DEVICE);
  1644.         error = ERROR;
  1645.         }
  1646.     
  1647.     return (error);
  1648.     }
  1649. #endif /* STANDALONE_AGENT */
  1650. /******************************************************************************
  1651. *
  1652. * muxLinkHeaderCreate - attach a link-level header to a packet
  1653. *
  1654. * This routine constructs a link-level header using the source address
  1655. * of the device indicated by the <pCookie> argument as returned from the
  1656. * muxBind() routine.
  1657. *
  1658. * The <pDstAddr> argument provides an M_BLK_ID buffer containing the
  1659. * link-level destination address.
  1660. * Alternatively, the <bcastFlag> argument, if TRUE, indicates that the
  1661. * routine should use the link-level broadcast address, if available for
  1662. * the device. Although other information contained in the <pDstAddr>
  1663. * argument must be accurate, the address data itself is ignored in that case.
  1664. *
  1665. * The <pPacket> argument contains the contents of the resulting link-level
  1666. * frame.  This routine prepends the new link-level header to the initial
  1667. * 'mBlk' in that network packet if space is available or allocates a new
  1668. * 'mBlk'-'clBlk'-cluster triplet and prepends it to the 'mBlk' chain. 
  1669. * When construction of the header is complete, it returns an M_BLK_ID that 
  1670. * points to the initial 'mBlk' in the assembled link-level frame.
  1671. *
  1672. * RETURNS: M_BLK_ID or NULL.
  1673. *
  1674. * ERRNO: S_muxLib_INVALID_ARGS
  1675. */
  1676. M_BLK_ID muxLinkHeaderCreate
  1677.     (
  1678.     void *  pCookie,  /* protocol/device binding from muxBind() */
  1679.     M_BLK_ID  pPacket,  /* structure containing frame contents */
  1680.     M_BLK_ID  pSrcAddr, /* structure containing source address */
  1681.     M_BLK_ID  pDstAddr,  /* structure containing destination address */
  1682.     BOOL  bcastFlag  /* use broadcast destination (if available)? */
  1683.     )
  1684.     {
  1685.     END_OBJ *  pEnd;
  1686.     M_BLK_ID pMblkHdr = NULL;
  1687.     pEnd = PCOOKIE_TO_ENDOBJ (pCookie);
  1688.     if (pEnd == NULL)
  1689.         {
  1690.         errnoSet(S_muxLib_INVALID_ARGS);
  1691.         return (NULL); 
  1692.         }
  1693.     if (pEnd->pFuncTable->formAddress != NULL)
  1694.         {
  1695.         pMblkHdr = pEnd->pFuncTable->formAddress (pPacket, pSrcAddr,
  1696.                                                   pDstAddr, bcastFlag);
  1697.         }
  1698.     else
  1699.         {
  1700.         switch (pEnd->mib2Tbl.ifType)
  1701.             {
  1702.             case M2_ifType_ethernet_csmacd:
  1703.             case M2_ifType_iso88023_csmacd:
  1704.                 M_PREPEND(pPacket, SIZEOF_ETHERHEADER, M_DONTWAIT);
  1705.                 if ( pPacket == NULL)
  1706.                     return NULL;
  1707.                 if (bcastFlag)
  1708.                     bcopy (etherbroadcastaddr, pPacket->m_data, 6);
  1709.                 else
  1710.                     bcopy(pDstAddr->m_data, pPacket->m_data, pDstAddr->m_len);
  1711.                 bcopy(pSrcAddr->m_data, pPacket->m_data + pDstAddr->m_len,
  1712.                       pSrcAddr->m_len);
  1713.                 ((struct ether_header *)pPacket->m_data)->ether_type =
  1714.                       pDstAddr->mBlkHdr.reserved;
  1715.                 pMblkHdr = pPacket;
  1716.                 break;
  1717.             default:
  1718.                 break;
  1719.             }
  1720.         }
  1721.     return (pMblkHdr);
  1722.     }
  1723. /******************************************************************************
  1724. *
  1725. * muxAddressForm - form a frame with a link-layer address
  1726. *
  1727. * Use this routine to create a frame with an appropriate link-layer address.  
  1728. * As input, this function expects the source address, the destination address, 
  1729. * and the data you want to include in the frame. When control returns from the 
  1730. * muxAddressForm() call, the <pMblk> parameter references a frame ready for 
  1731. * transmission.  Internally, muxAddressForm() either prepended the link-layer 
  1732. * header to the data buffer supplied in <pMblk> (if there was enough room) or 
  1733. * it allocated a new 'mBlk'-'clBlk'-cluster and prepended the new 'mBlk' to 
  1734. * the 'mBlk' chain supplied in <pMblk>.
  1735. *
  1736. * NOTE: You should set the 'pDstAddr.mBlkHdr.reserved' field to the network
  1737. * service type.
  1738. *
  1739. * .IP <pCookie> 13
  1740. * Expects the cookie returned from the muxBind().  This cookie 
  1741. * indicates the device to which the MUX has bound this protocol. 
  1742. * .IP <pMblk>
  1743. * Expects a pointer to the 'mBlk' structure that contains the packet. 
  1744. * .IP <pSrcAddr>
  1745. * Expects a pointer to the 'mBlk' that contains the source address.
  1746. * .IP <pDstAddr>
  1747. * Expects a pointer to the 'mBlk' that contains the destination address.
  1748. *
  1749. * NOTE: This routine is used only with ENDs, and is not needed for NPT
  1750. * drivers.
  1751. *
  1752. * VXWORKS AE PROTECTION DOMAINS
  1753. * Under VxWorks AE, you can call muxAddressForm() from within the kernel 
  1754. * protection domain only, and the data referenced in the <pCookie> 
  1755. * parameter must reside in the kernel protection domain. In addition, the 
  1756. * returned M_BLK_ID is valid in the kernel protection domain only.
  1757. * This restriction does not apply under non-AE versions of VxWorks.  
  1758. *
  1759. * RETURNS: M_BLK_ID or NULL.
  1760. *
  1761. * ERRNO: S_muxLib_NO_DEVICE
  1762. */
  1763. M_BLK_ID muxAddressForm
  1764.     (
  1765.     void *  pCookie,  /* protocol/device binding from muxBind() */
  1766.     M_BLK_ID  pMblk, /* structure to contain packet */
  1767.     M_BLK_ID  pSrcAddr, /* structure containing source address */
  1768.     M_BLK_ID  pDstAddr /* structure containing destination address */
  1769.     )
  1770.     {
  1771.     END_OBJ *   pEnd;
  1772.     M_BLK_ID pMblkHdr = NULL;
  1773.     ULONG       ifType;
  1774.     pEnd = PCOOKIE_TO_ENDOBJ (pCookie);
  1775.     
  1776.     if (pEnd == NULL)
  1777.         {
  1778.         errnoSet (S_muxLib_NO_DEVICE);
  1779.         return (NULL); 
  1780.         }
  1781.     
  1782.     if (pEnd->pFuncTable->formAddress != NULL)
  1783.         {
  1784.         pMblkHdr = pEnd->pFuncTable->formAddress (pMblk, pSrcAddr,
  1785.                                                   pDstAddr, FALSE);
  1786.         }
  1787.     else
  1788.         {
  1789.         if (pEnd->flags & END_MIB_2233)
  1790.             {
  1791.             if (pEnd->pMib2Tbl != NULL)
  1792.                 ifType = pEnd->pMib2Tbl->m2Data.mibIfTbl.ifType;
  1793.             else
  1794.                 return NULL;
  1795.             }
  1796.         else /* (RFC1213 style of counters supported) XXX */
  1797.             {
  1798.             ifType = pEnd->mib2Tbl.ifType;
  1799.             }
  1800.         switch (ifType)
  1801.             {
  1802.             case M2_ifType_ethernet_csmacd:
  1803.             case M2_ifType_iso88023_csmacd:
  1804.                 M_PREPEND(pMblk, SIZEOF_ETHERHEADER, M_DONTWAIT);
  1805.                 if (pMblk == NULL)
  1806.                     return NULL;
  1807.                 bcopy(pDstAddr->m_data, pMblk->m_data, pDstAddr->m_len);
  1808.                 bcopy(pSrcAddr->m_data, pMblk->m_data + pDstAddr->m_len,
  1809.                       pSrcAddr->m_len);
  1810.                 ((struct  ether_header *)pMblk->m_data)->ether_type =
  1811.                     pDstAddr->mBlkHdr.reserved;
  1812.                 pMblkHdr = pMblk;
  1813.                 break;
  1814.             default:
  1815.                 break;
  1816.             }
  1817.         }
  1818.     return (pMblkHdr);
  1819.     }
  1820. /******************************************************************************
  1821. *
  1822. * muxPacketDataGet - return the data from a packet
  1823. *
  1824. * Any service bound to a driver may use this routine to extract the
  1825. * packet data and remove the link-level header information. This
  1826. * routine copies the header information from the packet referenced in
  1827. * <pMblk> into the LL_HDR_INFO structure referenced in <pLinkHdrInfo>.
  1828. *
  1829. * .IP <pCookie>
  1830. * Expects the cookie returned from the muxBind() call.  This
  1831. * cookie indicates the device to which the MUX bound this service.
  1832. *
  1833. * .IP <pMblk>
  1834. * Expects a pointer to an 'mBlk' or 'mBlk' cluster representing a packet
  1835. * containing the data to be returned
  1836. *
  1837. * .IP <pLinkHdrInfo>
  1838. * Expects a pointer to an LL_HDR_INFO structure into which the packet header
  1839. * information is copied from the incoming 'mBlk'
  1840. * VXWORKS AE PROTECTION DOMAINS
  1841. * Under VxWorks AE, you can call muxPacketDataGet() from within the kernel 
  1842. * protection domain only, and the data referenced in the parameters must   
  1843. * reside in the kernel protection domain.  This restriction does not 
  1844. * apply under non-AE versions of VxWorks.  
  1845. *
  1846. * RETURNS: OK; or ERROR, if the device type is not recognized.
  1847. *
  1848. * ERRNO: S_muxLib_NO_DEVICE
  1849. */
  1850. STATUS muxPacketDataGet
  1851.     (
  1852.     void *        pCookie,   /* protocol/device binding from muxBind() */
  1853.     M_BLK_ID      pMblk,   /* returns the packet data */
  1854.     LL_HDR_INFO * pLinkHdrInfo   /* returns the packet header information */
  1855.     )
  1856.     {
  1857.     int       error = OK;
  1858.     END_OBJ * pEnd;
  1859.     pEnd = PCOOKIE_TO_ENDOBJ(pCookie);
  1860.     if (pEnd == NULL)
  1861.         {
  1862.         errnoSet(S_muxLib_NO_DEVICE);
  1863.         return (ERROR);
  1864.         }
  1865.     
  1866.     if (pEnd->pFuncTable->packetDataGet != NULL)
  1867.         {
  1868.         error = pEnd->pFuncTable->packetDataGet(pMblk, pLinkHdrInfo);
  1869.         }
  1870.     else
  1871.         {
  1872.         return (ERROR);
  1873.         }
  1874.     return (error);
  1875.     }
  1876. /******************************************************************************
  1877. *
  1878. * muxPacketAddrGet - get addressing information from a packet
  1879. *
  1880. * The routine returns the immediate source, immediate destination, ultimate 
  1881. * source, and ultimate destination addresses from the packet pointed to in 
  1882. * the first M_BLK_ID.  This routine makes no attempt to extract that 
  1883. * information from the packet directly.  Instead, it passes the packet 
  1884. * through to the driver routine that knows how to interpret the packets that 
  1885. * it has received.
  1886. *
  1887. * .IP <pCookie>
  1888. * Expects the cookie returned from the muxBind() call.  This
  1889. * cookie indicates the device to which the MUX bound this service.
  1890. *
  1891. * .IP <pMblk>
  1892. * Expects an M_BLK_ID representing packet data from which the addressing
  1893. * information is to be extracted
  1894. *
  1895. * .IP <pSrcAddr>
  1896. * Expects NULL or an M_BLK_ID which will hold the local source address
  1897. * extracted from the packet
  1898. *
  1899. * .IP <pDstAddr>
  1900. * Expects NULL or an M_BLK_ID which will hold the local destination address
  1901. * extracted from the packet
  1902. *
  1903. * .IP <pESrcAddr>
  1904. * Expects NULL or an M_BLK_ID which will hold the end source address
  1905. * extracted from the packet
  1906. *
  1907. * .IP <pEDstAddr>
  1908. * Expects NULL or an M_BLK_ID which will hold the end destination address
  1909. * extracted from the packet
  1910. *
  1911. * VXWORKS AE PROTECTION DOMAINS
  1912. * Under VxWorks AE, you can call muxPacketAddrGet() from within the kernel 
  1913. * protection domain only, and the data referenced in the parameters must 
  1914. * reside in the kernel protection domain.  This restriction does not apply 
  1915. * under non-AE versions of VxWorks.  
  1916. *
  1917. * RETURNS: OK or ERROR.
  1918. *
  1919. * ERRNO: S_muxLib_NO_DEVICE
  1920. */
  1921. STATUS muxPacketAddrGet
  1922.     (
  1923.     void *   pCookie,  /* protocol/device binding from muxBind() */
  1924.     M_BLK_ID pMblk, /* structure to contain packet */
  1925.     M_BLK_ID pSrcAddr,    /* structure containing source address */
  1926.     M_BLK_ID pDstAddr,          /* structure containing destination address */
  1927.     M_BLK_ID pESrcAddr,         /* structure containing the end source */
  1928.     M_BLK_ID pEDstAddr          /* structure containing the end destination */
  1929.     )
  1930.     {
  1931.     int       error = OK;
  1932.     END_OBJ * pEnd;
  1933.     pEnd = PCOOKIE_TO_ENDOBJ (pCookie);
  1934.     if (pEnd == NULL)
  1935.         {
  1936.         errnoSet(S_muxLib_NO_DEVICE);
  1937.         return (ERROR);
  1938.         }
  1939.     
  1940.     if (pEnd->pFuncTable->formAddress != NULL)
  1941.         {
  1942.         if (pEnd->pFuncTable->addrGet != NULL)
  1943.             {  
  1944.             error = pEnd->pFuncTable->addrGet (pMblk, pSrcAddr, pDstAddr,
  1945.                                                pESrcAddr, pEDstAddr);
  1946.             }
  1947.         }
  1948.     else
  1949.         {
  1950.         error = ERROR;
  1951.         }
  1952.     return (error);
  1953.     }
  1954. /******************************************************************************
  1955. *
  1956. * endFindByName - find a device using its string name
  1957. *
  1958. * This routine takes a string name and a unit number and finds the
  1959. * device that has that name/unit combination.
  1960. *
  1961. * VXWORKS AE PROTECTION DOMAINS
  1962. * Under VxWorks AE, you can call endFindByName() from within the kernel 
  1963. * protection domain only, and the data referenced in the <pName> 
  1964. * parameter must reside in the kernel protection domain. In addition, the 
  1965. * returned END_OBJ is valid in the kernel protection domain only. 
  1966. * This restriction does not apply under non-AE versions of VxWorks.  
  1967. *
  1968. * RETURNS: A pointer to an END_OBJ; or NULL, if the device is not found.
  1969. *
  1970. */
  1971. END_OBJ * endFindByName
  1972.     (
  1973.     char * pName, /* device name to search for */
  1974.     int    unit
  1975.     )
  1976.     {
  1977.     BOOL          found = FALSE;
  1978.     END_TBL_ROW * pNode;
  1979.     END_OBJ *     pEnd;
  1980.     
  1981.     if (pName == NULL)
  1982. return (NULL);
  1983.     for (pNode = (END_TBL_ROW *)lstFirst(&endList); pNode != NULL; 
  1984. pNode = (END_TBL_ROW *)lstNext(&pNode->node))
  1985. {
  1986. if (STREQ(pNode->name, pName))
  1987.     {
  1988.             found = TRUE;
  1989.             break;
  1990.     }
  1991. }
  1992.     if (found)
  1993.         {
  1994.         for (pEnd = (END_OBJ *)lstFirst(&pNode->units); pEnd != NULL; 
  1995.              pEnd = (END_OBJ *)lstNext(&pEnd->node))
  1996.             {
  1997.             if (pEnd->devObject.unit == unit)
  1998.                 {
  1999.                 return (pEnd);
  2000.                 }
  2001.             }
  2002.         }    
  2003.     errnoSet (S_muxLib_NO_DEVICE);
  2004.     return (NULL);
  2005.     }
  2006. /******************************************************************************
  2007. *
  2008. * muxDevExists - tests whether a device is already loaded into the MUX
  2009. *
  2010. * This routine takes a string device name (for example, ln or ei) and a unit
  2011. * number.  If this device is already known to the MUX, it returns TRUE.
  2012. * Otherwise, this routine returns FALSE. 
  2013. *
  2014. * .IP <pName>
  2015. * Expects a pointer to a string containing the device name
  2016. *
  2017. * .IP <unit>
  2018. * Expects the unit number of the device
  2019. *
  2020. * VXWORKS AE PROTECTION DOMAINS
  2021. * Under VxWorks AE, you can call muxDevExists() from within the kernel 
  2022. * protection domain only, and the data referenced in the <pName> 
  2023. * parameter must reside in the kernel protection domain.  
  2024. * This restriction does not apply under non-AE versions of VxWorks.  
  2025. *
  2026. * RETURNS: TRUE, if the device exists; else FALSE.
  2027. *
  2028. */
  2029. BOOL muxDevExists
  2030.     (
  2031.     char * pName, /* string containing a device name (ln, ei, ...)*/
  2032.     int    unit         /* unit number */
  2033.     )
  2034.     {
  2035.     if (endFindByName(pName, unit) == NULL)
  2036.         return (FALSE);
  2037.     return (TRUE);
  2038.     }
  2039. /******************************************************************************
  2040. *
  2041. * muxTxRestart - notify a service that it can restart its transmitter
  2042. *
  2043. * A device uses this routine to notify all the services bound to it that
  2044. * they can resume transmitting.  This after the device blocked transmission
  2045. * by returning END_ERR_BLOCK from endSend() or nptSend().
  2046. *
  2047. * .IP <pCookie>
  2048. * The device identifier (END_OBJ) returned from the driver's endLoad() or
  2049. * nptLoad() routine.
  2050. *
  2051. * RETURNS: N/A
  2052. *
  2053. * ERRNO: S_muxLib_NO_DEVICE
  2054. *
  2055. * NOMANUAL
  2056. */
  2057. void muxTxRestart
  2058.     (
  2059.     void * pCookie    /* device identifier from driver's load routine */
  2060.     )
  2061.     {
  2062.     NET_PROTOCOL* pProto;
  2063.     END_OBJ* pEnd;
  2064.     
  2065.     pEnd = (END_OBJ *)pCookie;
  2066.     if (pEnd == NULL)
  2067.         {
  2068.         errnoSet (S_muxLib_NO_DEVICE);
  2069.         return;
  2070.         }
  2071.     if (muxLibState.debug)
  2072.         logMsg ("muxTxRestartn", 0, 0, 0, 0, 0, 0);
  2073.     /*
  2074.      * Loop through the service list.
  2075.      */
  2076.     for (pProto = (NET_PROTOCOL *)lstFirst(&pEnd->protocols); 
  2077. pProto != NULL; pProto = (NET_PROTOCOL *)lstNext(&pProto->node))
  2078. {
  2079. if (pProto->stackTxRestartRtn != NULL)
  2080.             {
  2081.     /* 
  2082.      * the call back prototype differs depending on whether muxBind()
  2083.      * or muxTkBind was used to bind the service to the device.
  2084.      */
  2085.             if (pProto->nptFlag)
  2086.                 {
  2087.                 MUX_ID muxId = (MUX_ID)pProto->pSpare;
  2088.                 void * pSpare = NULL;
  2089.                 pSpare = (muxId) ? muxId->pNetCallbackId : NULL;
  2090.                 pProto->stackTxRestartRtn(pSpare);
  2091.                 }
  2092.             else
  2093.                 pProto->stackTxRestartRtn (pCookie, pProto->pSpare);
  2094.             }
  2095.         }
  2096.     }
  2097. /******************************************************************************
  2098. *
  2099. * muxError - notify a service that an error occurred.
  2100. *
  2101. * A driver uses this routine to notify all of the services bound to it that
  2102. * an error has occurred.  A set of error values are defined in end.h.
  2103. *
  2104. * .IP <pCookie>
  2105. * Expects the cookie that was returned by the driver's endLoad() or nptLoad()
  2106. * routine, a pointer to the driver's END_OBJ structure.
  2107. *
  2108. * .IP <pError>
  2109. * Expects an error structure as defined in end.h
  2110. *
  2111. * RETURNS: N/A
  2112. *
  2113. * ERRNO: S_muxLib_NO_DEVICE
  2114. *
  2115. * NOMANUAL
  2116. */
  2117. void muxError
  2118.     (
  2119.     void *    pCookie,                        /* END_OBJ */
  2120.     END_ERR * pError                          /* Error structure. */
  2121.     )
  2122.     {
  2123.     NET_PROTOCOL* pProto;
  2124.     END_OBJ* pEnd;
  2125.     
  2126.     pEnd = (END_OBJ *)pCookie;
  2127.     if (pEnd == NULL)
  2128.         {
  2129.         errnoSet(S_muxLib_NO_DEVICE);
  2130.         return;
  2131.         }
  2132.     if (muxLibState.debug)
  2133.         logMsg ("muxErrorn", 0, 0, 0, 0, 0, 0);
  2134.     /*
  2135.      * Loop through the service list.
  2136.      */
  2137.     for (pProto = (NET_PROTOCOL *)lstFirst (&pEnd->protocols); 
  2138. pProto != NULL; pProto = (NET_PROTOCOL *)lstNext (&pProto->node))
  2139. {
  2140. if (pProto->stackErrorRtn != NULL)
  2141.             {
  2142.     /* 
  2143.      * the call back prototype differs depending on whether muxBind()
  2144.      * or muxTkBind() was used to bind the service to this device.
  2145.      */
  2146.             if (pProto->nptFlag)
  2147.                 {
  2148.                 MUX_ID muxId = (MUX_ID)pProto->pSpare;
  2149.                 void * pSpare = NULL;
  2150.                 pSpare = (muxId) ? muxId->pNetCallbackId : NULL;
  2151.                 pProto->stackErrorRtn (pSpare,pError);
  2152.                 }
  2153.             else
  2154. pProto->stackErrorRtn (pCookie, pError, pProto->pSpare);
  2155.             }
  2156.         }
  2157.     }
  2158. #ifndef STANDALONE_AGENT
  2159. /******************************************************************************
  2160. *
  2161. * muxAddrResFuncAdd - replace the default address resolution function
  2162. *
  2163. * Use muxAddrResFuncAdd() to register an address resolution function for an 
  2164. * interface-type/protocol pair. You must call muxAddrResFuncAdd() prior to 
  2165. * calling the protocol's <protocol>Attach() routine. If the driver registers 
  2166. * itself as an Ethernet driver, you do not need to call muxAddrResFuncAdd(). 
  2167. * VxWorks automatically assigns arpresolve() to registered Ethernet devices. 
  2168. * The muxAddrResFuncAdd() functionality is intended for those who want to use
  2169. * VxWorks network stack with non-Ethernet drivers that require address 
  2170. * resolution. 
  2171. *
  2172. * .IP <ifType>
  2173. * Expects a media interface or network driver type, such as can be found in
  2174. * m2Lib.h. If using the END model, the <ifType> argument is restricted to 
  2175. * the values in m2Lib.h. In the NPT model, this restriction does not apply.
  2176. *
  2177. * .IP <protocol>
  2178. * Expects a network service or protocol type, such as can be found in RFC
  2179. * 1700. Look for the values under ETHER TYPES. For example, Internet IP
  2180. * would be identified as 2048 (0x800 hexadecimal). If using the END model, 
  2181. * <protocol> is restricted to the values in RFC 1700. In the NPT model,
  2182. * this restriction does not apply.
  2183. *
  2184. * .IP <addrResFunc>
  2185. * Expects a pointer to an address resolution function for this combination
  2186. * of driver type and service type. The prototype of your replacement address 
  2187. * resolution function must match that of arpresolve():
  2188. * .CS
  2189. * int arpresolve
  2190. *    (
  2191. *    struct arpcom *   ac,
  2192. *    struct rtentry *  rt,
  2193. *    struct mbuf *     m,
  2194. *    struct sockaddr * dst,
  2195. *    u_char *          desten
  2196. *    )
  2197. * .CE
  2198. * This function returns one upon success, which indicates that <desten> has 
  2199. * been updated with the necessary data-link layer information and that the 
  2200. * IP sublayer output function can transmit the packet. 
  2201. * This function returns zero if it cannot resolve the address immediately. 
  2202. * In the default arpresolve() implementation, resolving the address 
  2203. * immediately means arpresolve() was able to find the address in its 
  2204. * table of results from previous ARP requests. Returning zero indicates 
  2205. * that the table did not contain the information but that the packet 
  2206. * has been stored and that an ARP request has been queued. 
  2207. * If the ARP request times out, the packet is dropped. If the ARP request 
  2208. * completes successfully, processing that event updates the local ARP table 
  2209. * and resubmits the packet to the IP sublayer's output function for 
  2210. * transmission. This time, the arpresolve() call will return one. 
  2211. *
  2212. * What is essential to note here is that arpresolve() did not wait for 
  2213. * the ARP request to complete before returning. If you replace the default 
  2214. * arpresolve() function, you must make sure your function returns as soon 
  2215. * as possible and that it never blocks. Otherwise, you block the IP sublayer 
  2216. * from transmitting other packets out through the interface for which this 
  2217. * packet was queued. You must also make sure that your arpresolve() function 
  2218. * takes responsibility for the packet if it returns zero. Otherwise, the 
  2219. * packet is dropped. 
  2220. *
  2221. * RETURNS: OK, or ERROR.
  2222. *
  2223. * VXWORKS AE PROTECTION DOMAINS
  2224. * Under VxWorks AE, you can call muxAddrResFuncAdd() from within the kernel 
  2225. * protection domain only, and the data referenced in the <addrResFunc> 
  2226. * parameter must reside in the kernel protection domain.  
  2227. * This restriction does not apply under non-AE versions of VxWorks.  
  2228. *
  2229. */
  2230. STATUS muxAddrResFuncAdd
  2231.     (
  2232.     long    ifType,      /* Media interface type, typically from m2Lib.h */
  2233.     long    protocol,    /* Service type, for instance from RFC 1700 */
  2234.     FUNCPTR addrResFunc  /* Function to call. */
  2235.     )
  2236.     {
  2237.     BOOL           found = FALSE;
  2238.     MUX_ADDR_REC * pNode;
  2239.     
  2240.     if (ifType > MUX_MAX_IFTYPE)
  2241.         return (ERROR);
  2242.     if (&addrResList[ifType] == NULL)
  2243.         {
  2244.         lstInit (&addrResList[ifType]);
  2245.         pNode = KHEAP_ALLOC (sizeof (MUX_ADDR_REC));
  2246.         if (pNode == NULL)
  2247.             {
  2248.             return (ERROR);
  2249.             }
  2250.         pNode->addrResFunc = addrResFunc;
  2251.         pNode->protocol = protocol;
  2252.         lstAdd(&addrResList[ifType], &pNode->node);
  2253.         return (OK);
  2254.         }
  2255.     else
  2256.         {
  2257.         for (pNode = (MUX_ADDR_REC *)lstFirst (&addrResList[ifType]);
  2258.              pNode != NULL; 
  2259.              pNode = (MUX_ADDR_REC *)lstNext (&pNode->node))
  2260.             {
  2261.             if (pNode->protocol == protocol)
  2262.                 {
  2263.                 found = TRUE;
  2264.                 break;
  2265.                 }
  2266.             }
  2267.         }
  2268.     if (found)
  2269.         {
  2270.         return (ERROR);
  2271.         }
  2272.     else
  2273.         {
  2274.         pNode = KHEAP_ALLOC (sizeof (MUX_ADDR_REC));
  2275.         if (pNode == NULL)
  2276.             {
  2277.             return (ERROR);
  2278.             }
  2279.         pNode->addrResFunc = addrResFunc;
  2280.         pNode->protocol = protocol;
  2281.         lstAdd(&addrResList[ifType], &pNode->node);
  2282.         return (OK);
  2283.         }
  2284.     }
  2285. /******************************************************************************
  2286. *
  2287. * muxAddrResFuncGet - get the address resolution function for ifType/protocol
  2288. *
  2289. * This routine gets a pointer to the registered address resolution function 
  2290. * for the specified interface-protocol pair.  If no such function exists, 
  2291. * muxAddResFuncGet() returns NULL.  
  2292. *
  2293. * .IP <ifType>
  2294. * Expects a media interface or network driver type, such as those found
  2295. * in m2Lib.h. If using the END model, the <ifType> argument is restricted to 
  2296. * the m2Lib.h values. In the NPT model, this restriction does not apply.
  2297. *
  2298. * .IP <protocol>
  2299. * Expects a network service or protocol type such as those found in RFC 1700.
  2300. * Look for the values under ETHER TYPES.  For example, Internet IP would 
  2301. * be identified as 2048 (0x800 hexadecimal). If using the END model, the 
  2302. * <protocol> argument is restricted to the RFC 1700 values.  In the NPT model,
  2303. * this restriction does not apply.
  2304. *
  2305. * VXWORKS AE PROTECTION DOMAINS
  2306. * Under VxWorks AE, you can call muxAddrResFuncGet() from within the kernel 
  2307. * protection domain only.  In addition, the returned FUNCPTR is valid in the 
  2308. * kernel protection domain only.  This restriction does not apply under 
  2309. * non-AE versions of VxWorks.  
  2310. *
  2311. * RETURNS: FUNCPTR to the routine or NULL.
  2312. */
  2313. FUNCPTR muxAddrResFuncGet
  2314.     (
  2315.     long ifType,                             /* ifType from m2Lib.h    */
  2316.     long protocol                            /* protocol from RFC 1700 */
  2317.     )
  2318.     {
  2319.     MUX_ADDR_REC * pNode;
  2320.     if (ifType > MUX_MAX_IFTYPE)
  2321.         return (NULL);
  2322.     if (&addrResList[ifType] == NULL)
  2323.         return (NULL);
  2324.     for (pNode = (MUX_ADDR_REC *)lstFirst (&addrResList[ifType]);
  2325.          pNode != NULL; 
  2326.          pNode = (MUX_ADDR_REC *)lstNext (&pNode->node))
  2327.         {
  2328.         if (pNode->protocol == protocol)
  2329.             {
  2330.             return (pNode->addrResFunc);
  2331.             }
  2332.         }
  2333.     return (NULL);
  2334.     }
  2335.     
  2336. /******************************************************************************
  2337. *
  2338. * muxAddrResFuncDel - delete an address resolution function
  2339. *
  2340. * This function deletes the address resolution function registered for the
  2341. * specified interface-protocol pair. If using the NPT architecture, the 
  2342. * <ifType> and <protocol> arguments are not restricted to the m2Lib.h or 
  2343. * RFC 1700 values.
  2344. *
  2345. * .IP <ifType>
  2346. * Expects a media interface or network driver type. For and END driver, 
  2347. * use the values specified in m2Lib.h.
  2348. *
  2349. * .IP <protocol>
  2350. * Expects a network service or protocol type. For example, Internet IP would 
  2351. * be identified as 2048 (0x800 hexadecimal). This value can be found in RFC 
  2352. * 1700 under the heading, ETHER TYPES.  
  2353. *
  2354. * VXWORKS AE PROTECTION DOMAINS
  2355. * Under VxWorks AE, you can call muxAddrResFuncDel() from within the kernel 
  2356. * protection domain only.  This restriction does not apply under non-AE 
  2357. * versions of VxWorks.  
  2358. *
  2359. * RETURNS: OK or ERROR.
  2360. */
  2361.     
  2362. STATUS muxAddrResFuncDel
  2363.     (
  2364.     long ifType,    /* ifType of function you want to delete */
  2365.     long protocol   /* protocol from which to delete the function */
  2366.     )
  2367.     {
  2368.     MUX_ADDR_REC* pNode;
  2369.     if (ifType > MUX_MAX_IFTYPE)
  2370.         return (ERROR);
  2371.     if (&addrResList[ifType] == NULL)
  2372.         return (ERROR);
  2373.     for (pNode = (MUX_ADDR_REC *)lstFirst (&addrResList[ifType]);
  2374.          pNode != NULL; 
  2375.          pNode = (MUX_ADDR_REC *)lstNext (&pNode->node))
  2376.         {
  2377.         if (pNode->protocol == protocol)
  2378.             {
  2379.             lstDelete (&addrResList[ifType], &pNode->node);
  2380.             KHEAP_FREE ((char *)pNode);
  2381.             return (OK);
  2382.             }
  2383.         }
  2384.     return (ERROR);
  2385.     }
  2386. #endif /* STANDALONE_AGENT */
  2387. /******************************************************************************
  2388. *
  2389. * muxDevStopAll - stop all drivers that have been loaded into the MUX
  2390. *
  2391. * This routine calls the "stop" entry point for all drivers loaded into the
  2392. * MUX.
  2393. *
  2394. * WARNING:  Calling this routine with a timeout that is not WAIT_FOREVER
  2395. *           is a violation of mutual exclusion and will cause problems in
  2396. *           a running system.
  2397. *
  2398. *           This option should only be used if the system is being rebooted
  2399. *           (i.e. when called from a reboot hook) or if the application has
  2400. *           very specific knowledge of the state of all drivers in the system.
  2401. *
  2402. * RETURNS: OK or ERROR
  2403. *
  2404. * SEE ALSO
  2405. * muxDevStop
  2406. *
  2407. * NOMANUAL
  2408. */
  2409. STATUS muxDevStopAll
  2410.     (
  2411.     int timeout /* Number of ticks to wait before blowing away the devices. */
  2412.     )
  2413.     {
  2414.     END_TBL_ROW * pEndTblRow;    
  2415.     END_OBJ *     pEnd;
  2416.     /* Mutual exclusion is necessary to protect <endList> access */
  2417.     semTake (muxLibState.lock, timeout);
  2418.     
  2419.     /* Each Table row contains a list of ENDs for a particular driver */
  2420.     for (pEndTblRow = (END_TBL_ROW *)lstFirst (&endList); 
  2421.  pEndTblRow != NULL; 
  2422.  pEndTblRow = (END_TBL_ROW *)lstNext (&pEndTblRow->node))
  2423. {
  2424. /* Loop through all ENDs in the table row and call the stop routine */
  2425.         for (pEnd = (END_OBJ *)lstFirst (&pEndTblRow->units); 
  2426.      pEnd != NULL; 
  2427.              pEnd = (END_OBJ *)lstNext (&pEnd->node))
  2428.             {
  2429.             if (pEnd->pFuncTable->stop != NULL)
  2430.                 {
  2431.                 (void) pEnd->pFuncTable->stop (pEnd);
  2432.                 }
  2433.     }    
  2434. }
  2435.     semGive (muxLibState.lock);
  2436.     return (OK);
  2437.     }
  2438. /******************************************************************************
  2439. *
  2440. * muxDevStopAllImmediate - muxDevStopAll for rebootHook use only
  2441. *  
  2442. * RETURNS: OK or ERROR
  2443. *
  2444. * SEE ALSO
  2445. * muxDevStopAll
  2446. *
  2447. * NOMANUAL
  2448. */
  2449. LOCAL STATUS muxDevStopAllImmediate (void)
  2450.     {
  2451.     return (muxDevStopAll (0));
  2452.     }
  2453. /******************************************************************************
  2454. *
  2455. * muxEndFlagsNotify - notify all services of the new driver flags value
  2456. *
  2457. * This function executes in the context of tNetTask and its sole purpose
  2458. * is to traverse the protocol list in the driver, notifying all the bound
  2459. * services of a change in the device flags, except the service that
  2460. * changed the flags value in the first place.
  2461. * RETURNS: N/A
  2462. * NOMANUAL
  2463. */
  2464. LOCAL void muxEndFlagsNotify
  2465.     (
  2466.     void *  pCookie,  /* binding instance cookie */
  2467.     long  endFlags  /* new END flag settings */
  2468.     )
  2469.     {
  2470.     END_ERR endErr;
  2471.     MUX_ID  muxId = (MUX_ID)pCookie;
  2472.     NET_PROTOCOL * pProto;
  2473.     char msgBuffer[128];
  2474.     if ((muxId == NULL) || (muxId->pEnd == NULL))
  2475.         return;
  2476.     bzero (msgBuffer,128);
  2477.     /* create a message */
  2478.     sprintf (msgBuffer,
  2479.              "END FLAGS changed by protocol ID 0x%x for: %s Unit %dn",
  2480.              (UINT)muxId->netSvcType, muxId->pEnd->devObject.name,
  2481.              muxId->pEnd->devObject.unit);
  2482.     /* create the error notification */
  2483.     endErr.errCode = END_ERR_FLAGS;
  2484.     endErr.pMesg = msgBuffer;
  2485.     (UINT32)(endErr.pSpare) = endFlags;
  2486.     /*
  2487.      * notify all protocols that are bound to this END, except the one that
  2488.      * changed the flag settings originally.
  2489.      */
  2490.     for (pProto = (NET_PROTOCOL *)lstFirst(&muxId->pEnd->protocols); 
  2491.  pProto != NULL; pProto = (NET_PROTOCOL *)lstNext (&pProto->node))
  2492. {
  2493.         if (pProto->type != muxId->netSvcType && pProto->stackErrorRtn != NULL)
  2494.     {
  2495.     /* 
  2496.      * The call back prototype differs depending on whether muxBind()
  2497.      * or muxTkBind() was used to bind the protocol to the device.
  2498.      */
  2499.     if (pProto->nptFlag)    /* muxTkBind: new NPT prototype. */
  2500.                 {
  2501.                 MUX_ID protoMuxId = (MUX_ID)pProto->pSpare;
  2502.                 void * pSpare = NULL;
  2503.                 pSpare = (protoMuxId) ? protoMuxId->pNetCallbackId : NULL;
  2504.                 pProto->stackErrorRtn(pSpare, &endErr);
  2505.                 }
  2506.             else                   /* muxBind: original prototype. */
  2507. pProto->stackErrorRtn (muxId->pEnd, &endErr, pProto->pSpare);
  2508.             }
  2509.         }
  2510.     return;
  2511.     }
  2512. /******************************************************************************
  2513. *
  2514. * muxDevStartAll - start all ENDs that have been loaded into the MUX
  2515. *
  2516. * This routine calls the "start" entry point for all ENDs loaded into the MUX.
  2517. *
  2518. * RETURNS: OK or ERROR
  2519. *
  2520. * SEE ALSO
  2521. * muxDevStopAll
  2522. *
  2523. * NOMANUAL
  2524. */
  2525. STATUS muxDevStartAll
  2526.     (
  2527.     )
  2528.     {
  2529.     END_TBL_ROW* pEndTblRow;    
  2530.     END_OBJ* pEnd;
  2531.     /* Mutual exclusion is necessary to protect <endList> access */
  2532.     semTake (muxLibState.lock, WAIT_FOREVER);
  2533.     
  2534.     /* Each Table row contains a list of ENDs for a particular driver */
  2535.     for (pEndTblRow = (END_TBL_ROW *)lstFirst(&endList); 
  2536.  pEndTblRow != NULL; 
  2537.  pEndTblRow = (END_TBL_ROW *)lstNext(&pEndTblRow->node))
  2538. {
  2539. /* Loop through all ENDs in the table row and call the stop routine */
  2540.         for (pEnd = (END_OBJ *)lstFirst(&pEndTblRow->units); 
  2541.      pEnd != NULL; 
  2542.              pEnd = (END_OBJ *)lstNext(&pEnd->node))
  2543.             {
  2544.             if (pEnd->pFuncTable->start != NULL)
  2545. {
  2546. (void) pEnd->pFuncTable->start(pEnd->devObject.pDevice);
  2547. }
  2548.     }    
  2549. }
  2550.     semGive (muxLibState.lock);
  2551.     return (OK);
  2552.     }
  2553. /******************************************************************************
  2554. *
  2555. * muxPollTask - the routine that runs as the MUX polling task.
  2556. *
  2557. * This routine does the actual polling.
  2558. *
  2559. * RETURNS: N/A
  2560. *
  2561. * NOMANUAL
  2562. */
  2563. void muxPollTask ()
  2564.     {
  2565.     int i;
  2566.     END_OBJ *pEnd;
  2567.     for(;;)
  2568.         {
  2569. semTake (muxLibState.lock, WAIT_FOREVER);
  2570. for (i = 0; i < muxPollDevCount; i++)
  2571.      {
  2572.      pEnd = PCOOKIE_TO_ENDOBJ (ppMuxPollDevices[i]);
  2573.      /* We check to see if there is already a mblk, if not get one */
  2574.      pMuxPollMblkRing[i] = pMuxPollMblkRing[i] ? pMuxPollMblkRing[i] :
  2575.  netTupleGet2 (pEnd->pNetPool, GET_IFMTU(pEnd), FALSE);
  2576.      if(!pMuxPollMblkRing[i])
  2577.  continue;
  2578.      if (!TK_DRV_CHECK (ppMuxPollDevices[i]))
  2579.          {
  2580.          if (pEnd->pFuncTable->pollRcv (pEnd, pMuxPollMblkRing[i]) == OK)
  2581.      {
  2582.                      muxReceive (pEnd, pMuxPollMblkRing[i]);
  2583.      pMuxPollMblkRing[i] = NULL;
  2584.      }
  2585.          }
  2586.              else
  2587.          {
  2588.  if (muxTkPollReceive2 (pEnd, pMuxPollMblkRing[i]) == OK);
  2589.      pMuxPollMblkRing[i] = NULL;
  2590.          }
  2591.             }
  2592.         semGive (muxLibState.lock);
  2593.         taskDelay (muxLibState.taskDelay);
  2594.         }
  2595.     }
  2596. /*****************************************************************************
  2597. *
  2598. * muxTaskDelaySet - set the inter-cycle delay on the polling task
  2599. *
  2600. * This routine sets up a delay (measured in ticks) that is inserted at the 
  2601. * end of each run through the list of devices polled by 'tMuxPollTask'.
  2602. *
  2603. * RETURNS: OK; or ERROR, if you specify a delay less than zero. 
  2604. *
  2605. */
  2606. STATUS muxTaskDelaySet
  2607.     (
  2608.     int delay
  2609.     )
  2610.     {
  2611.     if (delay < 0)
  2612.         return (ERROR);
  2613.     
  2614.     muxLibState.taskDelay = delay;
  2615.     return (OK);
  2616.     }
  2617. /*****************************************************************************
  2618. *
  2619. * muxTaskDelayGet - get the delay on the polling task
  2620. *
  2621. * This routine returns the amount of delay (in ticks) that is inserted 
  2622. * between the polling runs of 'tMuxPollTask'.  This value is written to
  2623. * the location specified by <pDelay>.
  2624. *
  2625. * RETURNS: OK; or ERROR, if NULL is passed in the <pDelay> variable. 
  2626. *
  2627. */
  2628. STATUS muxTaskDelayGet
  2629.     (
  2630.     int* pDelay
  2631.     )
  2632.     {
  2633.     if (pDelay == NULL)
  2634.         return (ERROR);
  2635.     
  2636.     *pDelay = muxLibState.taskDelay;
  2637.     return (OK);
  2638.     }
  2639.     
  2640. /*****************************************************************************
  2641. *
  2642. * muxTaskPrioritySet - reset the priority of 'tMuxPollTask'
  2643. *
  2644. * This routine resets the priority of a running 'tMuxPollTask'.  Valid 
  2645. * task priorities are values between zero and 255 inclusive.  However, 
  2646. * do not set the priority of 'tMuxPollTask' to exceed that of 'tNetTask'. 
  2647. * Otherwise, you will shut out 'tNetTask' from getting any processor time. 
  2648. *
  2649. * RETURNS: OK; or ERROR, if you specify a non-valid priority value. 
  2650. *
  2651. */
  2652. STATUS muxTaskPrioritySet
  2653.     (
  2654.     int priority
  2655.     )
  2656.     {
  2657.     if (priority < 0 || priority > 255)
  2658.         return (ERROR);
  2659.     
  2660.     muxLibState.priority = priority;
  2661.     /*
  2662.      * If we're in polling mode then the task must be running.
  2663.      * So, find the task and update it's priority.
  2664.      */
  2665.      if (muxLibState.taskID)
  2666.         if (taskPrioritySet (muxLibState.taskID, muxLibState.priority) == ERROR)
  2667.             {
  2668.             if (muxLibState.debug)
  2669.                 {
  2670.                 logMsg("Invalid muxPollTask taskIDn", 1, 2, 3, 4, 5, 6);
  2671.                 }
  2672.             }
  2673.     return (OK);
  2674.     }
  2675. /*****************************************************************************
  2676. *
  2677. * muxTaskPriorityGet - get the priority of 'tMuxPollTask'
  2678. *
  2679. * This routine returns the current priority of 'tMuxPollTask'. This value
  2680. * is returned to the location specified by the <pPriority> parameter. 
  2681. *
  2682. * RETURNS: OK; or ERROR, if NULL is passed in the <pPriority> parameter.
  2683. *
  2684. */
  2685. STATUS muxTaskPriorityGet
  2686.     (
  2687.     int* pPriority
  2688.     )
  2689.     {
  2690.     if (pPriority == NULL)
  2691.         return (ERROR);
  2692.     
  2693.     *pPriority = muxLibState.priority;
  2694.     return (OK);
  2695.     }
  2696.    
  2697. /*****************************************************************************
  2698. *
  2699. * muxPollStart - initialize and start the MUX poll task
  2700. *
  2701. * This routine initializes and starts the MUX poll task, 'tMuxPollTask'.  
  2702. * This task runs an infinite loop in which it polls each of the interfaces 
  2703. * referenced on a list of network interfaces. To add or remove devices 
  2704. * from this list, use muxPollDevAdd() and muxPollDevDel(). Removing all 
  2705. * devices from the list automatically triggers a call to muxPollEnd(), 
  2706. * which shuts down 'tMuxPollTask'.
  2707. * Using the <priority> parameter, you assign the priority to 'tMuxPollTask'.
  2708. * Valid values are between 0 and 255, inclusive. However, you must not set
  2709. * the priority of 'tMuxPollTask' to exceed that of 'tNetTask'. Otherwise, 
  2710. * you risk shutting 'tNetTask' out from getting processor time. To reset 
  2711. * the 'tMuxPollTask' priority after launch, use muxTaskPrioritySet(). 
  2712. *
  2713. * Using the <delay> parameter, you can set up a delay at the end of each 
  2714. * trip though the poll list. To reset the value of this delay after the 
  2715. * launch of 'tNetTask', call muxTaskDelaySet(). 
  2716. *
  2717. * To shut down 'tMuxPollTask', call muxPollEnd(). 
  2718. * RETURNS: OK or ERROR
  2719. *
  2720. */
  2721. STATUS muxPollStart
  2722.     (
  2723.     int numDev,     /* Maximum number of devices to support poll mode. */
  2724.     int priority,   /* tMuxPollTask priority, not to exceed tNetTask. */
  2725.     int delay       /* Delay, in ticks, at end of each polling cycle. */
  2726.     )
  2727.     {
  2728.     int i;
  2729.     if (!(numDev > 0))
  2730. return (ERROR);
  2731.     if (priority < 0 || priority > 255 || delay < 0)
  2732.         return (ERROR);
  2733.    
  2734.     muxLibState.priority = priority;
  2735.     muxLibState.taskDelay = delay;
  2736.     if (!muxLibState.lock)
  2737. return (ERROR);
  2738.     ppMuxPollDevices = (void **) KHEAP_ALLOC ((numDev + 1) * sizeof (void *));
  2739.     if (!ppMuxPollDevices)
  2740. return (ERROR);
  2741.     for (i = 0; i <= numDev; i++)
  2742.   ppMuxPollDevices[i] = NULL;
  2743.     pMuxPollMblkRing = (M_BLK_ID *) KHEAP_ALLOC ((numDev + 1) * sizeof (M_BLK_ID));
  2744.     if (!pMuxPollMblkRing)
  2745. {
  2746. KHEAP_FREE ((char *)ppMuxPollDevices);
  2747. return (ERROR);
  2748.         }
  2749.     for (i = 0; i <= numDev; i++)
  2750.   pMuxPollMblkRing[i] = NULL;
  2751.     muxPollDevMax = numDev;
  2752.     muxPollDevCount = 0;
  2753.     muxLibState.taskID = taskSpawn ("tMuxPollTask", priority, 0, 0x4000, 
  2754.    (FUNCPTR)muxPollTask, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
  2755.     if (muxLibState.taskID == ERROR)
  2756. {
  2757.         semDelete (muxLibState.lock);
  2758. KHEAP_FREE ((char *)ppMuxPollDevices);
  2759. KHEAP_FREE ((char *)pMuxPollMblkRing);
  2760. muxLibState.taskID = 0;
  2761. return (ERROR);
  2762. }
  2763.     return (OK);
  2764.     }
  2765. /*****************************************************************************
  2766. *
  2767. * muxPollEnd - shuts down 'tMuxPollTask' and returns devices to interrupt mode
  2768. *
  2769. * This routine shuts down 'tMuxPollTask' and returns network devices to run in 
  2770. * their interrupt-driven mode. 
  2771. *
  2772. * RETURNS: OK or ERROR
  2773. *
  2774. */
  2775. STATUS muxPollEnd ()
  2776.     {
  2777.     int i;
  2778.     void **pList;
  2779.     if (!muxLibState.taskID)
  2780. return (ERROR);
  2781.     semTake (muxLibState.lock, WAIT_FOREVER);
  2782.     taskDelete (muxLibState.taskID);
  2783.     muxLibState.taskID = 0;
  2784.     for (pList = ppMuxPollDevices; *pList; pList++)
  2785.          muxIoctl(*pList, EIOCPOLLSTOP, NULL);
  2786.          
  2787.     KHEAP_FREE ((char *)ppMuxPollDevices);
  2788.     for (i = 0; i < muxPollDevCount; i++)
  2789.  if (pMuxPollMblkRing[i])
  2790.       netMblkClChainFree (pMuxPollMblkRing[i]);
  2791.     KHEAP_FREE ((char *)pMuxPollMblkRing);
  2792.     semGive (muxLibState.lock);
  2793.     return (OK);
  2794.     }
  2795. /*****************************************************************************
  2796. *
  2797. * muxPollDevAdd - adds a device to list polled by 'tMuxPollTask'
  2798. *
  2799. * This routine adds a device to list of devices polled by 'tMuxPollTask'. It 
  2800. * assumes that you have already called muxPollStart() and that 'tMuxPollTask' 
  2801. * is still running.  
  2802. *
  2803. * NOTE: You cannot use a device for WDB_COMM_END type debugging while that 
  2804. * device is on the 'tMuxPollTask' poll list. 
  2805. *
  2806. * RETURNS: OK or ERROR
  2807. *
  2808. */
  2809. STATUS muxPollDevAdd
  2810.     (
  2811.     int unit, /* Device unit number */
  2812.     char *pName /* Device name */
  2813.     )
  2814.     {
  2815.     void *pCookie = NULL;
  2816.     END_OBJ *pEnd = NULL;
  2817.      
  2818.     pCookie = muxTkCookieGet (pName, unit);
  2819.     if (muxPollDevStat (unit, pName) == TRUE)
  2820. return (ERROR);
  2821.     if (!muxLibState.taskID || !pCookie)
  2822.         return (ERROR);
  2823.     pEnd = PCOOKIE_TO_ENDOBJ(pCookie);
  2824.     if (pEnd == NULL)
  2825.         return (ERROR);
  2826.     
  2827.     if ( (pEnd->flags & END_MIB_2233) && (pEnd->pMib2Tbl == NULL) )
  2828. return (ERROR);
  2829.     semTake (muxLibState.lock, WAIT_FOREVER);
  2830.     if (muxPollDevCount == muxPollDevMax)
  2831. {
  2832.         semGive (muxLibState.lock);
  2833. return (ERROR);
  2834.         } 
  2835.     
  2836.     if (muxIoctl (pCookie, EIOCPOLLSTART, NULL) == ERROR)
  2837. {
  2838.         semGive (muxLibState.lock);
  2839. return (ERROR);
  2840.         } 
  2841.     ppMuxPollDevices[muxPollDevCount++] = pCookie;
  2842.     semGive (muxLibState.lock);
  2843.     return (OK);
  2844.     }
  2845. /*****************************************************************************
  2846. *
  2847. * muxPollDevDel - removes a device from the list polled by 'tMuxPollTask'
  2848. *
  2849. * This routine removes a device from the list of devices polled by 
  2850. * 'tMuxPollTask'. If you remove the last device on the list, a call to 
  2851. * muxPollDevDel() also makes an internal call to muxPollEnd().  This shuts 
  2852. * down 'tMuxPollTask' completely.  
  2853. *
  2854. * RETURNS: OK or ERROR
  2855. *
  2856. */
  2857. STATUS muxPollDevDel
  2858.     (
  2859.     int unit, /* Device unit number */
  2860.     char *pName /* Device name */
  2861.     )
  2862.     {
  2863.     int i;
  2864.     void *pCookie;
  2865.     void **pList;
  2866.     pCookie = muxTkCookieGet (pName, unit);
  2867.     if (!muxLibState.taskID || !pCookie)
  2868.         return (ERROR);
  2869.     semTake (muxLibState.lock, WAIT_FOREVER);
  2870.     for (i = 0; (i < muxPollDevCount) && (ppMuxPollDevices[i] != pCookie); i++);
  2871.     if ((pList = (ppMuxPollDevices + i)) != pCookie)
  2872. {
  2873. semGive (muxLibState.lock);
  2874. return (ERROR);
  2875. }
  2876.     muxIoctl (pCookie, EIOCPOLLSTOP, NULL);
  2877.     if (pMuxPollMblkRing[i])
  2878.          netMblkClChainFree (pMuxPollMblkRing[i]);
  2879.     pMuxPollMblkRing[i] = NULL;
  2880.     /* 
  2881.      * We don't care about order! So when a device is removed,
  2882.      * we take the last device on the list and fill in the spot
  2883.      * that was just cleared up. Notice that this is harmless
  2884.      * if one device is left.
  2885.      */
  2886.     if (--muxPollDevCount > 0)
  2887. {
  2888.         pList = ppMuxPollDevices + muxPollDevCount;
  2889. ppMuxPollDevices[muxPollDevCount] = NULL;
  2890. pMuxPollMblkRing[i] = pMuxPollMblkRing[muxPollDevCount];
  2891. }
  2892.     else
  2893. {
  2894. semGive (muxLibState.lock);
  2895. /* Remove muxPollTask if there are no devices left */
  2896. return (muxPollEnd ());
  2897. }
  2898.     semGive (muxLibState.lock);
  2899.     return (OK);
  2900.     }
  2901. /*****************************************************************************
  2902. *
  2903. * muxPollDevStat - reports whether device is on list polled by 'tMuxPollTask'
  2904. *
  2905. * This routine returns true or false depending on whether the specified 
  2906. * device is on the list of devices polled by 'tMuxPollTask'. 
  2907. *
  2908. * RETURNS: TRUE, if it is; or FALSE.
  2909. *
  2910. */
  2911. BOOL muxPollDevStat
  2912.     (
  2913.     int unit, /* Device unit number */
  2914.     char *pName /* Device name */
  2915.     )
  2916.     {
  2917.     int i;
  2918.     void *pCookie;
  2919.     
  2920.     pCookie = muxTkCookieGet (pName, unit);
  2921.     if (!muxLibState.taskID || !pCookie)
  2922.         return (FALSE);
  2923.     semTake (muxLibState.lock, WAIT_FOREVER);
  2924.     for (i = 0; (i < muxPollDevCount) && (ppMuxPollDevices[i] != pCookie); i++);
  2925.     if (ppMuxPollDevices[i] != pCookie)
  2926. {
  2927. semGive (muxLibState.lock);
  2928. return (FALSE);
  2929. }
  2930.     semGive (muxLibState.lock);
  2931.     return (TRUE);
  2932.     }
  2933. #ifdef ROUTER_STACK
  2934. /****************************************************************************
  2935. *
  2936. * muxProtoPrivDataGet - Returns the private data for the protocol specified
  2937. *
  2938. * This routine returns private data (specified by the <pSpare> pointer in the
  2939. * muxBind() call) for the specified protocol, <proto>, bound to the
  2940. * END device <pEnd>.
  2941. *
  2942. * RETURNS: The protocol specific private data if the protocol is bound to
  2943. * the MUX; NULL, otherwise.
  2944. *
  2945. * ERRNO:
  2946. * S_muxLib_NO_DEVICE
  2947. *
  2948. * NOMANUAL
  2949. * NOTE: Currently this is used only by Fastpath
  2950. */
  2951. void * muxProtoPrivDataGet 
  2952.     (
  2953.     END_OBJ * pEnd, /* Points to the END device */
  2954.     int proto /* The protocol whose private data is desired */
  2955.     )
  2956.     {
  2957.     NET_PROTOCOL * pProto;
  2958.     if (pEnd == NULL)
  2959.         {
  2960.         errno = S_muxLib_NO_DEVICE;
  2961.         return (NULL);
  2962.         }
  2963.     /* Loop through the protocol list, looking for the IP protocol binding. */
  2964.     for (pProto = (NET_PROTOCOL *)lstFirst (&pEnd->protocols); 
  2965.          pProto != NULL; pProto = (NET_PROTOCOL *)lstNext (&pProto->node))
  2966. {
  2967.         if (pProto->type == proto)   
  2968.             {
  2969.             return (pProto->pSpare);
  2970.             }
  2971.         }
  2972.     return (NULL);
  2973.     }
  2974. #endif /* ROUTER_STACK */