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

VxWorks

开发平台:

C/C++

  1.             printf (" %sn", rt->rt_ifp->int_name);
  2.             /* Now figure out all the state. */
  3.             if (rt->rt_state & RTS_CHANGED)
  4.                 printf ("RTS_CHANGED ");
  5.             if (rt->rt_state & RTS_EXTERNAL)
  6.                 printf ("RTS_EXTERNAL ");
  7.             if (rt->rt_state & RTS_INTERNAL)
  8.                 printf ("RTS_INTERNAL ");
  9.             if (rt->rt_state & RTS_PASSIVE)
  10.                 printf ("RTS_PASSIVE ");
  11.             if (rt->rt_state & RTS_INTERFACE)
  12.                 printf ("RTS_INTERFACE ");
  13.             if (rt->rt_state & RTS_REMOTE)
  14.                 printf ("RTS_REMOTE ");
  15.             if (rt->rt_state & RTS_SUBNET)
  16.                 printf ("RTS_SUBNET ");
  17.             if (rt->rt_state & RTS_OTHER)
  18.                 {
  19.                 printf ("RTS_OTHER ");
  20.                 if (rt->rt_state & RTS_PRIMARY)
  21.                     printf ("RTS_PRIMARY ");
  22.                 }
  23.             if (rt->rt_ifp && (rt->rt_ifp->int_flags & IFF_UP) == 0)
  24.                 printf ("DOWN ");
  25.             printf ("n");
  26.             }
  27.         }
  28.     if (doinghost)
  29.         {
  30.         printf ("-----------------------------------------------------------------n");
  31.         doinghost = 0;
  32.         base = nethash;
  33.         goto again;
  34.         }
  35.     return;
  36.     }
  37. /*****************************************************************************
  38. *
  39. * ripSetInterfaces - add all multicast interfaces to address group
  40. *
  41. * This routine sets all interfaces that are multicast capable into the
  42. * multicast group address passed in as an argument.
  43. *
  44. * RETURNS: N/A
  45. *
  46. * NOMANUAL
  47. */
  48. void ripSetInterfaces
  49.     (
  50.     INT32 sock,
  51.     UINT32 mcastAddr                          /* Address to join. */
  52.     )
  53.     {
  54.     struct ip_mreq ipMreq; /* Multicast structure for version 2 */
  55.     struct interface *  pIf;
  56.     UINT32  addr;
  57.     for (pIf = ripIfNet; pIf; pIf = pIf->int_next)
  58.         {
  59.         addr = ((struct sockaddr_in *)&(pIf->int_addr))->sin_addr.s_addr; 
  60.         ipMreq.imr_multiaddr.s_addr = htonl (mcastAddr);
  61.         ipMreq.imr_interface.s_addr = addr;
  62.         if (setsockopt (sock, IPPROTO_IP, IP_ADD_MEMBERSHIP,
  63.                         (char *)&ipMreq, sizeof (ipMreq)) < 0)
  64.             { 
  65.             if (routedDebug)
  66.                 logMsg ("setsockopt IP_ADD_MEMBERSHIP error:n",
  67.                         0, 0, 0, 0, 0, 0); 
  68.             }
  69.         }
  70.     }
  71. /*****************************************************************************
  72. *
  73. * ripClearInterfaces - remove all multicast interfaces from address group
  74. *
  75. * This routine removes all interfaces that are multicast capable from the
  76. * multicast group address given by <mcastAddr>. It is called when changing
  77. * the receive control switch from RIP-2 only mode with SNMP. Although it 
  78. * seems acceptable to allow membership in the multicast group unless the 
  79. * receive switch is set to RIP-1 only mode, ANVL test 16.1 would fail.
  80. *
  81. * RETURNS: N/A
  82. *
  83. * NOMANUAL
  84. */
  85. void ripClearInterfaces
  86.     (
  87.     INT32 sock,
  88.     UINT32 mcastAddr                          /* Address to join. */
  89.     )
  90.     {
  91.     struct ip_mreq ipMreq; /* Multicast structure for version 2 */
  92.     struct interface *  pIf;
  93.     UINT32  addr;
  94.     for (pIf = ripIfNet; pIf; pIf = pIf->int_next)
  95.         {
  96.         addr = ((struct sockaddr_in *)&(pIf->int_addr))->sin_addr.s_addr; 
  97.         ipMreq.imr_multiaddr.s_addr = htonl (mcastAddr);
  98.         ipMreq.imr_interface.s_addr = addr;
  99.         if (setsockopt (sock, IPPROTO_IP, IP_DROP_MEMBERSHIP,
  100.                         (char *)&ipMreq, sizeof (ipMreq)) < 0)
  101.             { 
  102.             if (routedDebug)
  103.                 logMsg ("setsockopt IP_DROP_MEMBERSHIP error.n",
  104.                         0, 0, 0, 0, 0, 0); 
  105.             }
  106.         }
  107.     }
  108. /******************************************************************************
  109. *
  110. * _ripIfShow - display information about an interface 
  111. *
  112. * This routine prints information about an interface entry.
  113. * The interface name, interface index, the UP/DOWN status and the 
  114. * interface address and netmask are displayed.
  115. *
  116. * RETURNS: N/A
  117. *
  118. * ERRNO: N/A
  119. *
  120. * NOMANUAL
  121. */
  122. void _ripIfShow 
  123.     (
  124.     struct interface *  pIf
  125.     )
  126.     {
  127.     char  address[32];
  128.     struct in_addr  sin_addr;
  129.     printf ("%-8s%-8d%-12s",
  130.             pIf->int_name, pIf->int_index,
  131.             (pIf->int_flags & IFF_UP) == IFF_UP ? "UP" : "DOWN");
  132.     inet_ntoa_b (((struct sockaddr_in *)&(pIf->int_addr))->sin_addr, 
  133.                  address);
  134.     printf ("%-17s", address);
  135.     sin_addr.s_addr = htonl (pIf->int_subnetmask);
  136.     inet_ntoa_b (sin_addr, address);
  137.     printf ("%-17s", address);
  138.     inet_ntoa_b (((struct sockaddr_in *)&(pIf->int_broadaddr))->sin_addr, 
  139.                  address);
  140.     printf ("%-17sn", address);
  141.     return;
  142. }
  143. /******************************************************************************
  144. *
  145. * ripIfShow - display the internal interface table maintained by RIP
  146. *
  147. * This routine prints every entry in the local RIP interface table. 
  148. * The interface name, interface index, the UP/DOWN status and the 
  149. * interface address and netmask are displayed.
  150. *
  151. * RETURNS: N/A
  152. *
  153. * ERRNO: N/A
  154. */
  155. void ripIfShow (void)
  156.     {
  157.     struct interface *  pIf;
  158.     if (!ripInitFlag)
  159.         return;
  160.     /* Block all processing to guarantee a stable list of interfaces. */
  161.     semTake (ripLockSem, WAIT_FOREVER);
  162.  
  163.     /*
  164.      * Loop through the interface list printing out the 
  165.      * interface name    index   UP/DOWN status    I/f addr    I/f netmask
  166.      */
  167.     printf ("Name    Index   Up/Down     Address          Netmask          "
  168.             "Broadcastn");
  169.     for (pIf = ripIfNet; pIf; pIf = pIf->int_next)
  170.         _ripIfShow (pIf);
  171.                 
  172.     semGive (ripLockSem);
  173.     return;
  174.     }
  175. /******************************************************************************
  176. *
  177. * ripAuthHookAdd - add an authentication hook to a RIP interface
  178. *
  179. * This routine installs a hook routine to validate incoming RIP messages
  180. * for a registered interface given by <pIpAddr>. (Interfaces created or
  181. * changed after a RIP session has started may be installed/updated with the
  182. * ripIfSearch() and ripIfReset() routines). The hook is only called if
  183. * an SNMP agent enables authentication for the corresponding interface.
  184. * It uses the following prototype:
  185. *
  186. * cs
  187. *     STATUS ripAuthHookRtn (char *pKey, RIP_PKT *pRip);
  188. * ce
  189. * The first argument contains the authentication key for the message
  190. * stored in the rip2IfConfAuthKey MIB variable and the second argument 
  191. * uses the RIP_PKT structure (defined in rip/ripLib.h) to access the message 
  192. * body. The routine must return OK if the message is acceptable, or ERROR 
  193. * otherwise. All RIP-2 messages sent to that routine already contain an 
  194. * authentication entry, but have not been verified. (Any unauthenticated
  195. * RIP-2 messages have already been discarded as required by the RFC 
  196. * specification). RIP-1 messages may be accepted or rejected. RIP-2 messages
  197. * requesting simple password authentication that match the key are
  198. * accepted automatically before the hook is called. The remaining RIP-2
  199. * messages either did not match that key or are using an unknown 
  200. * authentication type. If any messages are rejected, the MIB-II counters are 
  201. * updated appropriately outside of the hook routine.
  202. *
  203. * The current RIP implementation contains a sample authentication hook that
  204. * you may add as follows:
  205. *
  206. * cs
  207. *     if (ripAuthHookAdd ("90.0.0.1", ripAuthHook) == ERROR)
  208. *         logMsg ("Unable to add authorization hook.n", 0, 0, 0, 0, 0, 0);
  209. * ce
  210. *
  211. * The sample routine supports only simple password authentication against
  212. * the key included in the MIB variable. Since all such messages have already
  213. * been accepted, all RIP-2 messages received by the routine are discarded.
  214. * All RIP-1 messages are also discarded, so the hook actually has no
  215. * effect. The body of that routine is:
  216. *
  217. * cs
  218. * STATUS ripAuthHook
  219. *    (
  220. *    char *  pKey,  /@ rip2IfConfAuthKey entry from MIB-II family @/
  221. *    RIP_PKT *  pRip  /@ received RIP message @/
  222. *    )
  223. *    {
  224. *    if (pRip->rip_vers == 1)
  225. *        {
  226. *        /@ 
  227. *         @ The RFC specification recommends, but does not require, rejecting
  228. *         @ version 1 packets when authentication is enabled.
  229. *         @/
  230. *
  231. *        return (ERROR);
  232. *        }
  233. *
  234. *    /@
  235. *     @ The authentication type field in the RIP message corresponds to
  236. *     @ the first two bytes of the sa_data field overlayed on that
  237. *     @ message by the sockaddr structure contained within the RIP_PKT 
  238. *     @ structure (see rip/ripLib.h).
  239. *     @/
  240. *
  241. *    if ( (pRip->rip_nets[0].rip_dst.sa_data[0] != 0) ||
  242. *        (pRip->rip_nets[0].rip_dst.sa_data[1] !=
  243. *        M2_rip2IfConfAuthType_simplePassword))
  244. *        {
  245. *        /@ Unrecognized authentication type. @/
  246. *
  247. *        return (ERROR);
  248. *        }
  249. *
  250. *    /@ 
  251. *     @ Discard version 2 packets requesting simple password authentication
  252. *     @ which did not match the MIB variable. 
  253. *     @/
  254. *
  255. *    return (ERROR);
  256. *    }
  257. * ce
  258. *
  259. * A comparison against a different key could be performed as follows:
  260. *
  261. * cs
  262. *  bzero ( (char *)&key, AUTHKEYLEN);    /@ AUTHKEYLEN from rip/m2RipLib.h @/
  263. *
  264. *   /@
  265. *    @ The start of the authorization key corresponds to the third byte
  266. *    @ of the sa_data field in the sockaddr structure overlayed on the
  267. *    @ body of the RIP message by the RIP_PKT structure. It continues
  268. *    @ for the final 14 bytes of that structure and the first two bytes
  269. *    @ of the following rip_metric field.
  270. *    @/
  271. *
  272. *  bcopy ( (char *)(pRip->rip_nets[0].rip_dst.sa_data + 2),
  273. *         (char *)&key, AUTHKEYLEN);
  274. *
  275. *  if (bcmp ( (char *)key, privateKey, AUTHKEYLEN) != 0)
  276. *      {
  277. *      /@ Key does not match: reject message. @/
  278. *
  279. *      return (ERROR);
  280. *      }
  281. *  return (OK);
  282. * ce
  283. *
  284. * The ripAuthHookDelete() routine will remove the installed function. If
  285. * authentication is still enabled for the interface, all incoming messages
  286. * that do not use simple password authentication will be rejected until a
  287. * routine is provided.
  288. *
  289. * RETURNS: OK, if hook added; or ERROR otherwise.
  290. *
  291. * ERRNO:
  292. *  S_m2Lib_INVALID_PARAMETER
  293. *  S_m2Lib_ENTRY_NOT_FOUND
  294. */
  295. STATUS ripAuthHookAdd
  296.     (
  297.     char* pIpAddr, /* IP address in dotted decimal notation */
  298.     FUNCPTR pAuthHook /* routine to handle message authentication */
  299.     )
  300.     {
  301.     struct interface* pIfp;
  302.     struct sockaddr_in address;
  303.     if (!ripInitFlag)
  304.         return (ERROR);
  305.     if (pIpAddr == NULL)
  306.         {
  307.         errnoSet (S_m2Lib_INVALID_PARAMETER);
  308.         return (ERROR);
  309.         }
  310.     address.sin_len = sizeof (address);
  311.     address.sin_addr.s_addr = inet_addr (pIpAddr);
  312.     address.sin_family = AF_INET;
  313.     
  314.     pIfp = ripIfLookup ((struct sockaddr *)&address);
  315.     if (pIfp == NULL)
  316.         {
  317.         errnoSet (S_m2Lib_ENTRY_NOT_FOUND);
  318.         return (ERROR);
  319.         }
  320.     /* Short critical section with input processing. */
  321.     semTake (ripLockSem, WAIT_FOREVER);    
  322.     pIfp->authHook = pAuthHook;
  323.     semGive (ripLockSem);
  324.  
  325.     return (OK);
  326.     }
  327. /******************************************************************************
  328. *
  329. * ripAuthHookDelete - remove an authentication hook from a RIP interface
  330. *
  331. * This routine removes an assigned authentication hook from a registered
  332. * interface indicated by <pIpAddr>. (Interfaces created or changed after 
  333. * a RIP session has started may be installed/updated with the ripIfSearch() 
  334. * and ripIfReset() routines). If authentication is still enabled for the 
  335. * interface, RIP-2 messages using simple password authentication will be
  336. * accepted if they match the key in the MIB variable, but all other incoming 
  337. * messages will be rejected until a routine is provided.
  338. *
  339. * RETURNS: OK; or ERROR, if the interface could not be found.
  340. *
  341. * ERRNO:
  342. *  S_m2Lib_INVALID_PARAMETER
  343. *  S_m2Lib_ENTRY_NOT_FOUND
  344. */
  345. STATUS ripAuthHookDelete
  346.     (
  347.     char* pIpAddr /* IP address in dotted decimal notation */
  348.     )
  349.     {
  350.     struct interface* pIfp;
  351.     struct sockaddr_in address;
  352.     if (!ripInitFlag)
  353.         return (ERROR);
  354.     if (pIpAddr == NULL)
  355.         {
  356.         errnoSet (S_m2Lib_INVALID_PARAMETER);
  357.         return (ERROR);
  358.         }
  359.     address.sin_len = sizeof (address);
  360.     address.sin_addr.s_addr = inet_addr (pIpAddr);
  361.     address.sin_family = AF_INET;
  362.     
  363.     pIfp = ripIfLookup ( (struct sockaddr *)&address);
  364.     if (pIfp == NULL)
  365.         {
  366.         errnoSet (S_m2Lib_ENTRY_NOT_FOUND);
  367.         return (ERROR);
  368.         }
  369.     /* Short critical section with input processing. */
  370.  
  371.     semTake (ripLockSem, WAIT_FOREVER);    
  372.     pIfp->authHook = NULL;
  373.     semGive (ripLockSem);
  374.  
  375.     return (OK);
  376.     }
  377. /******************************************************************************
  378. *
  379. * ripAuthCheck - verify RIP messages if authentication is enabled
  380. *
  381. * This routine accepts all RIP-2 messages using simple password
  382. * authentication that match the key in the MIB variable. It is
  383. * called automatically when authentication is enabled. All other
  384. * RIP-2 messages and any RIP-1 messages may be accepted by an
  385. * authentication hook, or will be discarded if no hook is present.
  386. *
  387. * RETURNS: OK, if message is acceptable; or ERROR otherwise.
  388. *
  389. * NOMANUAL
  390. */
  391. STATUS ripAuthCheck
  392.     (
  393.     char *  pKey,  /* rip2IfConfAuthKey entry from MIB-II family */
  394.     RIP_PKT *  pRip  /* received RIP message */
  395.     )
  396.     {
  397.     if (pRip->rip_vers == 1)
  398.         {
  399.         /* 
  400.          * The RFC specification recommends, but does not require, rejecting
  401.          * version 1 packets when authentication is enabled. Those packets
  402.          * will be discarded unless accepted by the hook.
  403.          */
  404.         return (ERROR);
  405.         }
  406.     /*
  407.      * The authentication type field in the RIP message corresponds to
  408.      * the first two bytes of the sa_data field overlayed on that
  409.      * message by the sockaddr structure contained within the RIP_PKT 
  410.      * structure (see rip/ripLib.h).
  411.      */
  412.     if ((pRip->rip_nets[0].rip_dst.sa_data[0] != 0) ||
  413.         (pRip->rip_nets[0].rip_dst.sa_data[1] !=
  414.          M2_rip2IfConfAuthType_simplePassword))
  415.         {
  416.         /* 
  417.          * Reject messages with an unrecognized authentication type. This
  418.          * behavior can be overridden by the user's authentication hook.
  419.          */
  420.         return (ERROR);
  421.         }
  422.     /*
  423.      * The start of the authorization key corresponds to the third byte
  424.      * of the sa_data field in the sockaddr structure and continues for
  425.      * AUTHKEYLEN bytes (defined in rip/m2RipLib.h).
  426.      */
  427.     if (bcmp ( (char *)(pRip->rip_nets[0].rip_dst.sa_data + 2), 
  428.               pKey, AUTHKEYLEN) != 0)
  429.         {
  430.         return (ERROR);
  431.         }
  432.     /*
  433.      * Accept version 2 packets requesting simple password 
  434.      * authentication that matched the MIB variable.
  435.      */
  436.     return (OK);
  437.     }
  438. /******************************************************************************
  439. *
  440. * ripAuthHook - sample authentication hook
  441. *
  442. * This hook demonstrates one possible authentication mechanism. It rejects
  443. * all RIP-2 messages that used simple password authentication since they
  444. * did not match the key contained in the MIB variable. All other RIP-2
  445. * messages are also rejected since no other authentication type is
  446. * supported and all RIP-1 messages are also rejected, as recommended by
  447. * the RFC specification. This behavior is the same as if no hook were 
  448. * installed.
  449. *
  450. * RETURNS: OK, if message is acceptable; or ERROR otherwise.
  451. */
  452. STATUS ripAuthHook
  453.     (
  454.     char *      pKey,   /* rip2IfConfAuthKey entry from MIB-II family */
  455.     RIP_PKT *   pRip    /* received RIP message */
  456.     )
  457.     {
  458.     if (pRip->rip_vers == 1)
  459.         {
  460.         /*
  461.          * The RFC specification recommends, but does not require, rejecting
  462.          * version 1 packets when authentication is enabled.
  463.          */
  464.         return (ERROR);
  465.         }
  466.     /*
  467.      * The authentication type field in the RIP message corresponds to
  468.      * the first two bytes of the sa_data field overlayed on that
  469.      * message by the sockaddr structure contained within the RIP_PKT
  470.      * structure (see rip/ripLib.h).
  471.      */
  472.     if ((pRip->rip_nets[0].rip_dst.sa_data[0] != 0) ||
  473.         (pRip->rip_nets[0].rip_dst.sa_data[1] !=
  474.          M2_rip2IfConfAuthType_simplePassword))
  475.         {
  476.         /* Unrecognized authentication type. */
  477.         return (ERROR);
  478.         }
  479.     /*
  480.      * Discard version 2 packets requesting simple password
  481.      * authentication that did not match the MIB variable.
  482.      */
  483.     return (ERROR);
  484.     }
  485. /******************************************************************************
  486. *
  487. * ripLeakHookAdd - add a hook to bypass the RIP and kernel routing tables
  488. *
  489. * This routine installs a hook routine to support alternative routing
  490. * protocols for the registered interface given by <pIpAddr>. (Interfaces 
  491. * created or changed after a RIP session has started may be installed/updated
  492. * with the ripIfSearch() and ripIfReset() routines). 
  493. *
  494. * The hook uses the following interface:
  495. * cs
  496. *     STATUS ripLeakHookRtn (long dest, long gateway, long netmask)
  497. * ce
  498. *
  499. * The RIP session will not add the given route to any tables if the hook
  500. * routine returns OK, but will create a route entry otherwise.
  501. *
  502. * The ripLeakHookDelete() will allow the RIP session to add new routes
  503. * unconditionally.
  504. *
  505. * RETURNS: OK; or ERROR, if the interface could not be found.
  506. *
  507. * ERRNO:
  508. *  S_m2Lib_INVALID_PARAMETER
  509. *  S_m2Lib_ENTRY_NOT_FOUND
  510. */
  511. STATUS ripLeakHookAdd
  512.     (
  513.     char *  pIpAddr, /* IP address in dotted decimal notation */
  514.     FUNCPTR  pLeakHook /* function pointer to hook */
  515.     )
  516.     {
  517.     struct interface* pIfp;
  518.     struct sockaddr_in address;
  519.     if (!ripInitFlag)
  520.         return (ERROR);
  521.     if (pIpAddr == NULL)
  522.         {
  523.         errnoSet (S_m2Lib_INVALID_PARAMETER);
  524.         return (ERROR);
  525.         }
  526.     address.sin_len = sizeof (address);
  527.     address.sin_addr.s_addr = inet_addr (pIpAddr);
  528.     address.sin_family = AF_INET;
  529.     
  530.     pIfp = ripIfLookup ((struct sockaddr *)&address);
  531.     if (pIfp == NULL)
  532.         {
  533.         errnoSet (S_m2Lib_ENTRY_NOT_FOUND);
  534.         return (ERROR);
  535.         }
  536.     /* Short critical section with message and timer processing. */
  537.  
  538.     semTake (ripLockSem, WAIT_FOREVER);    
  539.     pIfp->leakHook = pLeakHook;
  540.     semGive (ripLockSem);
  541.     return (OK);
  542.     }
  543. /******************************************************************************
  544. *
  545. * ripLeakHookDelete - remove a table bypass hook from a RIP interface
  546. *
  547. * This routine removes the assigned bypass hook from a registered interface
  548. * indicated by <pIpAddr>. (Interfaces created or changed after a RIP
  549. * session has started may be installed/updated with the ripIfSearch() 
  550. * and ripIfReset() routines). The RIP session will return to the default 
  551. * behavior and add entries to the internal RIP table and kernel routing 
  552. * table unconditionally.
  553. *
  554. * RETURNS: OK; or ERROR, if the interface could not be found.
  555. *
  556. * ERRNO:
  557. *  S_m2Lib_INVALID_PARAMETER
  558. *  S_m2Lib_ENTRY_NOT_FOUND
  559. */
  560. STATUS ripLeakHookDelete
  561.     (
  562.     char* pIpAddr /* IP address in dotted decimal notation */
  563.     )
  564.     {
  565.     struct interface* pIfp;
  566.     struct sockaddr_in address;
  567.     if (!ripInitFlag)
  568.         return (ERROR);
  569.     if (pIpAddr == NULL)
  570.         {
  571.         errnoSet (S_m2Lib_INVALID_PARAMETER);
  572.         return (ERROR);
  573.         }
  574.     address.sin_len = sizeof (address);
  575.     address.sin_addr.s_addr = inet_addr (pIpAddr);
  576.     address.sin_family = AF_INET;
  577.     
  578.     pIfp = ripIfLookup ((struct sockaddr *)&address);
  579.     if (pIfp == NULL)
  580.         {
  581.         errnoSet (S_m2Lib_ENTRY_NOT_FOUND);
  582.         return (ERROR);
  583.         }
  584.    
  585.     /* Short critical section with message and timer processing. */
  586.  
  587.     semTake (ripLockSem, WAIT_FOREVER);    
  588.     pIfp->leakHook = NULL;
  589.     semGive (ripLockSem);
  590.  
  591.     return (OK);
  592.     }
  593. /******************************************************************************
  594. *
  595. * ripLeakHook - sample leak hook for RIP routes
  596. *
  597. * This routine prevents any routes from being added to the internal RIP
  598. * table or kernel routing table, and prints the information that was passed 
  599. * to it.
  600. *
  601. * RETURNS: OK
  602. *
  603. * NOMANUAL
  604. */
  605. STATUS ripLeakHook
  606.     (
  607.     long dest,
  608.     long gate,
  609.     long mask
  610.     )
  611.     {
  612.     printf ("Destination %lxtGateway %lxtMask %lxn", dest, gate, mask);
  613.     return (OK);
  614.     }
  615. /******************************************************************************
  616. *
  617. * ripSendHookAdd - add an update filter to a RIP interface
  618. *
  619. * This routine installs a hook routine to screen individual route entries
  620. * for inclusion in a periodic update. The routine is installed for the
  621. * registered interface given by <pIpAddr>. (Interfaces created or
  622. * changed after a RIP session has started may be installed/updated with 
  623. * the ripIfSearch() and ripIfReset() routines).
  624. *
  625. * The hook uses the following prototype:
  626. * cs
  627. *     BOOL ripSendHookRtn (struct rt_entry* pRt);
  628. * ce
  629. *
  630. * If the hook returns FALSE, the route is not included in the update.
  631. * Otherwise, it is included if it meets the other restrictions, such
  632. * as simple split horizon and border gateway filtering. The 
  633. * ripSendHookDelete() routine removes this additional filter from the
  634. * output processing.
  635. *
  636. * RETURNS: OK; or ERROR, if the interface could not be found.
  637. *
  638. * ERRNO:
  639. *  S_m2Lib_INVALID_PARAMETER
  640. *  S_m2Lib_ENTRY_NOT_FOUND
  641. */
  642. STATUS ripSendHookAdd
  643.     (
  644.     char* pIpAddr, /* IP address in dotted decimal notation */
  645.     BOOL (*ripSendHook) (struct rt_entry* pRt) /* Routine to use. */
  646.     )
  647.     {
  648.     struct interface* pIfp;
  649.     struct sockaddr_in address;
  650.     if (!ripInitFlag)
  651.         return (ERROR);
  652.     if (pIpAddr == NULL)
  653.         {
  654.         errnoSet (S_m2Lib_INVALID_PARAMETER);
  655.         return (ERROR);
  656.         }
  657.     address.sin_len = sizeof (address);
  658.     address.sin_addr.s_addr = inet_addr (pIpAddr);
  659.     address.sin_family = AF_INET;
  660.     
  661.     pIfp = ripIfLookup ((struct sockaddr *)&address);
  662.     if (pIfp == NULL)
  663.         {
  664.         errnoSet (S_m2Lib_ENTRY_NOT_FOUND);
  665.         return (ERROR);
  666.         }
  667.     /* Short critical section with output processing. */
  668.  
  669.     semTake (ripLockSem, WAIT_FOREVER);    
  670.     pIfp->sendHook = ripSendHook;
  671.     semGive (ripLockSem);
  672.  
  673.     return (OK);
  674.     }
  675. /******************************************************************************
  676. *
  677. * ripSendHookDelete - remove an update filter from a RIP interface
  678. *
  679. * This routine removes the hook routine that allowed additional screening
  680. * of route entries in periodic updates from the registered interface
  681. * indicated by <pIpAddr>. (Interfaces created or changed after a RIP 
  682. * session has started may be installed/updated with the ripIfSearch() 
  683. * and ripIfReset() routines). The RIP session will return to the default 
  684. * behavior and include any entries that meet the other restrictions (such 
  685. * as simple split horizon).
  686. *
  687. * RETURNS: OK; or ERROR, if the interface could not be found.
  688. *
  689. * ERRNO:
  690. *  S_m2Lib_INVALID_PARAMETER
  691. *  S_m2Lib_ENTRY_NOT_FOUND
  692. */
  693. STATUS ripSendHookDelete
  694.     (
  695.     char* pIpAddr /* IP address in dotted decimal notation */
  696.     )
  697.     {
  698.     struct interface* pIfp;
  699.     struct sockaddr_in address;
  700.     if (!ripInitFlag)
  701.         return (ERROR);
  702.     if (pIpAddr == NULL)
  703.         {
  704.         errnoSet (S_m2Lib_INVALID_PARAMETER);
  705.         return (ERROR);
  706.         }
  707.     address.sin_len = sizeof (address);
  708.     address.sin_addr.s_addr = inet_addr (pIpAddr);
  709.     address.sin_family = AF_INET;
  710.     
  711.     pIfp = ripIfLookup ((struct sockaddr *)&address);
  712.     if (pIfp == NULL)
  713.         {
  714.         errnoSet (S_m2Lib_ENTRY_NOT_FOUND);
  715.         return (ERROR);
  716.         }
  717.     /* Short critical section with output processing. */
  718.     semTake (ripLockSem, WAIT_FOREVER);
  719.     pIfp->sendHook = NULL;
  720.     semGive (ripLockSem);
  721.  
  722.     return (OK);
  723.     }
  724. /******************************************************************************
  725. *
  726. * ripSendHook - sample send hook for rip routes
  727. *
  728. * This routine displays all the routes that are being sent and returns OK
  729. * so that they are included in the update if all other criteria are met.
  730. *
  731. * RETURNS: OK
  732. *
  733. * NOMANUAL
  734. */
  735. BOOL ripSendHook
  736.     (
  737.     struct rt_entry* pRt
  738.     )
  739.     {
  740.     char address[32];
  741.     struct sockaddr_in* dSin;
  742.     struct sockaddr_in* gSin;
  743.     struct sockaddr_in* nSin;
  744.     ripRouteToAddrs (pRt, &dSin, &gSin, &nSin);
  745.     inet_ntoa_b (dSin->sin_addr, (char *)&address);
  746.     printf ("Route to %s ", address);
  747.     inet_ntoa_b (gSin->sin_addr, (char *)&address);
  748.     printf ("with gateway %s ", address);
  749.     inet_ntoa_b (nSin->sin_addr, (char *)&address);
  750.     printf ("and netmask %s being sent.n", address);
  751.     return (OK);
  752.     }
  753. /******************************************************************************
  754. *
  755. * ripRouteHookAdd - add a hook to install static and non-RIP routes into RIP
  756. *
  757. * This routine installs a hook routine that you can use to give RIP the 
  758. * ability to respond to route-add events generated by non-RIP agents. By   
  759. * design, RIP is not interested in the routes generated by non-RIP agents. 
  760. * If you do not install a route hook function, RIP continues this default 
  761. * behavior.  However, if you want RIP to add these non-RIP routes to its 
  762. * internal routing database and even propagate routes added by other 
  763. * agents, you must use ripRouteHookAdd() to register a function of the form:
  764. * ss
  765. * STATUS <Your>RipRouteHookRtn 
  766. *     ( 
  767. *     struct ROUTE_INFO * pRouteInfo, 
  768. *     int  protoId, 
  769. *     BOOL primaryRoute,
  770. *     int  flags 
  771. *     ) 
  772. * se
  773. * RIP invokes this function in response to the following events:
  774. *  '1.'  A non-RIP non-system route was added to the routing table. 
  775. *  '2.'  A route change message arrived. 
  776. *  '3.'  An ICMP redirect message arrived. 
  777. * The returned function value of the route hook routine tells rip 
  778. * how to respond to the event. In the first case, the returned 
  779. * function value tells RIP whether to add or ignore the new route. 
  780. * In the second case, the returned function tells RIP whether to 
  781. * delete the specified route or change its metric. In the third 
  782. * case, the event is of no direct importance for RIP, so RIP 
  783. * ignores the returned value of the route hook function. 
  784. * is
  785. * i <pRouteInfo>
  786. * This parameter passes in a pointer to a route information 
  787. * structure that stores the routing message. You should not 
  788. * access the contents of this structure directly. Instead, 
  789. * use ripAddrsXtract() to extract the following information: 
  790. *
  791. *  '-' destination address
  792. *  '-' netmask
  793. *  '-' gateway address
  794. *  '-' old gateway address (if available)
  795. * i <protoId> 
  796. * This parameter passes in the ID of the protocol that generated 
  797. * the event. Valid protocol IDs are defined in m2Lib.h as follows:
  798. *  'M2_ipRouteProto_other' (static routes) 
  799. *  'M2_ipRouteProto_local' 
  800. *  'M2_ipRouteProto_netmgmt'
  801. *  'M2_ipRouteProto_icmp'
  802. *  'M2_ipRouteProto_egp'
  803. *  'M2_ipRouteProto_ggp'
  804. *  'M2_ipRouteProto_hello'
  805. *  'M2_ipRouteProto_rip'
  806. *  'M2_ipRouteProto_is_is'
  807. *  'M2_ipRouteProto_es_is'
  808. *  'M2_ipRouteProto_ciscoIgrp'
  809. *  'M2_ipRouteProto_bbnSpfIgp'
  810. *  'M2_ipRouteProto_ospf'
  811. *  'M2_ipRouteProto_bgp'
  812. * i <primaryRoute> 
  813. * This parameter passes in a boolean value that indicates whether 
  814. * the route is a primary route. 'TRUE' indicates a primary route. 
  815. * 'FALSE' indicates a duplicate route. 
  816. * i <flags> 
  817. * This parameter passes in a value that indicates which event occurred: 
  818. *  '0' (zero)
  819. *  This indicates a route added to the routing table by a non-RIP agent. 
  820. *  'RIP_ROUTE_CHANGE_RECD' 
  821. *  This indicates a route change message. 
  822. *  'RIP_REDIRECT_RECD' 
  823. *  This indicates and ICMP redirect message. 
  824. * ie 
  825. * sh A New Non-RIP Non-System Route was Added to the Routing Table 
  826. * In response to this event, RIP needs to be told whether to ignore 
  827. * or add the route. RIP does this on the basis of the returned 
  828. * function value of the route hook routine. In the case of route-add 
  829. * event, RIP interprets the returned function value of the route hook 
  830. * routine as the metric for the route.
  831. *  
  832. * If the metric is HOPCNT_INFINITY, RIP ignores the route. If the 
  833. * metric is greater than zero but less than HOPCNT_INFINITY, RIP 
  834. * considers the route for inclusion. If the route is new to RIP, RIP 
  835. * adds the new route to its internal database, and then propagates 
  836. * the route in its subsequent update messages. If RIP already stores 
  837. * a route for that destination, RIP compares the metric of the new 
  838. * route and the stored route. If the new route has a better (lower) 
  839. * metric, RIP adds the new route. Otherwise, RIP ignores the new route. 
  840. * When generating its returned function value, your route hook 
  841. * routine can use the creator of the event (<protoID>) as a factor 
  842. * in the decision on whether to include the route. For example, 
  843. * if you wanted the route hook to tell RIP to ignore all non-RIP 
  844. * routes except static routes, your route hook would return 
  845. * HOPCNT_INFINITY if the <protoID> were anything other than 
  846. * 'M2_ipRouteProto_other'. Thus, your route hook routine is a 
  847. * vehicle through which you can implement a policy for including 
  848. * non-RIP routes in the RIP internal route data base. 
  849. * When designing your policy, you should keep in mind how RIP 
  850. * prioritizes these non-RIP routes and when it deletes these 
  851. * non-RIP routes. For example, non-RIP routes never time out. 
  852. * They remain in the RIP database until one of the following 
  853. * events occurs:
  854. *  '1.'  An agent deletes the route from the system routing table.
  855. *  '2.'  An agent deletes the interface through which the route passes. 
  856. *  '3.'  A route change message for the route arrives. 
  857. *  
  858. * Also, these non-RIP routes take precedence over RIP routes to 
  859. * the same destination. RIP ignores routes learned from RIP peers 
  860. * if a route to the same destination was recommended by the hook 
  861. * routine. This non-RIP route takes precedence over the RIP route 
  862. * without regard of the route metric. However, if the route hook 
  863. * routine adds multiple same-destination routes, the route with 
  864. * the lowest metric takes precedence. If the route hook route 
  865. * approves multiple same-metric same-destination routes, the 
  866. * most recently added route is installed.
  867. *  
  868. * sh A Route Change Notification Arrived
  869. *  
  870. * In response to this event, RIP needs to be told whether to 
  871. * delete the route or change its metric. If the hook returns a 
  872. * value greater than or equal to HOPCNT_INFINITY, RIP deletes 
  873. * the route from its internal routing data base. If the hook 
  874. * routine returns a valid metric (a value greater than zero 
  875. * but less than HOPCNT_INFINITY), RIP reassigns the routes 
  876. * metric to equal the returned value of the route hook routine. 
  877. * If the returned value of the route hook route is invalid 
  878. * (less than zero) RIP ignores the event. RIP also ignores 
  879. * the event if the route specified in <pRouteInfo> is not one 
  880. * stored in its internal data base. 
  881. * sh An ICMP Redirect Message Arrived 
  882. * In response to this event, RIP never needs to make any changes 
  883. * to its internal routing database. Thus, RIP ignores the returned 
  884. * function value of the route hook routine called in response 
  885. * to an ICMP redirect message. However, if the event is of 
  886. * interest to your particular environment, and it makes sense 
  887. * to catch the event in the context of the RIP task, you can 
  888. * use the route hook routine to do so. 
  889. * Within your route hook routine, your can recognize an ICMP 
  890. * event by checking whether the flags parameter value sets 
  891. * the RIP_REDIRECT_RECD bit. The <primaryRoute> parameter passes 
  892. * in a boolean value that indicates whether the route is 
  893. * primary route. If the <primaryRoute> passes in 'FALSE', the 
  894. * route hook routine need will most likely need to do nothing 
  895. * more. If this parameter passes in 'TRUE', take whatever action 
  896. * (if any) that you know to be appropriate to your particular 
  897. * environment. 
  898. * RETURNS: OK; or ERROR, if RIP is not initialized.
  899. */
  900. STATUS ripRouteHookAdd
  901.     (
  902.     FUNCPTR  pRouteHook /* function pointer to hook */
  903.     )
  904.     {
  905.     if (!ripInitFlag)
  906.         return (ERROR);
  907.     /* Short critical section with message and timer processing. */
  908.  
  909.     semTake (ripLockSem, WAIT_FOREVER);    
  910.     ripState.pRouteHook = pRouteHook;
  911.     semGive (ripLockSem);
  912.     return (OK);
  913.     }
  914. /****************************************************************************
  915. *
  916. * ripRouteHookDelete - remove the route hook
  917. *
  918. * This routine removes the route hook installed earlier by the 
  919. * ripRouteHookAdd() routine. This will cause RIP to ignore any routes
  920. * added to the system Routing database.
  921. *
  922. * RETURNS: OK; or ERROR, if RIP is not initialized.
  923. *
  924. */
  925. STATUS ripRouteHookDelete (void)
  926.     {
  927.     if (!ripInitFlag)
  928.         return (ERROR);
  929.    
  930.     /* Short critical section with message and timer processing. */
  931.  
  932.     semTake (ripLockSem, WAIT_FOREVER);    
  933.     ripState.pRouteHook = NULL;
  934.     semGive (ripLockSem);
  935.  
  936.     return (OK);
  937.     }
  938. /****************************************************************************
  939. *
  940. * ripRouteHook - sample route hook for non-RIP and redirected routes
  941. *
  942. * This routine allows RIP to include static (and other protocol) routes in
  943. * its database and propagate them to its peers. 
  944. * <pRouteInfo> points to a routing socket message structure that describes
  945. * the route details.
  946. * <protoId> identifies that routing protocol that is installing this route.
  947. * <primaryRoute> indicate if this is the route that will be used by the
  948. * IP forwarding process.
  949. * <flags> denote if this is a ICMP redirected route or a changed route or
  950. * a new route.
  951. *   flags == 0      New route (non-RIP)
  952. *   flags == RIP_REDIRECT_RECD ICMP redirected route
  953. *   flags == RIP_ROUTE_CHANGE_RECD Changed route
  954. * This routine first extracts pointers to the route destination, netmask and
  955. * gateway from the <pRouteInfo> parameter. In the case of redirects, the
  956. * old gateway address is also extracted and then a log message is printed
  957. * if configured to do so and then this routine exits.
  958. *
  959. * If it is a new route, this routine asks RIP to reject all routes except the
  960. * primary routes. For static routes, it assigns a metric that is the same 
  961. * as the interface index + the interface metric + protocol ID.
  962. *
  963. * RETURNS: A metric value (less than HOPCNT_INFINITY), if the route is to
  964. * be accepted; or HOPCNT_INFINITY, if the route is to be ignored.
  965. *
  966. * NOMANUAL
  967. */
  968. STATUS ripRouteHook
  969.     (
  970.     ROUTE_INFO * pRouteInfo, /* Route information */
  971.     int protoId, /* Routing protocol ID */
  972.     BOOL primaryRoute, /* Primary route ? */
  973.     int flags /* Whether redirect */
  974.     )
  975.     {
  976.     int  ifIndex;
  977.     int metric;
  978.     struct sockaddr * pDstAddr, * pNetmask, * pGateway, * pOldGateway;
  979.     /* Extract the address pointers from the route info structure */
  980.     ripAddrsXtract (pRouteInfo, &pDstAddr, &pNetmask, &pGateway, &pOldGateway);
  981.     /* Get the interface index */
  982.     ifIndex = pRouteInfo->rtm.rtm_index;
  983.     if (routedDebug)
  984.         {
  985.         logMsg ("nripRouteHook: called for proto: %d, ifIndex=%d, Redirect = %s,"
  986.                 " Initial metric = %d Primary route=%sn", protoId, ifIndex, 
  987.                 (int)((flags & RIP_REDIRECT_RECD) ? "Yes" : "No"),
  988.                 pRouteInfo->rtm.rtm_rmx.rmx_hopcount, 
  989.                 (int)(primaryRoute ? "TRUE" : "FALSE"), 0);
  990.         ripSockaddrPrint (pDstAddr);
  991.         ripSockaddrPrint (pNetmask);
  992.         ripSockaddrPrint (pGateway);
  993.         }
  994.     /* If it is a redirect message, print the old gateway and exit */
  995.     if (flags & RIP_REDIRECT_RECD)
  996.         {
  997.         if (routedDebug)
  998.             {
  999.             logMsg ("ripRouteHook: Redirect received fromn", 0, 0, 0, 0, 0, 0);
  1000.             ripSockaddrPrint (pOldGateway);
  1001.             }
  1002.         return (HOPCNT_INFINITY);
  1003.         }
  1004.     /* If it is a route change message, print the old gateway address */
  1005.     if (flags & RIP_ROUTE_CHANGE_RECD)
  1006.         {
  1007.         if (routedDebug)
  1008.             {
  1009.             logMsg ("ripRouteHook: route change: Old gateway:n", 0, 0, 0, 0, 0, 0);
  1010.             ripSockaddrPrint (pOldGateway);
  1011.             }
  1012.         }
  1013.     /* 
  1014.      * If it is not a primary route return ERROR to let RIP ignore this
  1015.      * route
  1016.      */
  1017.     if (! primaryRoute)
  1018.         return (HOPCNT_INFINITY);
  1019.     /* 
  1020.      * Calculate metric. We give preference to static routes over other routes
  1021.      * This is an arbitrary metric that is the sum of protocol ID,
  1022.      * interface index and the initial route metric. Since the static route
  1023.      * has the lowest protocol ID it gets the lowest metric.
  1024.      */
  1025.     metric = protoId + ifIndex + pRouteInfo->rtm.rtm_rmx.rmx_hopcount;
  1026.     if (metric >= (HOPCNT_INFINITY - 1))
  1027.         metric = HOPCNT_INFINITY - 2;
  1028.     if (routedDebug) 
  1029.         logMsg ("ripRouteHook: returning metric %dn", metric, 0, 0, 0, 0, 0);
  1030.     return (metric);
  1031.     }
  1032. /****************************************************************************
  1033. *
  1034. * ripIfSearch - add new interfaces to the internal list
  1035. *
  1036. * By default, a RIP session will not recognize any interfaces initialized
  1037. * after it has started. This routine schedules a search for additional
  1038. * interfaces that will occur during the next update of the internal routing
  1039. * table. Once completed, the session will accept and send RIP messages over
  1040. * the new interfaces.
  1041. *
  1042. * RETURNS: N/A
  1043. *
  1044. * ERRNO: N/A
  1045. *
  1046. * INTERNAL
  1047. * This routine just sets the flag tested by the watchdog timer handler
  1048. * to trigger a search. Mutual exclusion with that thread is not necessary
  1049. * in this case, since any change will correctly begin the search, which
  1050. * is not time sensitive. However, the actual search routine must lock out 
  1051. * all other processing.
  1052. */
  1053. void ripIfSearch (void)
  1054.     {
  1055.     if (!ripInitFlag)
  1056.         return;
  1057.     ripState.lookforinterfaces = TRUE;
  1058.     }
  1059. /******************************************************************************
  1060. *
  1061. * ripIfReset - alter the RIP configuration after an interface changes
  1062. *
  1063. * This routine updates the interface list and routing tables to reflect
  1064. * address and/or netmask changes for the device indicated by <pIfName>. 
  1065. * To accommodate possible changes in the network number, all routes using 
  1066. * the named interface are removed from the routing tables, but will be
  1067. * added in the next route update if appropriate. None of the removed
  1068. * routes are poisoned, so it may take some time for the routing tables of
  1069. * all the RIP participants to stabilize if the network number has changed.
  1070. * This routine replaces the existing interface structure with a new one.
  1071. * Thus, any interface specific MIB2 changes that were made to the interface
  1072. * being reset will be lost
  1073. *
  1074. * RETURNS: OK, or ERROR if named interface not found or not added to list.
  1075. *
  1076. * ERRNO: N/A
  1077. *
  1078. * INTERNAL
  1079. * This routine uses the mutex semaphore to block all other RIP processing
  1080. * until the data structures are in a stable state. The internal RIP routing
  1081. * table and the kernel routing table will be updated after it returns. If
  1082. * the network number did not change, all the removed routes received from
  1083. * other RIP sessions are still valid and will be added by the next update.
  1084. */
  1085. STATUS ripIfReset 
  1086.     (
  1087.     char *  pIfName  /* name of changed interface */
  1088.     )
  1089.     {
  1090.     long  ifIndex;
  1091.     int  slen; 
  1092.     int  tlen;
  1093.     BOOL found = FALSE;
  1094.     struct interface * pIf;  /* Target interface entry, if found. */
  1095.     struct interface * pPrevIf;/* Previous interface entry. */
  1096.     struct interface * pNextIf;/* Next interface entry. */
  1097.     STATUS result = OK;
  1098.     if (!ripInitFlag)
  1099.         return (ERROR);
  1100.     if (pIfName == NULL)
  1101.         return (ERROR);
  1102.     slen = strlen (pIfName);
  1103.     if (slen == 0)
  1104.         return (ERROR);
  1105.     /* Get the index of the Interface */
  1106.     ifIndex = ifNameToIfIndex (pIfName);
  1107.     if (ifIndex == 0)
  1108.         {
  1109.         /* 
  1110.          * Well, this means that the interface is gone. We just
  1111.          * remove its entries in our table
  1112.          */
  1113.         }
  1114.     /* 
  1115.      * Block access to all processing while updating the interface 
  1116.      * list and routing tables. 
  1117.      */
  1118.     semTake (ripLockSem, WAIT_FOREVER);
  1119.     pPrevIf = ripIfNet; 
  1120.     for (pIf = ripIfNet; pIf; pIf = pNextIf)
  1121.         {
  1122.         /* 
  1123.          * Save the next interface value now as we might delete the
  1124.          * interface below.
  1125.          */
  1126.         pNextIf = pIf->int_next;
  1127.         /* 
  1128.          * Ignore names of different lengths to prevent a false match 
  1129.          * between overlapping unit numbers such as "ln1" and "ln10".
  1130.          */
  1131.         tlen = strlen (pIf->int_name);
  1132.         if (tlen != slen)
  1133.             {
  1134.             pPrevIf = pIf;
  1135.             continue;
  1136.             }
  1137.         if (strcmp (pIfName, pIf->int_name) == 0)
  1138.             {
  1139.             found = TRUE;
  1140.             /*
  1141.              * Mark the interface down so that ifRouteAdd() will not
  1142.              * select this interface
  1143.              */
  1144.             pIf->int_flags &=  ~IFF_UP;
  1145.             /* 
  1146.              * Now delete all routes passing through this interface.
  1147.              * including the locally generated entries for accessing the
  1148.              * directly connected network
  1149.              */
  1150.             ripRoutesDelete (pIf, TRUE);
  1151.             /* Now delete the interface itself */
  1152.             ripInterfaceIntDelete (pIf, pPrevIf);
  1153.             }
  1154.         else 
  1155.             pPrevIf = pIf;
  1156.         }
  1157.     /* If interface was not found, return error */
  1158.     if (!found)
  1159.         {
  1160.         semGive (ripLockSem);
  1161.         return (ERROR);
  1162.         }
  1163.     /* 
  1164.      * Add the new entry from kernel's list. If ifIndex == 0, that means
  1165.      * the interface has been deleted. Don't bother calling routedIfInit
  1166.      * if that's the case.
  1167.      */
  1168.     if (ifIndex != 0) 
  1169.         result = routedIfInit (FALSE, ifIndex); 
  1170.     semGive (ripLockSem);
  1171.     return (result);
  1172.     }
  1173. /******************************************************************************
  1174. * ripFilterEnable - activate strict border gateway filtering
  1175. *
  1176. * This routine configures an active RIP session to enforce the restrictions 
  1177. * necessary for RIP-1 and RIP-2 routers to operate correctly in the same 
  1178. * network as described in section 3.2 of RFC 1058 and section 3.3 of RFC 1723. 
  1179. * When enabled, routes to portions of a logical network (including host 
  1180. * routes) will be limited to routers within that network. Updates sent 
  1181. * outside that network will only include a single entry representing the 
  1182. * entire network. That entry will subsume all subnets and host-specific
  1183. * routes. If supernets are used, the entry will advertise the largest
  1184. * class-based portion of the supernet reachable through the connected
  1185. * interface.
  1186. *
  1187. * RETURNS: N/A
  1188. *
  1189. * ERRNO: N/A
  1190. *
  1191. * INTERNAL
  1192. * This routine allows the supply() routine in ./rip/output.c to call
  1193. * the family-specific sendroute routine that selects the RTS_INTERNAL 
  1194. * route entries for transmission outside of a network. The current
  1195. * implementation for AF_INET routes is the inet_sendroute routine in
  1196. * the ./rip/inet.c file.
  1197. */
  1198. void ripFilterEnable (void)
  1199.     {
  1200.     if (!ripInitFlag)
  1201.         return;
  1202.     /* Wait for current processing to complete before changing behavior. */
  1203.     semTake (ripLockSem, WAIT_FOREVER);
  1204.     ripFilterFlag = TRUE;
  1205.     semGive (ripLockSem);
  1206.     return;
  1207.     }
  1208. /******************************************************************************
  1209. *
  1210. * ripFilterDisable - prevent strict border gateway filtering
  1211. *
  1212. * This routine configures an active RIP session to ignore the restrictions 
  1213. * necessary for RIP-1 and RIP-2 routers to operate correctly in the same 
  1214. * network. All border gateway filtering is ignored and all routes to
  1215. * subnets, supernets, and specific hosts will be sent over any available 
  1216. * interface. This operation is only correct if no RIP-1 routers are present 
  1217. * anywhere on the network. Results are unpredictable if that condition is 
  1218. * not met, but high rates of packet loss and widespread routing failures are 
  1219. * likely.
  1220. *
  1221. * The border gateway filtering rules are in force by default.
  1222. *
  1223. * RETURNS: N/A
  1224. *
  1225. * ERRNO: N/A
  1226. *
  1227. * INTERNAL
  1228. * This routine prevents the supply() routine in ./rip/output.c from executing
  1229. * the family-specific sendroute routine that limits the propagation
  1230. * of internal network information. The current implementation for AF_INET 
  1231. * routes is the inet_sendroute routine in the ./rip/inet.c file.
  1232. */
  1233. void ripFilterDisable (void)
  1234.     {
  1235.     if (!ripInitFlag)
  1236.         return;
  1237.     semTake (ripLockSem, WAIT_FOREVER);
  1238.     ripFilterFlag = FALSE;
  1239.     semGive (ripLockSem);
  1240.     return;
  1241.     }
  1242. /******************************************************************************
  1243. *
  1244. * ripShutdown - terminate all RIP processing
  1245. *
  1246. * This routine "poisons" all routes in the current table by transmitting
  1247. * updates with an infinite metric for each entry over all available
  1248. * interfaces. It then halts all RIP processing and removes the associated
  1249. * tasks and data structures. When completed successfully, the RIP
  1250. * services are unavailable until restarted with the ripLibInit() routine.
  1251. *
  1252. * RETURNS: OK if shutdown completed, or ERROR otherwise.
  1253. *
  1254. * ERRNO: N/A
  1255. *
  1256. * INTERNAL
  1257. * The ripState global is not changed by this routine so that the system
  1258. * status can still be examined before restarting. That global is cleared
  1259. * by the initialization routine.
  1260. */
  1261. STATUS ripShutdown (void)
  1262.     {
  1263.     register struct rthash *rh;
  1264.     register struct interface *ifp, *pTemp;
  1265.     register struct rt_entry *rt;
  1266.     struct rthash *base = hosthash;
  1267.     int doinghost = 1;
  1268. #ifdef RIP_MD5
  1269.     RIP_AUTH_KEY * pAuth;
  1270. #endif /* RIP_MD5 */
  1271. #ifndef VIRTUAL_STACK
  1272.     IMPORT RIP ripState;
  1273. #endif
  1274.     if (!ripInitFlag)
  1275.         return (OK);
  1276.     /* 
  1277.      * Obtain the lock semaphore to synchronize the shutdown with the
  1278.      * timer and message processing threads.
  1279.      */
  1280.     semTake (ripLockSem, WAIT_FOREVER);
  1281.     /* 
  1282.      * Remove the watchdog timer and RIP tasks to prevent further updates
  1283.      * and eliminate the mutex semaphore. The timer task must be removed
  1284.      * first to prevent an invalid reference to the watchdog.
  1285.      */
  1286.     taskDelete (ripState.ripTimerTaskId);
  1287.     wdCancel (ripState.timerDog);
  1288.     wdDelete (ripState.timerDog);
  1289.     taskDelete (ripState.ripTaskId);
  1290.     semDelete (ripLockSem);
  1291.     /* Set the route hook to NULL */
  1292.     ripState.pRouteHook = NULL;
  1293.     /* 
  1294.      * Poison all known routes to signal neighboring RIP 
  1295.      * routers of pending exit.
  1296.      */
  1297.     if (ripState.supplier)
  1298.         {
  1299.         again:
  1300.         for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++)
  1301.             {
  1302.             rt = rh->rt_forw;
  1303.             for (; rt != (struct rt_entry *)rh; rt = rt->rt_forw)
  1304.                 rt->rt_metric = HOPCNT_INFINITY;
  1305.             }
  1306.         if (doinghost)
  1307.             {
  1308.             doinghost = 0;
  1309.             base = nethash;
  1310.             goto again;
  1311.             }
  1312.         toall (supply, 0, (struct interface *)NULL);
  1313. }
  1314.     /* Remove all entries from the kernel and RIP routing tables. */
  1315.     rtdeleteall ();
  1316.     /* Remove list of available interfaces. */
  1317.     ifp = ripIfNet;
  1318.     while (ifp != NULL)
  1319.         {
  1320.         pTemp = ifp;
  1321.         ifp = pTemp->int_next;
  1322. #ifdef RIP_MD5
  1323.         /* free the auth keys for this interface */
  1324.         pAuth = pTemp->pAuthKeys;
  1325.         while (pAuth != NULL)
  1326.             {
  1327.             pTemp->pAuthKeys = pAuth->pNext;
  1328.             free (pAuth);
  1329.             pAuth = pTemp->pAuthKeys;
  1330.             }
  1331. #endif /* RIP_MD5 */
  1332.         free (pTemp);
  1333.         }
  1334.     /* Free up the RIP interface exclusion list */
  1335.     lstFree (&ripIfExcludeList);
  1336.     /* Remove the remaining data structures and the input/output socket. */
  1337.     semDelete (ripState.timerSem);
  1338.     close (ripState.s); 
  1339.     close (ripState.routeSocket); 
  1340.     /* Set ripInitFlag to FALSE now that we have uninitialized RIP */
  1341.     ripInitFlag = FALSE;
  1342.     return (OK);
  1343.     }
  1344. /******************************************************************************
  1345. *
  1346. * ripDebugLevelSet - specify amount of debugging output
  1347. *
  1348. * This routine determines the amount of debugging information sent to
  1349. * standard output during the RIP session. Higher values of the <level>
  1350. * parameter result in increasingly verbose output. A <level> of zero
  1351. * restores the default behavior by disabling all debugging output.
  1352. *
  1353. * RETURNS: N/A
  1354. *
  1355. * ERRNO: N/A
  1356. */
  1357. void ripDebugLevelSet
  1358.     (
  1359.     int  level  /* verbosity level (0 - 3) */
  1360.     )
  1361.     {
  1362.     /* Disable debugging if a bogus value is given. */
  1363.     if (level < 0 || level > 3)
  1364.         level = 0;
  1365.     routedDebug = level;
  1366.     }
  1367. #ifdef RIP_MD5
  1368. /***************************************************************************
  1369. *
  1370. * ripAuthKeyShow - show current authentication configuration
  1371. *
  1372. * This routines shows the current configuration of the authentication keys
  1373. * for each interface.
  1374. *
  1375. * RETURNS: N/A
  1376. */
  1377. void ripAuthKeyShow
  1378.     (
  1379.     UINT showKey        /* if non-zero then key values are shown */
  1380.     )
  1381.     {
  1382.     register RIP_AUTH_KEY * pAuthKey;
  1383.     register struct interface *ifp;
  1384.     time_t t;
  1385.     semTake (ripLockSem, WAIT_FOREVER);
  1386.     printf ("n%-10s  %-9s %-10s  %-15s %-24sn", 
  1387.             "Interface", "KeyID", "Protocol", "Expires", "Key");
  1388.     printf ("----------------------------------------------------------------" 
  1389.             "----------n");
  1390.     t = time (NULL);
  1391.     for (ifp = ripIfNet; ifp; ifp = ifp->int_next)
  1392.         {
  1393.         for (pAuthKey = ifp->pAuthKeys; pAuthKey; pAuthKey = pAuthKey->pNext)
  1394.             {
  1395.             printf ("%-10s  ", ifp->int_name);
  1396.             printf ("%-9u ", pAuthKey->keyId);
  1397.             if (pAuthKey->authProto == RIP_AUTH_PROTO_MD5)
  1398.                 printf ("%-10s  ", "MD5");
  1399.             else if (pAuthKey->authProto == RIP_AUTH_PROTO_SHA1)
  1400.                 printf ("%-10s  ", "SHA-1");
  1401.             else
  1402.                 printf ("%-10s  ", "unknown");
  1403.             if (pAuthKey->timeEnd > t)
  1404.                 printf ("%-15lu ", (pAuthKey->timeEnd - t));
  1405.             else
  1406.                 printf ("%-15s ", "expired");
  1407.             if (showKey)
  1408.                 printf ("%-24sn", pAuthKey->pKey);
  1409.             else
  1410.                 printf ("<not shown>n");
  1411.             }
  1412.         }
  1413.     printf ("n");
  1414.     semGive (ripLockSem);
  1415.     }
  1416. /***************************************************************************
  1417. *
  1418. * ripAuthKeyAdd - add a new RIP authentication key
  1419. *
  1420. * This routine is used to add a new RIP authentication key for a specific
  1421. * interface.
  1422. *
  1423. * RETURNS: ERROR, if the interface does not exist, or the <keyId> already 
  1424. * exists, or if the protocol is not supported; OK, if key was entered.
  1425. */
  1426. STATUS ripAuthKeyAdd
  1427.     (
  1428.     char *      pInterfaceName, /* interface to add a key */
  1429.     UINT16      keyId,          /* the keyId for this new key */
  1430.     char *      pKey,           /* the secret key */
  1431.     UINT        keyLen,         /* length of the secret key */
  1432.     UINT        authProto,      /* auth protocol to use (1 = MD5) */
  1433.     ULONG       timeValid       /* number of seconds until key expires */
  1434.     )
  1435.     {
  1436.     register struct interface *ifp;
  1437.     register RIP_AUTH_KEY * pAuthKey;
  1438.     RIP_AUTH_KEY * pNewAuthKey;
  1439.     if (authProto != RIP_AUTH_PROTO_MD5) return ERROR;
  1440.     semTake (ripLockSem, WAIT_FOREVER);
  1441.     for (ifp = ripIfNet; ifp; ifp = ifp->int_next)
  1442.         {
  1443.         if (strcmp (pInterfaceName, ifp->int_name) == 0)
  1444.             {
  1445.             for (pAuthKey = ifp->pAuthKeys; pAuthKey;
  1446.                  pAuthKey = pAuthKey->pNext)
  1447.                 {
  1448.                 if (pAuthKey->keyId == keyId)
  1449.                     {
  1450.                     semGive (ripLockSem);
  1451.                     return ERROR;
  1452.                     }
  1453.                 }
  1454.             pNewAuthKey = malloc (sizeof (RIP_AUTH_KEY));
  1455.             if (pNewAuthKey == NULL)
  1456.                 {
  1457.                 semGive (ripLockSem);
  1458.                 return ERROR;
  1459.                 }
  1460.             memset (pNewAuthKey, 0, sizeof (RIP_AUTH_KEY));
  1461.             pNewAuthKey->keyId = keyId;
  1462.             pNewAuthKey->authProto = authProto;
  1463.             pNewAuthKey->timeStart = time (NULL);
  1464.             pNewAuthKey->timeEnd = (pNewAuthKey->timeStart + timeValid);
  1465.             memcpy (pNewAuthKey->pKey, pKey, keyLen);
  1466.             pNewAuthKey->ifp = ifp;
  1467.             pNewAuthKey->pNext = ifp->pAuthKeys;
  1468.             ifp->pAuthKeys = pNewAuthKey;
  1469.             semGive (ripLockSem);
  1470.             return OK;
  1471.             }
  1472.         }
  1473.     semGive (ripLockSem);
  1474.     return ERROR;
  1475.     }
  1476. /***************************************************************************
  1477. *
  1478. * ripAuthKeyDelete - delete an existing RIP authentication key
  1479. *
  1480. * This routine is used to delete a RIP authentication key for a specific
  1481. * interface.
  1482. *
  1483. * RETURNS: ERROR, if the interface does not exist, or the <keyId> does not 
  1484. * exist; OK, if key was deleted.
  1485. */
  1486. STATUS ripAuthKeyDelete
  1487.     (
  1488.     char *      pInterfaceName, /* interface to delete a key from */
  1489.     UINT16      keyId           /* the keyId of the key to delete */
  1490.     )
  1491.     {
  1492.     register struct interface *ifp;
  1493.     register RIP_AUTH_KEY * pPrevAuthKey;
  1494.     register RIP_AUTH_KEY * pAuthKey;
  1495.     semTake (ripLockSem, WAIT_FOREVER);
  1496.     for (ifp = ripIfNet; ifp; ifp = ifp->int_next)
  1497.         {
  1498.         if (strcmp (pInterfaceName, ifp->int_name) == 0)
  1499.             {
  1500.             if (ifp->pAuthKeys == NULL)
  1501.                 {
  1502.                 semGive (ripLockSem);
  1503.                 return ERROR;
  1504.                 }
  1505.             pPrevAuthKey = ifp->pAuthKeys;
  1506.             pAuthKey = pPrevAuthKey->pNext;
  1507.             if (pPrevAuthKey->keyId == keyId)
  1508.                 {
  1509.                 ifp->pAuthKeys = pAuthKey;
  1510.                 free (pPrevAuthKey);
  1511.                 semGive (ripLockSem);
  1512.                 return OK;
  1513.                 }
  1514.             while (pAuthKey)
  1515.                 {
  1516.                 if (pAuthKey->keyId == keyId)
  1517.                     {
  1518.                     pPrevAuthKey->pNext = pAuthKey->pNext;
  1519.                     free (pAuthKey);
  1520.                     semGive (ripLockSem);
  1521.                     return OK;
  1522.                     }
  1523.                 pPrevAuthKey = pAuthKey;
  1524.                 pAuthKey = pAuthKey->pNext;
  1525.                 }
  1526.             semGive (ripLockSem);
  1527.             return ERROR;
  1528.             }
  1529.         }
  1530.     semGive (ripLockSem);
  1531.     return ERROR;
  1532.     }
  1533. /***************************************************************************
  1534. *
  1535. * ripAuthKeyFind - find a RIP authentication key
  1536. *
  1537. * This routine is used to find a RIP authentication key based on a specified
  1538. * interface and keyId.  When a key is found, a pointer to the RIP_AUTH_KEY
  1539. * struct for the key is stored in pKey.
  1540. *
  1541. * RETURNS: ERROR, if the key is not found; OK if the key was found.
  1542. */
  1543. STATUS ripAuthKeyFind
  1544.     (
  1545.     struct interface *  ifp,   /* interface to search for key */
  1546.     UINT16              keyId, /* the keyId of the key to search for */
  1547.     RIP_AUTH_KEY **     pKey   /* storage for the key data */
  1548.     )
  1549.     {
  1550.     register RIP_AUTH_KEY * pAuthKey;
  1551.     for (pAuthKey = ifp->pAuthKeys; pAuthKey; pAuthKey = pAuthKey->pNext)
  1552.         {
  1553.         if (pAuthKey->keyId == keyId)
  1554.             {
  1555.             *pKey = pAuthKey;
  1556.             return OK;
  1557.             }
  1558.         }
  1559.     return ERROR;
  1560.     }
  1561. /***************************************************************************
  1562. *
  1563. * ripAuthKeyFindFirst - find a RIP authentication key
  1564. *
  1565. * This routine is used to find a RIP authentication key based on a specified
  1566. * interface.  Because a <keyId> is not specified, this routine returns the 
  1567. * first non-expired key found for the interface.  When a key is found, a 
  1568. * pointer to the RIP_AUTH_KEY structure for the key is returned in <pKey>.
  1569. *
  1570. * RETURNS: ERROR, if a key is not found; OK, if a key was found.
  1571. */
  1572. STATUS ripAuthKeyFindFirst
  1573.     (
  1574.     struct interface *  ifp,   /* interface to search for key */
  1575.     RIP_AUTH_KEY **     pKey   /* storage for the key data */
  1576.     )
  1577.     {
  1578.     register RIP_AUTH_KEY * pAuthKey;
  1579.     RIP_AUTH_KEY * pBackup;
  1580.     time_t t;
  1581.     /*
  1582.      * Save an available key for possible use if no valid entries exist,
  1583.      * regardless of the expiration time (RFC 2082, section 4.3).
  1584.      */
  1585.     pBackup = ifp->pAuthKeys;
  1586.     if (pBackup == NULL)
  1587.         {
  1588.         logMsg ("RIP: Error! No MD5 keys available!", 0, 0, 0, 0, 0, 0);
  1589.         return (ERROR);
  1590.         }
  1591.     /* check that the key has not yet expired */
  1592.     t = time (NULL);
  1593.     for (pAuthKey = ifp->pAuthKeys; pAuthKey; pAuthKey = pAuthKey->pNext)
  1594.         {
  1595.         if (pAuthKey->timeEnd > t)
  1596.             {
  1597.             *pKey = pAuthKey;
  1598.             return OK;
  1599.             }
  1600.         }
  1601.     /*
  1602.      * All keys expired! Send notification to network manager and treat
  1603.      * available key as having an infinite lifetime (RFC 2082, section 4.3).
  1604.      */
  1605.     logMsg ("RIP: Warning! Last authentication key expired. Using key ID %x.n",
  1606.             pBackup->keyId, 0, 0, 0, 0, 0);
  1607.     *pKey = pBackup;
  1608.     return ERROR;
  1609.     }
  1610. /***************************************************************************
  1611. *
  1612. * ripAuthKeyInMD5 - authenticate an incoming RIP-2 message using MD5
  1613. *
  1614. * This routine is used to authenticate an incoming RIP-2 message using
  1615. * the MD5 digest protocol.  This authentication scheme is described in
  1616. * RFC 2082.
  1617. *
  1618. * RETURNS: ERROR, if could not authenticate; OK, if authenticated.
  1619. */
  1620. STATUS ripAuthKeyInMD5
  1621.     (
  1622.     struct interface *  ifp,    /* interface message received on */
  1623.     RIP_PKT *          pRip, /* received RIP message */
  1624.     UINT                size    /* length of the RIP message */
  1625.     )
  1626.     {
  1627.     RIP2_AUTH_PKT_HDR * pAuthHdr;
  1628.     RIP2_AUTH_PKT_TRL * pAuthTrl;
  1629.     RIP_AUTH_KEY * pAuthKey;
  1630.     UCHAR savedDigest [MD5_DIGEST_LEN];
  1631.     UCHAR newDigest [MD5_DIGEST_LEN];
  1632.     UINT numRipEntries;
  1633.     MD5_CTX_T context;
  1634.     time_t t;
  1635.     /* must be a RIP version 2 packet */
  1636.     if (pRip->rip_vers == 1)
  1637.         return ERROR;
  1638.     pAuthHdr = (RIP2_AUTH_PKT_HDR *)pRip->rip_nets;
  1639.     /* check basic auth header fields */
  1640.     if ((pAuthHdr->authIdent != RIP2_AUTH) ||
  1641.         (ntohs (pAuthHdr->authType) != M2_rip2IfConfAuthType_md5) ||
  1642.         (pAuthHdr->zero1 != 0) || (pAuthHdr->zero2 != 0))
  1643.         return ERROR;
  1644.     /* get the secret key for the given keyid for this interface */
  1645.     if (ripAuthKeyFind (ifp, pAuthHdr->keyId, &pAuthKey) == ERROR)
  1646.         return ERROR;
  1647.     /* check that the key has not yet expired */
  1648.     t = time (NULL);
  1649.     if (pAuthKey->timeEnd <= t)
  1650.         return ERROR;
  1651.     /* check that MD5 is being used for this key and the authDataLen is 16 */
  1652.     if ((pAuthKey->authProto != RIP_AUTH_PROTO_MD5) ||
  1653.         (pAuthHdr->authDataLen != MD5_DIGEST_LEN))
  1654.         return ERROR;
  1655.     /* make sure the trailing digest is the correct length */
  1656.     if ((size - (ntohs (pAuthHdr->packetLen) + 4)) != MD5_DIGEST_LEN)
  1657.         return ERROR;
  1658.     /* make sure all RIP entries are 20 bytes long */
  1659.     if (((ntohs (pAuthHdr->packetLen) - 24) % 20) != 0)
  1660.         return ERROR;
  1661.     /* get the number of RIP entries including the auth header */
  1662.     numRipEntries = ((ntohs (pAuthHdr->packetLen) - 24) / 20);
  1663.     /* get the auth trailer that includes the message digest */
  1664.     pAuthTrl = (RIP2_AUTH_PKT_TRL *)(pAuthHdr + 1 + numRipEntries);
  1665.     /* check basic auth trailer fields */
  1666.     if ((pAuthTrl->authIdent != RIP2_AUTH) ||
  1667.         ((ntohs (pAuthTrl->authTag) != 0x01) &&
  1668.          (ntohs (pAuthTrl->authTag) != M2_rip2IfConfAuthType_md5)))
  1669.         return ERROR;
  1670.     /* save the old digest */
  1671.     memcpy (savedDigest, pAuthTrl->authDigest, MD5_DIGEST_LEN);
  1672.     /* write the secret key over the digest in the packet */
  1673.     memcpy (pAuthTrl->authDigest, pAuthKey->pKey, MD5_DIGEST_LEN);
  1674.     /* compute the MD5 authentication digest */
  1675.     memset (&context, 0, sizeof (MD5_CTX_T));
  1676.     MD5Init (&context);
  1677.     MD5Update (&context, (UCHAR *)pRip, size);
  1678.     MD5Final (newDigest, &context);
  1679.     /* check if the message is authentic by comparing the digests */
  1680.     if (memcmp (savedDigest, newDigest, MD5_DIGEST_LEN) != 0)
  1681.         return ERROR;
  1682.     /*
  1683.      * check that the sequence number is greater than the last received
  1684.      * make sure this check is done after the message is authenticated
  1685.      */
  1686.     if ((ntohl (pAuthHdr->sequence) != 0) &&
  1687.         (ntohl (pAuthHdr->sequence) <= pAuthKey->lastRcvSequence))
  1688.         return ERROR;
  1689.     /* save the new recieved sequence number */
  1690.     pAuthKey->lastRcvSequence = ntohl (pAuthHdr->sequence);
  1691.     return OK; /* Gee wiz... */
  1692.     }
  1693. /***************************************************************************
  1694. *
  1695. * ripAuthKeyOut1MD5 - start MD5 authentication of an outgoing RIP-2 message
  1696. *
  1697. * This routine is used to start the authentication of an outgoing RIP-2
  1698. * message by adding the authentication header used for MD5 authentication.
  1699. * This authentication scheme is described in RFC 2082.  This function
  1700. * returns a pointer the authentication header and a pointer to the looked up 
  1701. * authentication key.
  1702. *
  1703. * RETURNS: ERROR, if a key could not be found; OK, if the header was added.
  1704. */
  1705. STATUS ripAuthKeyOut1MD5
  1706.     (
  1707.     struct interface *   pIfp,      /* interface message being sent on */
  1708.     struct netinfo *     pNetinfo,  /* pointer to next RIP entry to fill in */
  1709.     RIP2_AUTH_PKT_HDR ** ppAuthHdr, /* stores the authentication header */
  1710.     RIP_AUTH_KEY **      ppAuthKey  /* stores the authentication key to use */
  1711.     )
  1712.     {
  1713.     /* get the first RIP entry for storing auth data */
  1714.     *ppAuthHdr = (RIP2_AUTH_PKT_HDR *)pNetinfo;
  1715.     memset (*ppAuthHdr, 0, sizeof (RIP2_AUTH_PKT_HDR));
  1716.     /* fill in the auth tag and type */
  1717.     (*ppAuthHdr)->authIdent = RIP2_AUTH;
  1718.     (*ppAuthHdr)->authType = htons (M2_rip2IfConfAuthType_md5);
  1719.     /* the packet len will be filled in later (in ripAuthKeyOut2MD5) */
  1720.     /* get a secret key for this interface */
  1721.     if (ripAuthKeyFindFirst (pIfp, ppAuthKey) == ERROR)
  1722.         return ERROR;
  1723.     /* fill in the keyId and authDataLen */
  1724.     (*ppAuthHdr)->keyId = (*ppAuthKey)->keyId;
  1725.     if ((*ppAuthKey)->authProto != RIP_AUTH_PROTO_MD5)
  1726.         return ERROR;
  1727.     (*ppAuthHdr)->authDataLen = MD5_DIGEST_LEN;
  1728.     /*
  1729.      * Fill in the sequence number.  If the last sent is 0 then
  1730.      * no RIP message has been sent out this interface.  So 0 must
  1731.      * be sent as the sequence number.
  1732.      */
  1733.     if ((*ppAuthKey)->lastSntSequence == 0)
  1734.         (*ppAuthHdr)->sequence = 0;
  1735.     else
  1736.         (*ppAuthHdr)->sequence = htonl ((*ppAuthKey)->lastSntSequence + 1);
  1737.     (*ppAuthKey)->lastSntSequence++;
  1738.     return OK;
  1739.     }
  1740. /***************************************************************************
  1741. *
  1742. * ripAuthKeyOut2MD5 - authenticate an outgoing RIP-2 message using MD5
  1743. *
  1744. * This routine is used to authenticate an outgoing RIP-2 message using
  1745. * the MD5 digest protocol.  This authentication scheme is described in
  1746. * RFC 2082.  This function modifies the size given in pSize to account
  1747. * for the extra auth trailer data.  The auth trailer is appended to the
  1748. * given RIP_PKT and the authentication digest is filled in.
  1749. *
  1750. * RETURNS: N/A
  1751. */
  1752. void ripAuthKeyOut2MD5
  1753.     (
  1754.     RIP_PKT *          pRip,   /* RIP message to authenticate */
  1755.     UINT *              pSize,    /* length of the RIP message */
  1756.     struct netinfo *    pNetinfo, /* pointer to next RIP entry to fill in */
  1757.     RIP2_AUTH_PKT_HDR * pAuthHdr, /* pointer to auth header in the message */
  1758.     RIP_AUTH_KEY *      pAuthKey  /* the auth key data to use */
  1759.     )
  1760.     {
  1761.     RIP2_AUTH_PKT_TRL * pAuthTrl;
  1762.     MD5_CTX_T context;
  1763.     UCHAR newDigest [MD5_DIGEST_LEN];
  1764.     /* get the last RIP entry for storing the auth digest */
  1765.     pAuthTrl = (RIP2_AUTH_PKT_TRL *)pNetinfo;
  1766.     memset (pAuthTrl, 0, sizeof (RIP2_AUTH_PKT_TRL));
  1767.     /* fill in the packet len located in the auth header */
  1768.     pAuthHdr->packetLen = htons ((UINT16)*pSize);
  1769.     /* increment the size to show the auth trailer */
  1770.     *pSize += sizeof (struct netinfo);
  1771.     /* fill in the auth tag and type */
  1772.     pAuthTrl->authIdent = RIP2_AUTH;
  1773.     pAuthTrl->authTag = htons (0x01);
  1774.     /* copy in the secret key into the auth trailer */
  1775.     memcpy (pAuthTrl->authDigest, pAuthKey->pKey, MD5_DIGEST_LEN);
  1776.     /* compute the digest and store it in the auth trailer */
  1777.     memset (&context, 0, sizeof (MD5_CTX_T));
  1778.     MD5Init (&context);
  1779.     MD5Update (&context, (UCHAR *)pRip, *pSize);
  1780.     MD5Final (newDigest, &context);
  1781.     memcpy (pAuthTrl->authDigest, newDigest, MD5_DIGEST_LEN);
  1782.     }
  1783. #endif /* RIP_MD5 */
  1784. #ifdef ROUTER_STACK
  1785. LOCAL BOOL ripRouteSame 
  1786.     (
  1787.     struct rt_entry * pRtEntry, /* RIP Route entry to compare */
  1788.     struct sockaddr * pDstAddr, /* Destination addr to compare with */
  1789.     struct sockaddr * pNetmask, /* Netmask to compare with */
  1790.     struct sockaddr * pGateway /* Gateway to compare with */
  1791.     )
  1792.     {
  1793.     struct sockaddr netmask;
  1794.     struct sockaddr_in * pNsin;
  1795.     if (routedDebug)
  1796.         {
  1797.         logMsg ("nnripRouteSame: route entry:n", 0, 0, 0, 0, 0, 0);
  1798.         ripSockaddrPrint (&pRtEntry->rt_dst);
  1799.         ripSockaddrPrint (&pRtEntry->rt_netmask);
  1800.         ripSockaddrPrint (&pRtEntry->rt_router);
  1801.         logMsg ("ripRouteSame: to be compared entry:n", 0, 0, 0, 0, 0, 0);
  1802.         ripSockaddrPrint (pDstAddr);
  1803.         ripSockaddrPrint (pNetmask);
  1804.         ripSockaddrPrint (pGateway);
  1805.         logMsg ("nn", 0, 0, 0, 0, 0, 0);
  1806.         }
  1807.     /* If destination values differ, return FALSE */
  1808.     if (!equal (pDstAddr, &pRtEntry->rt_dst))
  1809.         return (FALSE);
  1810.     /* 
  1811.      * If the gateway value is specified, then 
  1812.      * compare the gateway value we have in the route entry.
  1813.      * If the gateway value is not specified, then this is a primary route
  1814.      * that is being changed. Check that the route entry we have is also for
  1815.      * the primary route. If not, the routes don't match.
  1816.      */
  1817.     if (pGateway)
  1818.         {
  1819.         if (!equal (pGateway, &pRtEntry->rt_router))
  1820.             return (FALSE);
  1821.         }
  1822.     else
  1823.         {
  1824.         if (! (pRtEntry->rt_state & RTS_PRIMARY))
  1825.             return (FALSE);
  1826.         }
  1827.     /* 
  1828.      * We always store the netmask of a default route as all zeros.
  1829.      * So if it is a default route, we need only compare the destination
  1830.      * and gateway address fields
  1831.      */
  1832.     if (((struct sockaddr_in *)&(pRtEntry->rt_dst))->sin_addr.s_addr == 0)
  1833.         return (TRUE);
  1834.     /* 
  1835.      * If netmask is specified, check that they match. We
  1836.      * check only the address part as thge prefix part sometimes
  1837.      * differs
  1838.      */
  1839.     if (pNetmask)
  1840.         return (SOCKADDR_IN (pNetmask) == SOCKADDR_IN (&pRtEntry->rt_netmask));
  1841.     /* 
  1842.      * If no netmask was specified, we calculated the netmask to be that
  1843.      * of the interface. Check for that case
  1844.      */
  1845.     bzero ((char *)&netmask, sizeof (netmask));
  1846.     netmask.sa_family = AF_INET;
  1847.     netmask.sa_len = 16;
  1848.     pNsin = (struct sockaddr_in *)&netmask;
  1849.     pNsin->sin_addr.s_addr = htonl (pRtEntry->rt_ifp->int_subnetmask);
  1850.     return (equal (&netmask, &pRtEntry->rt_netmask));
  1851.     }
  1852. /***************************************************************************
  1853. *
  1854. * ripInterfaceUpFlagSet - set or reset the interface UP flag
  1855. *
  1856. * This function sets or resets the IFF_UP flag of the interface specified
  1857. * by <pIfName> according to the status described by <up>. If the interface
  1858. * is being set up, it also adds the interface routes the interface,
  1859. * else if the interface is being brought down, it deletes all routes 
  1860. * passing through the interface except the routes learned through the
  1861. * Routing system callback.
  1862. *
  1863. * RETURNS: OK or ERROR.
  1864. *
  1865. * NOMANUAL
  1866. *
  1867. * INTERNAL
  1868. * This routine loops through the entire interface table looking for
  1869. * interfaces with the specified name. A single IP interface with aliases
  1870. * is stored by RIP as multiple interface with the same name (but different
  1871. * addresses). Hence the looping is needed.
  1872. */
  1873. LOCAL STATUS ripInterfaceUpFlagSet
  1874.     (
  1875.     u_short  ifIndex,
  1876.     BOOL  up
  1877.     )
  1878.     {
  1879.     int  error = ERROR;
  1880.     struct interface *  pIf;  /* Target interface entry, if found. */
  1881.     if (ifIndex == 0) 
  1882.         return (ERROR);
  1883.     if (routedDebug) 
  1884.         logMsg ("ripInterfaceUpFlagSet: Setting %d %sn", 
  1885.                 ifIndex, (int)(up ? "UP" : "DOWN"), 0, 0, 0, 0);
  1886.     /* 
  1887.      * Now loop through our interface list and set the flag of all matching
  1888.      * interfaces. We might have more than one interface match a given
  1889.      * index if the interface is aliased. We treat each alias as a separate
  1890.      * interface.
  1891.      */
  1892.     for (pIf = ripIfNet; pIf; pIf = pIf->int_next)
  1893.         {
  1894.         if (ifIndex == pIf->int_index)
  1895.             {
  1896.             if (up && (pIf->int_flags & IFF_UP) == 0) 
  1897.                 {
  1898.                 pIf->int_flags |= IFF_UP;
  1899.                 /*
  1900.                  * Now add a route to the local network. This will delete
  1901.                  * any non-interface routes that we might have learned
  1902.                  * for the network while we were down
  1903.                  */
  1904.                 addrouteforif (pIf);
  1905.                 }
  1906.             else if (!up && (pIf->int_flags & IFF_UP) == IFF_UP) 
  1907.                 {
  1908.                 pIf->int_flags &= ~IFF_UP;
  1909.                 /* 
  1910.                  * Now delete all routes that pass through this interface.
  1911.                  * Don't delete the STATIC or non-RIP routes that we learned
  1912.                  * for this interface (through the Routing system callback
  1913.                  * as we will never ever re-learn them
  1914.                  */
  1915.                 ripRoutesDelete (pIf, FALSE);
  1916.                 }
  1917.             error = OK;
  1918.             }
  1919.         }
  1920.     return (error);
  1921.     }
  1922. #endif /* ROUTER_STACK */
  1923. /***************************************************************************
  1924. *
  1925. * ripRoutesDelete - delete routes passing through an interface
  1926. *
  1927. * This function deletes all routes passing though the interface specified
  1928. * by the <pIf> parameter. If the deleteAllRoutes parameter is set to FALSE,
  1929. * then only the routes that were added by us (the interface routes and routes
  1930. * learned from our peers) are deleted. The Static and other routing protocol
  1931. * routes  (like OSPF) learned through the routing syste, callback are not
  1932. * deleted.
  1933. *
  1934. * RETURNS: OK or ERROR
  1935. *
  1936. * NOMANUAL
  1937. */
  1938. LOCAL STATUS ripRoutesDelete
  1939.     (
  1940.     struct interface * pIf,
  1941.     BOOL deleteAllRoutes
  1942.     )
  1943.     {
  1944.     struct rt_entry * rt;
  1945.     struct sockaddr * dst;
  1946.     struct rthash *  pHashList;  /* Individual hash table entry. */
  1947.     struct rt_entry * pRt;  /* Individual route entry. */
  1948.     struct sockaddr_in  net;
  1949.     int  error = ERROR;
  1950.     if (!(pIf->int_flags & IFF_ROUTES_DELETED))
  1951.         {
  1952.         pIf->int_flags |= IFF_ROUTES_DELETED;
  1953.         /* 
  1954.          * If the interface is subnetted, then we must have added
  1955.          * (or incremented ref count on) the class based network route.
  1956.          * If we added the route, then that will be taken care of in
  1957.          * rt_delete(). If we just increased the refcnt, then we need to
  1958.          * decrease the refcnt
  1959.          */
  1960.         if (!(pIf->int_flags & IFF_POINTOPOINT) &&
  1961.             pIf->int_netmask != pIf->int_subnetmask)
  1962.             {
  1963.             /* look for route to logical network */
  1964.             memset(&net, 0, sizeof (net));
  1965.             net.sin_len = sizeof (net);
  1966.             net.sin_family = AF_INET;
  1967.             net.sin_addr.s_addr = htonl (pIf->int_net);
  1968.             dst = (struct sockaddr *)&net;
  1969.             rt = rtlookup(dst);
  1970.             if (rt && rt->rt_ifp != pIf)
  1971.                 {
  1972.                 /* 
  1973.                  * We didn't add the route, just incremented the ref count.
  1974.                  * Decrement the ref counts now
  1975.                  */
  1976.                 rt->rt_refcnt--;
  1977.                 rt->rt_subnets_cnt--;
  1978.                 }
  1979.             }
  1980.         /*
  1981.          * Now check if we added the network (remote, for PPP links)
  1982.          * route. If we did, then no need to do anything as rtdelete will
  1983.          * handle the route deletion. If we didn't add the route, then 
  1984.          * we must've increased the ref count. We need to decrement the ref
  1985.          * count now that we will not be referencing it any more.
  1986.          */
  1987.         if (pIf->int_flags & IFF_POINTOPOINT)
  1988.             dst = &pIf->int_dstaddr;
  1989.         else
  1990.             {
  1991.             memset(&net, 0, sizeof (net));
  1992.             net.sin_len = sizeof (net);
  1993.             net.sin_family = AF_INET;
  1994.             net.sin_addr.s_addr = htonl (pIf->int_subnet);
  1995.             dst = (struct sockaddr *)&net;
  1996.             }
  1997.         if ((rt = rtlookup(dst)) == NULL) 
  1998.             rt = rtfind(dst);
  1999.         if (rt && rt->rt_ifp != pIf)
  2000.             rt->rt_refcnt--;
  2001.         /*
  2002.          * For a point to point link, we either added a route for the
  2003.          * local end of the link, or incremented the reference count 
  2004.          * on an existing  route. If there are no other references to that 
  2005.          * route, delete it, else just decrement the reference count
  2006.          * NOTE: He we don't check for the interface, as the interface is
  2007.          * the same (loopback) for all instances of this route
  2008.          */
  2009.         if (pIf->int_flags & IFF_POINTOPOINT)
  2010.             {
  2011.             dst = &pIf->int_addr;
  2012.             if ((rt = rtlookup(dst)) == NULL) 
  2013.                 rt = rtfind(dst);
  2014.             if (rt)
  2015.                 {
  2016.                 if (rt->rt_refcnt == 0)
  2017.                     rtdelete (rt);
  2018.                 else 
  2019.                     rt->rt_refcnt--;
  2020.                 }
  2021.             }
  2022.         }
  2023.     /* 
  2024.      * Remove any routes associated with the changed interface from
  2025.      * both hash tables.
  2026.      */
  2027.     for (pHashList = hosthash; pHashList < &hosthash [ROUTEHASHSIZ]; 
  2028.          pHashList++)
  2029.         {
  2030.         pRt = pHashList->rt_forw;
  2031.         for (; pRt != (struct rt_entry *)pHashList; pRt = pRt->rt_forw)
  2032.              {
  2033.              if (pRt->rt_ifp != pIf)
  2034.                  continue;
  2035.              if (!deleteAllRoutes && ((pRt->rt_state & RTS_OTHER) != 0))
  2036.                  continue;
  2037.              pRt = pRt->rt_back;
  2038.              rtdelete (pRt->rt_forw);
  2039.              error = OK;
  2040.              }
  2041.         }
  2042.     for (pHashList = nethash; pHashList < &nethash [ROUTEHASHSIZ]; pHashList++)
  2043.         {
  2044.         pRt = pHashList->rt_forw;
  2045.         for (; pRt != (struct rt_entry *)pHashList; pRt = pRt->rt_forw)
  2046.              {
  2047.              if (pRt->rt_ifp != pIf)
  2048.                  continue;
  2049.              if (!deleteAllRoutes && ((pRt->rt_state & RTS_OTHER) != 0))
  2050.                  continue;
  2051.              pRt = pRt->rt_back;
  2052.              rtdelete (pRt->rt_forw);
  2053.              error = OK;
  2054.              }
  2055.         }
  2056.     return (error);
  2057.     }
  2058. #ifdef ROUTER_STACK
  2059. /***************************************************************************
  2060. *
  2061. * ripInterfaceDelete - delete the interface
  2062. *
  2063. * This function deletes the interface structure pointed to by <pIf>
  2064. * and frees the memory associated with it. This function is actually
  2065. * a wrapper for the ripInterfaceIntDelete() call that actually deletes
  2066. * the interface.
  2067. *
  2068. * RETURNS: OK or ERROR
  2069. *
  2070. * NOMANUAL
  2071. *
  2072. */
  2073. LOCAL STATUS ripInterfaceDelete
  2074.     (
  2075.     struct interface * pIf
  2076.     )
  2077.     {
  2078.     struct interface * pTmpIf;
  2079.     struct interface * pPrevIf;
  2080.     /* Search for the interface in our list */
  2081.     pPrevIf = ripIfNet; 
  2082.     for (pTmpIf = ripIfNet; pTmpIf && pTmpIf != pIf; pTmpIf = pTmpIf->int_next)
  2083.         pPrevIf = pTmpIf;
  2084.     if (pTmpIf == NULL)
  2085.         return (ERROR);
  2086.     return (ripInterfaceIntDelete (pIf, pPrevIf));
  2087.     }
  2088. #endif /* ROUTER_STACK */
  2089. /***************************************************************************
  2090. *
  2091. * ripInterfaceIntDelete - delete the interface
  2092. *
  2093. * This function deletes the interface structure pointed to by <pIf>
  2094. * from the list of interfaces and frees the memory associated with
  2095. * the interface.
  2096. *
  2097. * RETURNS: OK or ERROR
  2098. *
  2099. * NOMANUAL
  2100. *
  2101. */
  2102. LOCAL STATUS ripInterfaceIntDelete
  2103.     (
  2104.     struct interface * pIf,
  2105.     struct interface * pPrevIf
  2106.     )
  2107.     {
  2108. #ifdef RIP_MD5
  2109.     RIP_AUTH_KEY * pAuth;
  2110. #endif /* RIP_MD5 */
  2111.     /* Reset head of the list if necessary. */
  2112.     if (pIf == ripIfNet)
  2113.         ripIfNet = pIf->int_next;
  2114.     else
  2115.         pPrevIf->int_next = pIf->int_next;
  2116.     /* 
  2117.      * If the matching interface is the last entry in the list, reset
  2118.      * the (global) tail pointer so the list will rebuild correctly.
  2119.      */
  2120.     if (pIf->int_next == NULL)
  2121.         {
  2122.         /* 
  2123.          * Set tail pointer to head of list if the matching interface 
  2124.          * is the only entry. Otherwise set it to the next field of
  2125.          * the new list tail (which currently points to NULL).
  2126.          */
  2127.         if (ripIfNet == NULL)   /* Only entry in list? */
  2128.             ifnext = &ripIfNet;
  2129.         else
  2130.             ifnext = &pPrevIf->int_next;
  2131.         }
  2132. #ifdef RIP_MD5
  2133.     /* free the auth keys for this interface */
  2134.     pAuth = pIf->pAuthKeys;
  2135.     while (pAuth != NULL)
  2136.         {
  2137.         pIf->pAuthKeys = pAuth->pNext;
  2138.         free (pAuth);
  2139.         pAuth = pIf->pAuthKeys;
  2140.         }
  2141. #endif /* RIP_MD5 */
  2142.     free (pIf); 
  2143.     return (OK);
  2144.     }
  2145. /***************************************************************************
  2146. *
  2147. * ripIfExcludeListAdd - Add an interface to the RIP exclusion list
  2148. *
  2149. * This function adds the interface specified by <ifName> to a list of
  2150. * interfaces on which RIP will not be started. This can be used to 
  2151. * prevent RIP from starting on an interface.
  2152. *
  2153. * RETURNS: OK if the interface was successfully added to the list;
  2154. *          ERROR otherwise.
  2155. *
  2156. * NOTE: This command must be issued prior to the interface being added
  2157. *       to the system, as RIP starts on an interface, unless it has been
  2158. *       excluded, as soon as an interface comes up.
  2159. *       If RIP was already running on the interface which is now desired
  2160. *       to be excluded from RIP, the ripIfReset command should be used 
  2161. *       after the ripIfExcludeListAdd command.
  2162. */
  2163. STATUS ripIfExcludeListAdd
  2164.     (
  2165.     char *  pIfName  /* name of interface to be excluded */
  2166.     )
  2167.     {
  2168.     RT_IFLIST * pIfList;
  2169.     int  slen; 
  2170.     if (pIfName == NULL)
  2171.         return (ERROR);
  2172.     slen = strlen (pIfName);
  2173.     if (slen == 0 || slen >= IFNAMSIZ)
  2174.         return (ERROR);
  2175.     pIfList = (RT_IFLIST *)malloc (sizeof (RT_IFLIST));
  2176.     if (pIfList == NULL)
  2177.         return (ERROR);
  2178.     strcpy (pIfList->rtif_name, pIfName);
  2179.     /* 
  2180.      * Insert the interface in the list of interfaces on which RIP is not
  2181.      * to be started
  2182.      */
  2183.     lstAdd (&ripIfExcludeList, &(pIfList->node)); 
  2184.     return (OK);
  2185.     }
  2186. /***************************************************************************
  2187. *
  2188. * ripIfExcludeListDelete - Delete an interface from RIP exclusion list
  2189. *
  2190. * This function deletes the interface specified by <ifName> from the list of
  2191. * interfaces on which RIP will not be started. That is, RIP will start on the
  2192. * interface when it is added or comes up.
  2193. *
  2194. * RETURNS: OK if the interface was successfully removed from the list;
  2195. *          ERROR otherwise.
  2196. *
  2197. * NOTE: RIP will not automatically start on the interface. The ripIfSearch() 
  2198. *       call will need to be made after this call to cause RIP to start on
  2199. *       this interface.
  2200. *
  2201. */
  2202. STATUS ripIfExcludeListDelete
  2203.     (
  2204.     char *  pIfName  /* name of un-excluded interface */
  2205.     )
  2206.     {
  2207.     RT_IFLIST * pIfList;
  2208.     int  slen; 
  2209.     if (pIfName == NULL)
  2210.         return (ERROR);
  2211.     slen = strlen (pIfName);
  2212.     if (slen == 0 || slen >= IFNAMSIZ)
  2213.         return (ERROR);
  2214.     for (pIfList = (RT_IFLIST *)lstFirst (&ripIfExcludeList);
  2215.          pIfList != NULL; pIfList = (RT_IFLIST *)lstNext (&pIfList->node))
  2216.         {
  2217.         if (slen == strlen (pIfList->rtif_name) && 
  2218.             strcmp (pIfName, pIfList->rtif_name) == 0) 
  2219.             {
  2220.             /* 
  2221.              * Delete the interface from the list of interfaces on 
  2222.              * which RIP is not to be started
  2223.              */
  2224.             lstDelete (&ripIfExcludeList, &pIfList->node);
  2225.             free ((char *)pIfList);
  2226.             return (OK);
  2227.             }
  2228.         }
  2229.     return (ERROR);
  2230.     }
  2231. /***************************************************************************
  2232. *
  2233. * ripIfExcludeListCheck - Check if an interface is on the RIP exclusion list
  2234. *
  2235. * This function checks if the interface specified by <ifName> is on the
  2236. * RIP exclusion list.
  2237. *
  2238. * RETURNS: OK if the interface exists on the list; ERROR otherwise.
  2239. *
  2240. * NOMANUAL
  2241. */
  2242. STATUS ripIfExcludeListCheck
  2243.     (
  2244.     char *  pIfName  /* name of interface to check*/
  2245.     )
  2246.     {
  2247.     RT_IFLIST * pIfList;
  2248.     int  slen; 
  2249.     if (pIfName == NULL)
  2250.         return (ERROR);
  2251.     slen = strlen (pIfName);
  2252.     if (slen == 0 || slen >= IFNAMSIZ)
  2253.         return (ERROR);
  2254.     for (pIfList = (RT_IFLIST *)lstFirst (&ripIfExcludeList);
  2255.          pIfList != NULL; pIfList = (RT_IFLIST *)lstNext (&pIfList->node))
  2256.         {
  2257.         if (slen == strlen (pIfList->rtif_name) && 
  2258.             strcmp (pIfName, pIfList->rtif_name) == 0) 
  2259.             {
  2260.             return (OK);
  2261.             }
  2262.         }
  2263.     return (ERROR);
  2264.     }
  2265. /***************************************************************************
  2266. *
  2267. * ripIfExcludeListShow - Show the RIP interface exclusion list
  2268. *
  2269. * This function prints out the interfaces on which RIP will not be started.
  2270. *
  2271. * RETURNS: Nothing
  2272. *
  2273. */
  2274. void ripIfExcludeListShow (void)
  2275.     {
  2276.     RT_IFLIST * pIfList;
  2277.     printf ("List of interfaces on which RIP will not be started:n");
  2278.     for (pIfList = (RT_IFLIST *)lstFirst (&ripIfExcludeList);
  2279.          pIfList != NULL; pIfList = (RT_IFLIST *)lstNext (&pIfList->node))
  2280.         printf ("%sn", pIfList->rtif_name);
  2281.     printf ("n");
  2282.     }