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

VxWorks

开发平台:

C/C++

  1. /* startup.c - RIP routines for creating initial data structures */
  2. /* Copyright 1984 - 2002 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5.  * Copyright (c) 1983, 1988, 1993
  6.  * The Regents of the University of California.  All rights reserved.
  7.  *
  8.  * Redistribution and use in source and binary forms, with or without
  9.  * modification, are permitted provided that the following conditions
  10.  * are met:
  11.  * 1. Redistributions of source code must retain the above copyright
  12.  *    notice, this list of conditions and the following disclaimer.
  13.  * 2. Redistributions in binary form must reproduce the above copyright
  14.  *    notice, this list of conditions and the following disclaimer in the
  15.  *    documentation and/or other materials provided with the distribution.
  16.  * 3. All advertising materials mentioning features or use of this software
  17.  *    must display the following acknowledgement:
  18.  * This product includes software developed by the University of
  19.  * California, Berkeley and its contributors.
  20.  * 4. Neither the name of the University nor the names of its contributors
  21.  *    may be used to endorse or promote products derived from this software
  22.  *    without specific prior written permission.
  23.  *
  24.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  25.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  26.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  27.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  28.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  29.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  30.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  31.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  32.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  33.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  34.  * SUCH DAMAGE.
  35.  * @(#)startup.c 8.2 (Berkeley) 4/28/95
  36.  */
  37. /*
  38. modification history
  39. --------------------
  40. 01l,22mar02,niq  Merged from Synth view, tor3_x.synth branch, ver 01q
  41. 01k,24jan02,niq  SPR 68672 - Add route to the local end of the PTP link with
  42.                  the correct netmask
  43.                  SPR 72415 - Added support for Route tags
  44. 01j,15oct01,rae  merge from truestack ver 01m, base 01h (SPR #69983 etc.)
  45. 01i,10nov00,spm  merged from version 01j of tor3_x branch (SPR #29099 fix)
  46. 01h,11sep98,spm  provided fatal error handling in place of quit routine,
  47.                  replaced ripMakeAddr with optimized results (SPR #22350)
  48. 01g,01sep98,spm  modified addrouteforif to correctly support interfaces 
  49.                  with classless netmasks (SPR #22220); changed spacing
  50.                  for coding standards
  51. 01f,26jul98,spm  moved assignment from conditional to avoid compiler warnings
  52. 01e,06oct97,gnn  fixed SPR 9211 and added sendHook functionality
  53. 01d,16may97,gnn  added code to initialize hooks to NULL.
  54. 01c,07apr97,gnn  cleared up some of the more egregious warnings.
  55.                  added MIB-II interfaces and options.
  56. 01b,24feb97,gnn  added rip version 2 functionality.
  57. 01a,26nov96,gnn  created from BSD4.4 routed
  58. */
  59. /*
  60. DESCRIPTION
  61. */
  62. /*
  63.  * Routing Table Management Daemon
  64.  */
  65. #include "vxWorks.h"
  66. #include "rip/defs.h"
  67. #include "sys/ioctl.h"
  68. #include "net/if.h"
  69. #include "net/if_dl.h"
  70. #include "netinet/in.h"
  71. #include "stdlib.h"
  72. #include "logLib.h"
  73. #include "m2Lib.h"
  74. #include "sockLib.h"
  75. #ifdef VIRTUAL_STACK
  76. #include "netinet/vsLib.h"
  77. #include "netinet/vsRip.h"
  78. #endif /* VIRTUAL_STACK */
  79. #define same(a1, a2) 
  80.         (memcmp((a1)->sa_data, (a2)->sa_data, 14) == 0)
  81. /* globals */
  82. #ifndef VIRTUAL_STACK
  83. IMPORT int routedDebug;
  84. IMPORT RIP ripState;
  85. struct interface * ripIfNet;
  86. struct interface ** ifnext = &ripIfNet;
  87. #endif /* VIRTUAL_STACK */
  88. /* locals */
  89. #ifndef VIRTUAL_STACK
  90. LOCAL int foundloopback; /* valid flag for loopaddr */
  91. LOCAL struct sockaddr  loopaddr; /* our address on loopback */
  92. LOCAL struct rt_addrinfo info;
  93. #endif /* VIRTUAL_STACK */
  94. /* forward declarations */
  95. IMPORT void _ripAddrsXtract (caddr_t, caddr_t, struct rt_addrinfo *); 
  96. IMPORT int sysctl_rtable (int *, int, caddr_t, size_t *, caddr_t *, size_t);
  97. IMPORT void _ripIfShow (struct interface *);
  98. void addrouteforif(register struct interface *);
  99. LOCAL int add_ptopt_localrt (register struct interface *, int);
  100. /* defines */
  101. /* Sleazy use of local variables throughout file, warning!!!! */
  102. #define NETMASK info.rti_info[RTAX_NETMASK]
  103. #define IFAADDR info.rti_info[RTAX_IFA]
  104. #define BRDADDR info.rti_info[RTAX_BRD]
  105. /*****************************************************************************
  106. *
  107. * routedIfInit - initialize interface information
  108. *
  109. * This routine behaves differently based on the <ifindex> parameter.
  110. * If <ifIndex> is 0, this routine searches the kernel's "ifnet" interface
  111. * list for all interfaces belonging to the AF_INET family and copies the
  112. * interface data into RIP private interface table list if that interface is UP.
  113. * If <ifIndex> is non-zero then only the specified interface is queried
  114. * and its data copied if the interface is UP.
  115. *
  116. * Interfaces that are down are ignored.
  117. *
  118. * For every interface retrieved from the kernel, this routine checks if
  119. * a route for the interface address already exists in RIP's table. If it does
  120. * this signifies that RIP already knows about this interface address; hence it
  121. * skips over that entry. If a route doesn't exist, then RIP adds a route
  122. * to that interface in its own table as well as in the system Routing database.
  123. * The above procedure is repeated for each address entry present for an
  124. * interface.
  125. *
  126. * If an interface has multiple IP addresses (aliases), this routine creates
  127. * a different interface entry (virtual interface) for each address. 
  128. * For example an interface "fei0" in the system with address "100.10.1.1"
  129. * and "144.1.1.1" will result in two interfaces in RIP's interface list - 
  130. *  1) "fei0", 100.10.1.1
  131. * 2) "fei0", 144.1.1.1
  132. * The <resetFlag> parameter distinguishes the initial execution of this
  133. * routine from later executions which add new interfaces to the list. 
  134. * It is used to initialize RIP's interface list.
  135. *
  136. * If the sytem runs out of memory during uring the addition of an interface
  137. * to RIP's internal list, or if is encounters some incomplete entries, 
  138. * the "lookforinterfaces" flag is set to automatically repeat the execution
  139. * of this routine at the next timer interval. 
  140. *
  141. * The initial execution of this routine (during RIP startup) must succeed
  142. * or the session will not begin, but the session will continue regardless
  143. * of the results of later executions.
  144. *
  145. * RETURNS: OK, or ERROR if unable to process interface table.
  146. *
  147. * NOMANUAL
  148. *
  149. * INTERNAL
  150. * After the RIP session has started, the routine can be called again
  151. * within the context of either the RIP timer task or the RIP input task. 
  152. * The caller should take the ripLockSem semaphore to provide mutual
  153. * exclusion so that no message processing happens while the 
  154. * interface list is changed and any corresponding route entries are
  155. * created.
  156. */
  157. STATUS routedIfInit
  158.     (
  159.     BOOL  resetFlag,  /* build entire new list or add entries? */
  160.     long ifIndex /* particular interface to search for, 0-all */
  161.     )
  162.     {
  163.     struct interface ifs, *ifp;
  164.     size_t needed;
  165.     int mib[6], no_ipaddr = 0, flags = 0;
  166.     char *buf, *cplim, *cp;
  167.     register struct if_msghdr *ifm;
  168.     register struct ifa_msghdr *ifam;
  169.     struct sockaddr_dl *sdl = NULL;
  170.     struct sockaddr_in *sin;
  171.     struct ip_mreq ipMreq;  /* Structure for joining multicast groups. */
  172.     u_long i;
  173.     if (resetFlag)
  174.         {
  175.         /* Reset globals in case of restart after shutdown. */
  176.         foundloopback = 0;
  177.         ripIfNet = NULL;
  178.         ifnext = &ripIfNet;
  179.         }
  180.     ripState.lookforinterfaces = FALSE;
  181.     ipMreq.imr_multiaddr.s_addr = htonl (RIP_MCAST_ADDR);
  182.     /* 
  183.      * The sysctl_rtable routine provides access to internal networking data 
  184.      * according to the specified operations. The NET_RT_IFLIST operator
  185.      * traverses the entire internal "ifnet" linked list created when the
  186.      * network devices are initialized. The third argument, when non-zero,
  187.      * restricts the search to a particular unit number. In this case, all
  188.      * devices are examined. The first argument, when non-zero, limits the
  189.      * addresses to the specified address family. 
  190.      */
  191.     mib[0] = AF_INET;
  192.     mib[1] = NET_RT_IFLIST;
  193.     mib[2] = ifIndex;
  194.     /* 
  195.      * The first call to the routine determines the amount of space needed
  196.      * for the results. No data is actually copied.
  197.      */
  198.     if (sysctl_rtable(mib, 3, NULL, &needed, NULL, 0) < 0)
  199.         {
  200.         if (routedDebug)
  201.             logMsg ("Error %x estimating size of interface buffer.n", errno,
  202.                     0, 0, 0, 0, 0);
  203.         return (ERROR);
  204.         }
  205.     if (routedDebug)
  206.         logMsg ("Executing routedInit for iIndex = %d.n", ifIndex, 0, 0, 0, 0, 0);
  207.     /* 
  208.      * Allocate the required data, and repeat the system call to copy the
  209.      * actual values.
  210.      */
  211.     buf = malloc (needed);
  212.     if (buf == NULL)
  213.         {
  214.         if (routedDebug)
  215.             logMsg ("Error %x allocating interface buffer.n", errno,
  216.                     0, 0, 0, 0, 0);
  217.         return (ERROR);
  218.         }
  219.     if (sysctl_rtable(mib, 3, buf, &needed, NULL, 0) < 0)
  220.         {
  221.         if (routedDebug)
  222.             logMsg ("Error %x retrieving interface table.n", errno,
  223.                     0, 0, 0, 0, 0);
  224.         free (buf);
  225.         return (ERROR);
  226.         }
  227.     /* End of VxWorks specific stuff. */
  228.     /* 
  229.      * Analyze the retrieved data. The provided buffer now contains a 
  230.      * structure of type if_msghdr for each interface followed by zero 
  231.      * or more structures of type ifa_msghdr for each address for that
  232.      * interface. The if_msghdr structures have type fields of
  233.      * RTM_IFINFO and the address structures have type fields of 
  234.      * RTM_NEWADDR.
  235.      */
  236.     cplim = buf + needed;
  237.     for (cp = buf; cp < cplim; cp += ifm->ifm_msglen) 
  238.         {
  239.         ifm = (struct if_msghdr *)cp;
  240.         if (ifm->ifm_type == RTM_IFINFO) 
  241.             {
  242.             /* Parse the generic interface information. */
  243.             memset(&ifs, 0, sizeof(ifs));
  244.             ifs.int_flags = flags = (0xffff & ifm->ifm_flags) | IFF_INTERFACE;
  245.             /* 
  246.              * The sockaddr_dl structure containing the link-level address
  247.              * immediately follows the if_msghdr structure.
  248.              */
  249.             sdl = (struct sockaddr_dl *) (ifm + 1);
  250.             sdl->sdl_data[sdl->sdl_nlen] = 0;
  251.             no_ipaddr = 1;
  252.             continue;
  253.             }
  254.         /* 
  255.          * Only address entries should be present at this point.
  256.          * Exit if an unknown type is detected.
  257.          */
  258.         if (ifm->ifm_type != RTM_NEWADDR)
  259.             {
  260.             if (routedDebug)
  261.                 logMsg ("Unexpected entry in interface table.n", 
  262.                         0, 0, 0, 0, 0, 0);
  263.             free (buf);
  264.             return (ERROR);
  265.             }
  266.         /* If RIP is not desired on this interface, then so be it */
  267.         if (ripIfExcludeListCheck (sdl->sdl_data) == OK)
  268.             continue;
  269.         /* 
  270.          * Ignore the address information if the interface initialization
  271.          * is incomplete. Set flag to repeat the search at the next timer 
  272.          * interval.
  273.          */
  274.         if ( (flags & IFF_UP) == 0)
  275.             {
  276.             continue;
  277.             }
  278.         /* Access the address information through the ifa_msghdr structure. */
  279.         ifam = (struct ifa_msghdr *)ifm;
  280.         /* Reset the pointers to access the address pointers. */
  281.         info.rti_addrs = ifam->ifam_addrs;
  282.         _ripAddrsXtract ((char *)(ifam + 1), cp + ifam->ifam_msglen, &info);
  283.         if (IFAADDR == 0) 
  284.             {
  285.             if (routedDebug)
  286.                 logMsg ("No address for %s.n", (int)sdl->sdl_data,
  287.                         0, 0, 0, 0, 0);
  288.             continue;
  289.             }
  290.         /* Copy and process the actual address values. */
  291.         ifs.int_addr = *IFAADDR;
  292.         if (ifs.int_addr.sa_family != AF_INET)
  293.             continue;
  294.         no_ipaddr = 0;
  295.         if (ifs.int_flags & IFF_POINTOPOINT)
  296.             {
  297.             if (BRDADDR == 0)    /* No remote address specified? */
  298.                 {
  299.                 if (routedDebug)
  300.                     logMsg ("No dstaddr for %s.n", (int)sdl->sdl_data, 
  301.                             0, 0, 0, 0, 0);
  302.                 continue;
  303.                 }
  304.             if (BRDADDR->sa_family == AF_UNSPEC)
  305.                 {
  306.                 ripState.lookforinterfaces = TRUE;
  307.                 continue;
  308.                 }
  309.             /* Store the remote address for the link in the correct place. */
  310.             ifs.int_dstaddr = *BRDADDR;
  311.             }
  312.         /*
  313.          * Skip interfaces we already know about. But if there are
  314.          * other interfaces that are on the same network as the ones
  315.          * we already know about, we want to know about them as well.
  316.          */
  317.         if (ifs.int_flags & IFF_POINTOPOINT)
  318.             {
  319.             if (ripIfWithDstAddrAndIndex (&ifs.int_dstaddr, NULL, 
  320.                                           ifam->ifam_index))
  321.                 continue;
  322.             }
  323.         else if (ripIfWithAddrAndIndex (&ifs.int_addr, ifam->ifam_index))
  324.             continue;
  325.         if (ifs.int_flags & IFF_LOOPBACK)
  326.             {
  327.             ifs.int_flags |= IFF_PASSIVE;
  328.             foundloopback = 1;
  329.             loopaddr = ifs.int_addr;
  330.             for (ifp = ripIfNet; ifp; ifp = ifp->int_next)
  331.                  if (ifp->int_flags & IFF_POINTOPOINT)
  332.                      add_ptopt_localrt(ifp, 0);
  333.             }
  334.         /* Assign the broadcast address for the interface, if any. */
  335.         if (ifs.int_flags & IFF_BROADCAST)
  336.             {
  337.             if (BRDADDR == 0)
  338.                 {
  339.                 if (routedDebug)
  340.                     logMsg ("No broadcast address for %s.n",
  341.                             (int)sdl->sdl_data, 0, 0, 0, 0, 0);
  342.                 continue;
  343.                 }
  344.             ifs.int_dstaddr = *BRDADDR;
  345.             }
  346.          /*
  347.           * Use a minimum metric of one; treat the interface metric 
  348.           * (default 0) as an increment to the hop count of one.
  349.           */
  350.         ifs.int_metric = ifam->ifam_metric + 1;
  351.         /* Assign the network and subnet values. */
  352.         if (NETMASK == 0) 
  353.             {
  354.             if (routedDebug)
  355.                 logMsg ("No netmask for %s.n", (int)sdl->sdl_data,
  356.                         0, 0, 0, 0, 0);
  357.             continue;
  358.             }
  359.         /* 
  360.          * For AF_INET addresses, the int_subnetmask field copied here
  361.          * defaults to the class-based value for the associated int_addr 
  362.          * field, but will contain some other value if explicity specified.
  363.          */
  364.         sin = (struct sockaddr_in *)NETMASK;
  365.         ifs.int_subnetmask = ntohl (sin->sin_addr.s_addr);
  366.         /*
  367.          * The network number stored here may differ from the original
  368.          * value accessed through the ifnet linked list. The original value
  369.          * is equal to the class-based setting by default, but is reset
  370.          * to the same value as the int_subnetmask field if a less
  371.          * specific (i.e. supernetted) value is assigned. This value is
  372.          * always set equal to the class-based value, even if a supernet
  373.          * is specified.
  374.          */
  375.         sin = (struct sockaddr_in *)&ifs.int_addr;
  376.         i = ntohl(sin->sin_addr.s_addr);
  377.         if (IN_CLASSA(i))
  378.             ifs.int_netmask = IN_CLASSA_NET;
  379.         else if (IN_CLASSB(i))
  380.             ifs.int_netmask = IN_CLASSB_NET;
  381.         else
  382.             ifs.int_netmask = IN_CLASSC_NET;
  383.         ifs.int_net = i & ifs.int_netmask;
  384.         ifs.int_subnet = i & ifs.int_subnetmask;
  385.         /* 
  386.          * The IFF_SUBNET flag indicates that the interface does not use the
  387.          * class-based mask stored in the int_netmask field: it may be more 
  388.          * or less specific than that value.
  389.          */
  390.         if (ifs.int_subnetmask != ifs.int_netmask)
  391.             ifs.int_flags |= IFF_SUBNET;
  392.         ifp = (struct interface *)malloc (sdl->sdl_nlen + 1 + sizeof(ifs));
  393.         if (ifp == 0)
  394.             {
  395.             if (routedDebug)
  396.                 logMsg ("routedIfInit: out of memory.n", 0, 0, 0, 0, 0, 0);
  397.             ripState.lookforinterfaces = TRUE;
  398.             break;
  399.             }
  400.         *ifp = ifs;
  401.         /*
  402.          * Count the # of directly connected networks
  403.          * and point to point links which aren't looped
  404.          * back to ourself.  This is used below to
  405.          * decide if we should be a routing ``supplier''.
  406.          */
  407.         if ( (ifs.int_flags & IFF_LOOPBACK) == 0 &&
  408.             ( (ifs.int_flags & IFF_POINTOPOINT) == 0 ||
  409.              ripIfWithAddr (&ifs.int_dstaddr) == 0))
  410.             ripState.externalinterfaces++;
  411.         /*
  412.          * If we have a point-to-point link, we want to act
  413.          * as a supplier even if it's our only interface,
  414.          * as that's the only way our peer on the other end
  415.          * can tell that the link is up.
  416.          */
  417.         if ( (ifs.int_flags & IFF_POINTOPOINT) && ripState.supplier < 0)
  418.             ripState.supplier = 1;
  419.         /* 
  420.          * Copy the interface name specified in the link-level address. 
  421.          * into the space provided.
  422.          */
  423.         ifp->int_name = (char *)(ifp + 1);
  424.         strcpy (ifp->int_name, sdl->sdl_data);
  425.         /* Set the index of the interface */
  426.         ifp->int_index = ifam->ifam_index;
  427.         /* Add the given entry to the ripIfNet linked list. */
  428.         *ifnext = ifp;
  429.         ifnext = &ifp->int_next;
  430.         /* Create a route to the network reachable with the new address. */
  431.         addrouteforif (ifp);
  432.         /* Set the MIB variables for the configuration on this interface. */
  433.         bzero ( (char *)&ifp->ifStat, sizeof(ifp->ifStat));
  434.         bzero ( (char *)&ifp->ifConf, sizeof(ifp->ifConf));
  435.         sin = (struct sockaddr_in *)&ifs.int_addr;
  436.         i = sin->sin_addr.s_addr;
  437.         ifp->ifStat.rip2IfStatAddress = i;
  438.         ifp->ifConf.rip2IfConfAddress = i;
  439.         ifp->ifConf.rip2IfConfAuthType = ripState.ripConf.rip2IfConfAuthType;
  440.         bcopy (ripState.ripConf.rip2IfConfAuthKey,
  441.                ifp->ifConf.rip2IfConfAuthKey, 16);
  442.         ifp->ifConf.rip2IfConfSend = ripState.ripConf.rip2IfConfSend;
  443.         ifp->ifConf.rip2IfConfReceive = ripState.ripConf.rip2IfConfReceive;
  444.         ifp->ifConf.rip2IfConfDefaultMetric = 
  445.                                       ripState.ripConf.rip2IfConfDefaultMetric;
  446.         ifp->ifConf.rip2IfConfStatus = ripState.ripConf.rip2IfConfStatus;
  447.         ifp->authHook = NULL;
  448.         ifp->leakHook = NULL;
  449.         ifp->sendHook = NULL;
  450.         /*
  451.          * If multicasting is enabled and the interface supports it, 
  452.          * attempt to join the RIP multicast group.
  453.          */
  454.         if (ripState.multicast && (ifs.int_flags & IFF_MULTICAST))
  455.             {
  456.             ipMreq.imr_interface.s_addr = i;
  457.             if (setsockopt (ripState.s, IPPROTO_IP, IP_ADD_MEMBERSHIP,
  458.                             (char *)&ipMreq, sizeof (ipMreq)) < 0)
  459.                 {
  460.                 if (routedDebug)
  461.                     logMsg ("setsockopt IP_ADD_MEMBERSHIP error:n",
  462.                             0, 0, 0, 0, 0, 0);
  463.                 }
  464.             }
  465.         }
  466.     if (ripState.externalinterfaces > 1 && ripState.supplier < 0)
  467.         ripState.supplier = 1;
  468.     free (buf);
  469.     return (OK);
  470.     }
  471. /*
  472.  * Add route for interface if not currently installed.
  473.  * Create route to other end if a point-to-point link,
  474.  * otherwise a route to this (sub)network.
  475.  * INTERNET SPECIFIC.
  476.  */
  477. void addrouteforif(ifp)
  478. register struct interface *ifp;
  479. {
  480. struct sockaddr_in net;
  481. struct sockaddr *dst;
  482. int state;
  483. register struct rt_entry *rt;
  484.         int refcnt_save = 0;
  485.         int subnets_cnt_save = 0;
  486.         /* Clear the fact there there are no routes for this interface */
  487.         ifp->int_flags &= ~IFF_ROUTES_DELETED;
  488.         /*
  489.          * The algorithm explained....
  490.          * We are going to add  route(s) for the interface.
  491.          * The following cases exist:
  492.          * 1) The interface is not PPP and  not-subnetted 
  493.          *    e.g, 164.10.1.1/16
  494.          *         In this case we just want to add the following route
  495.          *            164.10.0.0 255.255.0.0 --> 164.10.1.1
  496.          *         If there already exists another route for that same network,
  497.          *            if that route is not an internally generated route
  498.          *               increment rt_refcnt 
  499.          *            else
  500.          *               Delete the existing route and save its ref counts
  501.          *               Add route through this interface.
  502.          *               Set the reference counts from the previous route.
  503.          *               increment rt_refcnt and rt_subnets_cnt
  504.          *         else
  505.          *            Add the route through the inetrface
  506.          *            Set rt_refcnt and rt_subnets_cnt to zero
  507.          *
  508.          * 2) The interface is not PPP and is subnetted 
  509.          *    e.g, 164.10.2.1/24
  510.          *         In this case we want to add the following routes
  511.          *            164.10.2.0 255.255.255.0 --> 164.10.2.1
  512.          *            164.10.0.0 255.255.0.0   --> 164.10.2.1 (Internal route)
  513.          *         The internal route is used for border gateway filtering.
  514.          *
  515.          *         If there already exists another route for that same 
  516.          *          (sub)network,
  517.          *            if that route is not an internally generated route
  518.          *               increment rt_refcnt 
  519.          *            else
  520.          *               Delete the existing route and save its ref counts
  521.          *               Add route through this interface.
  522.          *               Set the reference counts from the previous route.
  523.          *               increment rt_refcnt and rt_subnets_cnt
  524.          *         else
  525.          *            Add the route through the inetrface
  526.          *            Set rt_refcnt and rt_subnets_cnt to zero
  527.          *         If there exists a route for the class based network
  528.          *            increment the rt_refcnt and rt_subnets_cnt for the route
  529.          *         else
  530.          *            Add the internal class based route. 
  531.          *            Set both the ref counts to zero.
  532.          *
  533.          * 3) The interface is PPP
  534.          *    e.g, 164.10.1.1/32 --> 124.10.2.2
  535.          *         In this case we just want to add the following routes
  536.          *            124.10.2.2   255.255.255.255  --> 164.10.1.1
  537.          *            164.10.1.1   255.255.255.255  --> 127.0.0.1
  538.          *         If there already exists another route for the destination
  539.          *            increment rt_refcnt 
  540.          *         else
  541.          *            Add the route through the inetrface
  542.          *            Set rt_refcnt and rt_subnets_cnt to zero
  543.          *         Add a route for the local address of the link thru the 
  544.          *          loopback interface.
  545.          */
  546.         /* Check if there already exists a route for the network (remote end)*/
  547. if (ifp->int_flags & IFF_POINTOPOINT)
  548. dst = &ifp->int_dstaddr;
  549. else {
  550. memset(&net, 0, sizeof (net));
  551.                 net.sin_len = sizeof (net);
  552. net.sin_family = AF_INET;
  553. net.sin_addr.s_addr = htonl (ifp->int_subnet);
  554. dst = (struct sockaddr *)&net;
  555. }
  556.         if ((rt = rtlookup(dst)) == NULL) 
  557.             rt = rtfind(dst);
  558. if (rt)
  559.             {
  560.             /* 
  561.              * If we have an indirect route to the destination, 
  562.              * delete it as we now have a direct route
  563.              */
  564.             if ((rt->rt_state & RTS_INTERFACE) == 0)
  565.                 rtdelete (rt);
  566.             else
  567.                 {
  568.                 if (ifp->int_flags & IFF_POINTOPOINT)
  569.                     {
  570.                     rt->rt_refcnt++;
  571.                     if (ifp->int_flags & IFF_POINTOPOINT && foundloopback) 
  572.                         add_ptopt_localrt(ifp, 0);
  573.                     return;
  574.                     }
  575.                 if ((rt->rt_state & (RTS_INTERFACE | RTS_INTERNAL))
  576.                         == RTS_INTERFACE)
  577.                     {
  578.                     /* The route is not an internal route */
  579.                     if (rt->rt_ifp->int_subnetmask == ifp->int_subnetmask)
  580.                         {
  581.                         /* 
  582.                          * This interface is on the same (sub)network as the
  583.                          * retrieved route. Increment the reference count.
  584.                          */
  585.                         rt->rt_refcnt++;
  586.                         /*
  587.                          * If the interface uses classless addressing, 
  588.                          * an additional entry is stored in the routing table
  589.                          * which can be correctly interpreted by RIP-1 and 
  590.                          * RIP-2 routers that are not directly connected to
  591.                          * the interface's network. The appropriate entry is
  592.                          * selected by the border gateway filtering performed
  593.                          * when updates are generated.
  594.                          */
  595.                         if (ifp->int_flags & IFF_SUBNET) 
  596.                             {
  597.                             net.sin_addr.s_addr = htonl (ifp->int_net);
  598.                             if ((rt = rtlookup(dst)) == NULL) 
  599.                                 rt = rtfind(dst);
  600.                             if (rt == 0)
  601.                                 {
  602.                                 if (routedDebug) 
  603.                                     logMsg ("Error! Didn't find classful route"
  604.                                             " for %x, interface %s.n", 
  605.                                             (int)ifp->int_net, 
  606.                                             (int)ifp->int_name, 0, 0, 0, 0);
  607.                                 }
  608.                             else 
  609.                                 {
  610.                                 rt->rt_refcnt++;
  611.                                 rt->rt_subnets_cnt++;
  612.                                 if ((rt->rt_state & (RTS_INTERNAL|RTS_SUBNET))
  613.                                     == (RTS_INTERNAL|RTS_SUBNET) && 
  614.                                     (ifp->int_metric < rt->rt_metric))
  615.                                     rtchange (rt, &ifp->int_addr, 
  616.                                               ifp->int_metric, NULL, 0, 0, 
  617.                                               ifp);
  618.                                 }
  619.                             }
  620.                         return;
  621.                         }
  622.                     }
  623.                 else
  624.                     {
  625.                     /*
  626.                      * If this was a classful route installed by an earlier
  627.                      * subnetted interface, save the reference count values
  628.                      * as we'll need to restore them on the route that will
  629.                      * be installed later
  630.                      */
  631.                     refcnt_save = rt->rt_refcnt + 1; 
  632.                     subnets_cnt_save = rt->rt_subnets_cnt + 1;
  633.                     rtdelete (rt);
  634.                     }
  635.                 }
  636.             }
  637. /*
  638.  * If the interface uses classless addressing, an additional entry
  639.          * is stored in the routing table which can be correctly interpreted
  640.          * by RIP-1 and RIP-2 routers that are not directly connected to
  641.          * the interface's network. The appropriate entry is selected by the
  642.          * border gateway filtering performed when updates are generated.
  643.  */
  644. if ((ifp->int_flags & (IFF_SUBNET|IFF_POINTOPOINT)) == IFF_SUBNET) {
  645. struct in_addr subnet;
  646. subnet = net.sin_addr;
  647. net.sin_addr.s_addr = htonl (ifp->int_net);
  648. if ((rt = rtlookup(dst)) == NULL) 
  649.     rt = rtfind(dst);
  650. if (rt == 0) 
  651.                     rt = rtadd(dst, &ifp->int_addr, ifp->int_metric,
  652.                                ((ifp->int_flags & (IFF_INTERFACE|IFF_REMOTE)) |
  653.                                 RTS_PASSIVE | RTS_INTERNAL | RTS_SUBNET), 
  654.                                NULL, M2_ipRouteProto_rip, 0, 0, ifp);
  655. else 
  656.                     {
  657.                     rt->rt_refcnt++; 
  658.                     rt->rt_subnets_cnt++; 
  659.                     if ((rt->rt_state & (RTS_INTERNAL|RTS_SUBNET)) == 
  660.                         (RTS_INTERNAL|RTS_SUBNET) && 
  661.                         (ifp->int_metric < rt->rt_metric))
  662.                         rtchange(rt, &ifp->int_addr, ifp->int_metric, NULL, 
  663.                                  0, 0, ifp);
  664.                     }
  665. net.sin_addr = subnet;
  666. }
  667. if (ifp->int_transitions++ > 0)
  668.             if (routedDebug)
  669. logMsg ("Warning! Re-installing route for interface %s.n", 
  670.                         (int)ifp->int_name, 0, 0, 0, 0, 0);
  671. state = ifp->int_flags &
  672.     (IFF_INTERFACE | IFF_PASSIVE | IFF_REMOTE | IFF_SUBNET);
  673. if (ifp->int_flags & IFF_POINTOPOINT && 
  674.             (ntohl(((struct sockaddr_in *)&ifp->int_dstaddr)->sin_addr.s_addr)
  675.              & ifp->int_netmask) != ifp->int_net)
  676. state &= ~RTS_SUBNET;
  677. if (ifp->int_flags & IFF_LOOPBACK)
  678. state |= RTS_EXTERNAL;
  679. rt = rtadd(dst, &ifp->int_addr, ifp->int_metric, state, NULL, 
  680.                    M2_ipRouteProto_rip, 0, 0, ifp);
  681.         /*
  682.          * Now set the reference counts.
  683.          * This might be a network route that replaced a previous
  684.          * classful route. If we had any references on that earlier
  685.          * route we need to transfer them here
  686.          */
  687.         rt->rt_refcnt = refcnt_save;
  688.         rt->rt_subnets_cnt = subnets_cnt_save;
  689. if (ifp->int_flags & IFF_POINTOPOINT && foundloopback)
  690.                     add_ptopt_localrt(ifp, 0);
  691.     }
  692. /*
  693.  * Add route to local end of point-to-point using loopback.
  694.  * If a route to this network is being sent to neighbors on other nets,
  695.  * mark this route as subnet so we don't have to propagate it too.
  696.  */
  697. int add_ptopt_localrt(ifp, refcnt)
  698.     register struct interface *ifp;
  699.     int refcnt;
  700.     {
  701.     struct rt_entry *rt;
  702.     struct sockaddr *dst;
  703.     struct sockaddr_in net;
  704.     int state;
  705.     struct sockaddr_in hostMask = {
  706.     sizeof (struct sockaddr_in),
  707.     AF_INET, 0, {INADDR_BROADCAST} };
  708.     state = RTS_INTERFACE | RTS_PASSIVE;
  709.     /* look for route to logical network */
  710.     memset(&net, 0, sizeof (net));
  711.     net.sin_len = sizeof (net);
  712.     net.sin_family = AF_INET;
  713.     net.sin_addr.s_addr = htonl (ifp->int_net);
  714.     dst = (struct sockaddr *)&net;
  715.     if ((rt = rtlookup(dst)) == NULL) 
  716.         rt = rtfind(dst);
  717.     if (rt && rt->rt_state & RTS_INTERNAL)
  718.         state |= RTS_SUBNET;
  719.     dst = &ifp->int_addr;
  720.     rt = rtfind (dst);
  721.     if (rt) 
  722.         {
  723.         if (rt->rt_state & RTS_INTERFACE)
  724.             {
  725.             /*
  726.              * We are piggybacking onto somebody else' route. So we
  727.              * should increment the ref count
  728.              */
  729.             if (refcnt == 0)
  730.                 refcnt = 1;
  731.             rt->rt_refcnt += refcnt; 
  732.             return (ERROR);
  733.             }
  734.         rtdelete(rt);
  735.         }
  736.     rt = rtadd(dst, &loopaddr, 1, state, (struct sockaddr *)&hostMask,
  737.                M2_ipRouteProto_rip, 0, 0, NULL);
  738.     if (rt)
  739.         rt->rt_refcnt = refcnt;
  740.     return (OK);
  741.     }
  742. /*
  743.  * Add route for interface or an internal network route for
  744.  * a subnetted interface
  745.  * This routine is called from the rtdelete() routine when an
  746.  * interface route is deleted and there exists other references to that
  747.  * route. This routine will add the route through another interface
  748.  * and adjust the reference count accordingly.
  749.  * The internalFlag is set when an internally generated classful route
  750.  * should be added. If the flag is not set, then a regular interface
  751.  * route is added.
  752.  * In the simplest of cases, wherein the route being deleted was referenced
  753.  * by another interface on the same network, a new route is added through that
  754.  * other interface.
  755.  *
  756.  * In other cases, the network route being deleted might be referenced by
  757.  * point to point interfaces on the same network: e.g
  758.  *   164.10.0.0/16  -->  164.10.1.1   (being deleted)
  759.  *   is referenced by the following PPP interface
  760.  *      src = 164.10.22.1, dst=164.10.22.2
  761.  * In the above case the rt_refcnt field of the route (prior to rtdelete)
  762.  * would be 2 and rt_subnets_cnt would be 0. On call to this routine,
  763.  * refCnt would be 1 and subnetsCnt would be 0
  764.  * This routine would need to add the following routes in response to the
  765.  * deletion of the 164.10.0.0/16  -->  164.10.1.1 route:
  766.  *    164.10.22.2/32 --> 164.10.22.1
  767.  *    164.10.22.1/32 --> 127.0.0.1
  768.  * Both the above routes should have rt_refcnt and rt_subnets_cnt set to zero
  769.  *
  770.  * There are many other cases where just the local or the remote end of the PPP
  771.  * interface may be referencing the route being deleted, or there may be
  772.  * multiple such interfaces. 
  773.  *     
  774.  * INPUT
  775.  *    pAddr     -  Destination of the interface route being deleted
  776.  *    refCnt    -  How many more references to this route exist
  777.  *    subnetsCnt-  How many subnetted interfaces exist for this network
  778.  *    internalFlag-Should an internal or a regular interface route be added
  779.  *    subnetMask-  Mask associated with the route being deleted
  780.  *
  781.  * NOMANUAL
  782.  *
  783.  * NOTE: INTERNET SPECIFIC.
  784.  */
  785. void ifRouteAdd
  786.     (
  787.     struct sockaddr * pAddr,
  788.     int refCnt,
  789.     int subnetsCnt,
  790.     BOOL internalFlag,
  791.     u_long subnetMask
  792.     )
  793.     {
  794.     register struct interface *ifp = 0;
  795.     register struct interface *pPPPIfp = 0;
  796.     register struct interface *pNetIfp = 0;
  797.     register struct interface *pSubnetIfp = 0;
  798.     register struct interface *pIfMax;
  799.     register int af = pAddr->sa_family;
  800.     register u_long dstaddr;
  801.     int addLocalRoute = 0;
  802.     int addDstRoute = 0;
  803.     int state; 
  804.     struct rt_entry *rt;
  805.     if (af >= AF_MAX) 
  806.         return;
  807.     pIfMax = 0;
  808.     dstaddr = ntohl (((struct sockaddr_in *)pAddr)->sin_addr.s_addr);
  809.     /*
  810.      * If we need to add an "internal" route (a classful route for a
  811.      * subnetted network - to be used for border gateway filtering)
  812.      * Look for a list of subnetted interfaces that are on the same network
  813.      * as the current route, and add a class based network route through
  814.      * the interface that has the least metric
  815.      */
  816.     if (internalFlag)
  817.         {
  818.         for (ifp = ripIfNet; ifp; ifp = ifp->int_next) 
  819.             {
  820.             if (ifp->int_flags & IFF_REMOTE || !(ifp->int_flags & IFF_UP) || 
  821.                 ifp->int_flags & IFF_POINTOPOINT)
  822.                 continue;
  823.             if (af != ifp->int_addr.sa_family) 
  824.                 continue;
  825.             if ((ifp->int_netmask != ifp->int_subnetmask) && 
  826.                 (dstaddr == ifp->int_net)) 
  827.                 {
  828.                 if (!pSubnetIfp || pSubnetIfp->int_metric > ifp->int_metric)
  829.                     pSubnetIfp = ifp;
  830.                 if (routedDebug > 2)
  831.                     {
  832.                     logMsg ("internalFlag: found ifp = %xn", (int)pSubnetIfp, 0,
  833.                             0, 0, 0, 0);
  834.                     _ripIfShow (pSubnetIfp);
  835.                     }
  836.                 }
  837.             }
  838.         ifp = pSubnetIfp;
  839.         }
  840.     else
  841.         {
  842.         for (ifp = ripIfNet; ifp; ifp = ifp->int_next) 
  843.             {
  844.             if (ifp->int_flags & IFF_REMOTE || !(ifp->int_flags & IFF_UP))
  845.                 continue;
  846.             if (af != ifp->int_addr.sa_family) 
  847.                 continue;
  848.             /* See if the address matches any end of the PPP links */
  849.             if ((ifp->int_flags & IFF_POINTOPOINT)) 
  850.                 {
  851.                 if (same (&ifp->int_dstaddr, pAddr) || 
  852.                     same (&ifp->int_addr, pAddr)) 
  853.                     {
  854.                     if (!pPPPIfp || pPPPIfp->int_metric > ifp->int_metric)
  855.                         pPPPIfp = ifp; 
  856.                     if (routedDebug > 2)
  857.                         {
  858.                         logMsg ("PPP: found ifp = %xn", (int)pPPPIfp, 0,
  859.                                 0, 0, 0, 0);
  860.                         _ripIfShow (pPPPIfp);
  861.                         }
  862.                     }
  863.                 }
  864.             /*
  865.              * It would seem that the two else if cases below could be
  866.              * replaced with a single if (dstaddr == ifp->int_subnet)
  867.              * but the above case will not be able to distinguish between
  868.              * 164.10.0.0/16 and 164.10.0.0/24. Hence we need to
  869.              * compare separately
  870.              */
  871.             else if ((ifp->int_netmask == ifp->int_subnetmask) &&
  872.                      (dstaddr == ifp->int_net)) 
  873.                 {
  874.                 if (!pNetIfp || pNetIfp->int_metric > ifp->int_metric)
  875.                     pNetIfp = ifp;
  876.                 if (routedDebug > 2)
  877.                     {
  878.                     logMsg ("NET: found ifp = %xn", (int)pNetIfp, 0,
  879.                             0, 0, 0, 0);
  880.                     _ripIfShow (pNetIfp);
  881.                     }
  882.                 }
  883.             else if ((ifp->int_netmask != ifp->int_subnetmask) &&
  884.                      (dstaddr == ifp->int_subnet)) 
  885.                 {
  886.                 if (!pSubnetIfp || pSubnetIfp->int_metric > ifp->int_metric)
  887.                     pSubnetIfp = ifp;
  888.                 if (routedDebug > 2)
  889.                     {
  890.                     logMsg ("SUBNET: found ifp = %xn", (int)pSubnetIfp, 0,
  891.                             0, 0, 0, 0);
  892.                     _ripIfShow (pSubnetIfp);
  893.                     }
  894.                 }
  895.             }
  896.         ifp = pPPPIfp ? pPPPIfp : (pNetIfp ? pNetIfp : pSubnetIfp);
  897.         if (ifp == NULL)
  898.             {
  899.             /*
  900.              * We did not find any interface that matched the address of the
  901.              * route being deleted. This must be the following case:
  902.              *   164.10.0.0/16  -->  164.10.1.1   (being deleted)
  903.              *   is referenced by the following PPP interface
  904.              *      src = 164.10.22.1, dst=164.10.22.2
  905.              * So now, search for PPP interfaces that lie on the same
  906.              * network as the route being deleted. We do that by applying the
  907.              * netmask of the route to the PPP interface address. 
  908.              * If we have both ends of the link on the same network, then we
  909.              * will have to add two routes:
  910.              *   one for the remote end.
  911.              *   one for the local end
  912.              */
  913.             pAddr = NULL;
  914.             for (ifp = ripIfNet; ifp; ifp = ifp->int_next) 
  915.                 {
  916.                 if (ifp->int_flags & IFF_REMOTE || !(ifp->int_flags & IFF_UP))
  917.                     continue;
  918.                 if (af != ifp->int_addr.sa_family) 
  919.                     continue;
  920.                 if ((ifp->int_flags & IFF_POINTOPOINT)) 
  921.                     {
  922.                     if ((ntohl(((struct sockaddr_in *)
  923.                                 &ifp->int_dstaddr)->sin_addr.s_addr) & 
  924.                          subnetMask) == dstaddr)
  925.                         {
  926.                         addDstRoute = 1;
  927.                         if (routedDebug > 2)
  928.                             {
  929.                             logMsg ("Add PPP dest route for %x.n", (int)ifp, 0,
  930.                                     0, 0, 0, 0);
  931.                             _ripIfShow (ifp);
  932.                             }
  933.                         if (!pPPPIfp || pPPPIfp->int_metric > ifp->int_metric)
  934.                             pPPPIfp = ifp; 
  935.                         pAddr = &ifp->int_dstaddr;
  936.                         }
  937.                     if ((ntohl(((struct sockaddr_in *)
  938.                                 &ifp->int_addr)->sin_addr.s_addr) & 
  939.                          subnetMask) == dstaddr)
  940.                         {
  941.                         addLocalRoute = 1;
  942.                         if (routedDebug > 2)
  943.                             {
  944.                             logMsg ("Add PPP local route for %x.n", (int)ifp, 0,
  945.                                     0, 0, 0, 0);
  946.                             _ripIfShow (ifp);
  947.                             }
  948.                         if (!pPPPIfp || pPPPIfp->int_metric > ifp->int_metric)
  949.                             pPPPIfp = ifp; 
  950.                         break;
  951.                         }
  952.                     }
  953.                 }
  954.             ifp = pPPPIfp;
  955.             }
  956.         }
  957.     if (ifp == NULL)
  958.         {
  959.         if (routedDebug > 2)
  960.             logMsg ("No ifp foundn", 0, 0, 0, 0, 0, 0);
  961.         return;
  962.         }
  963.     /*
  964.      * If both the local and remote end were on the same network, we had
  965.      * incremented the refcount by 2 when we added the route. So account
  966.      * for that. rtdelete() had already decremented the refcount by 1
  967.      */
  968.     if (addDstRoute && addLocalRoute)
  969.         refCnt--;
  970.     /*
  971.      * pAddr will be set to NULL if we just need to add a route to the
  972.      * local end of the PPP link. In all other cases, add the route
  973.      */
  974.     if (pAddr)
  975.         {
  976.         state = ifp->int_flags &
  977.             (IFF_INTERFACE | IFF_PASSIVE | IFF_REMOTE | IFF_SUBNET);
  978.         if (ifp->int_flags & IFF_POINTOPOINT && 
  979.             (same (&ifp->int_dstaddr, pAddr)) &&
  980.             (ntohl(((struct sockaddr_in *)&ifp->int_dstaddr)->sin_addr.s_addr) 
  981.              & ifp->int_netmask) != ifp->int_net)
  982.                 state &= ~RTS_SUBNET;
  983.         if (internalFlag)
  984.             rt = rtadd(pAddr, &ifp->int_addr, ifp->int_metric,
  985.                        ((ifp->int_flags & (IFF_INTERFACE|IFF_REMOTE)) |
  986.                         RTS_PASSIVE | RTS_INTERNAL | RTS_SUBNET), 
  987.                        NULL, M2_ipRouteProto_rip, 0, 0, ifp);
  988.         else
  989.             rt = rtadd(pAddr, &ifp->int_addr, ifp->int_metric, state, NULL, 
  990.                        M2_ipRouteProto_rip, 0, 0, ifp);
  991.         /*
  992.          * Now set the reference counts.
  993.          */
  994.         if (rt)
  995.             {
  996.             rt->rt_refcnt = refCnt;
  997.             rt->rt_subnets_cnt = subnetsCnt;
  998.             }
  999.         }
  1000.     /* Now add route to the local end of PPP link, if needed */
  1001.     if (addLocalRoute) 
  1002.         add_ptopt_localrt(ifp, refCnt);
  1003.         
  1004.     }