[BACK]Return to route.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / net

Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.

Diff for /src/sys/net/route.c between version 1.66 and 1.66.2.4

version 1.66, 2005/05/29 21:22:53 version 1.66.2.4, 2007/09/03 14:42:24
Line 97 
Line 97 
  *      @(#)route.c     8.3 (Berkeley) 1/9/95   *      @(#)route.c     8.3 (Berkeley) 1/9/95
  */   */
   
   #include "opt_route.h"
   
 #include <sys/cdefs.h>  #include <sys/cdefs.h>
 __KERNEL_RCSID(0, "$NetBSD$");  __KERNEL_RCSID(0, "$NetBSD$");
   
 #include "opt_ns.h"  
   
 #include <sys/param.h>  #include <sys/param.h>
   #include <sys/sysctl.h>
 #include <sys/systm.h>  #include <sys/systm.h>
 #include <sys/callout.h>  #include <sys/callout.h>
 #include <sys/proc.h>  #include <sys/proc.h>
Line 122  __KERNEL_RCSID(0, "$NetBSD$");
Line 123  __KERNEL_RCSID(0, "$NetBSD$");
 #include <netinet/in.h>  #include <netinet/in.h>
 #include <netinet/in_var.h>  #include <netinet/in_var.h>
   
 #ifdef NS  #ifdef RTFLUSH_DEBUG
 #include <netns/ns.h>  #define rtcache_debug() __predict_false(_rtcache_debug)
 #endif  #else /* RTFLUSH_DEBUG */
   #define rtcache_debug() 0
 #define SA(p) ((struct sockaddr *)(p))  #endif /* RTFLUSH_DEBUG */
   
 struct  route_cb route_cb;  struct  route_cb route_cb;
 struct  rtstat  rtstat;  struct  rtstat  rtstat;
Line 135  struct radix_node_head *rt_tables[AF_MAX
Line 136  struct radix_node_head *rt_tables[AF_MAX
 int     rttrash;                /* routes not in table but not freed */  int     rttrash;                /* routes not in table but not freed */
 struct  sockaddr wildcard;      /* zero valued cookie for wildcard searches */  struct  sockaddr wildcard;      /* zero valued cookie for wildcard searches */
   
 POOL_INIT(rtentry_pool, sizeof(struct rtentry), 0, 0, 0, "rtentpl", NULL);  POOL_INIT(rtentry_pool, sizeof(struct rtentry), 0, 0, 0, "rtentpl", NULL,
 POOL_INIT(rttimer_pool, sizeof(struct rttimer), 0, 0, 0, "rttmrpl", NULL);      IPL_SOFTNET);
   POOL_INIT(rttimer_pool, sizeof(struct rttimer), 0, 0, 0, "rttmrpl", NULL,
       IPL_SOFTNET);
   
 struct callout rt_timer_ch; /* callout for rt_timer_timer() */  struct callout rt_timer_ch; /* callout for rt_timer_timer() */
   
   #ifdef RTFLUSH_DEBUG
   static int _rtcache_debug = 0;
   #endif /* RTFLUSH_DEBUG */
   
 static int rtdeletemsg(struct rtentry *);  static int rtdeletemsg(struct rtentry *);
 static int rtflushclone1(struct radix_node *, void *);  static int rtflushclone1(struct rtentry *, void *);
 static void rtflushclone(struct radix_node_head *, struct rtentry *);  static void rtflushclone(sa_family_t family, struct rtentry *);
   
   #ifdef RTFLUSH_DEBUG
   SYSCTL_SETUP(sysctl_net_rtcache_setup, "sysctl net.rtcache.debug setup")
   {
           const struct sysctlnode *rnode;
   
           /* XXX do not duplicate */
           if (sysctl_createv(clog, 0, NULL, &rnode, CTLFLAG_PERMANENT,
               CTLTYPE_NODE, "net", NULL, NULL, 0, NULL, 0, CTL_NET, CTL_EOL) != 0)
                   return;
           if (sysctl_createv(clog, 0, &rnode, &rnode, CTLFLAG_PERMANENT,
               CTLTYPE_NODE,
               "rtcache", SYSCTL_DESCR("Route cache related settings"),
               NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL) != 0)
                   return;
           if (sysctl_createv(clog, 0, &rnode, &rnode,
               CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT,
               "debug", SYSCTL_DESCR("Debug route caches"),
               NULL, 0, &_rtcache_debug, 0, CTL_CREATE, CTL_EOL) != 0)
                   return;
   }
   #endif /* RTFLUSH_DEBUG */
   
   struct ifaddr *
   rt_get_ifa(struct rtentry *rt)
   {
           struct ifaddr *ifa;
   
           if ((ifa = rt->rt_ifa) == NULL)
                   return ifa;
           else if (ifa->ifa_getifa == NULL)
                   return ifa;
   #if 0
           else if (ifa->ifa_seqno != NULL && *ifa->ifa_seqno == rt->rt_ifa_seqno)
                   return ifa;
   #endif
           else {
                   ifa = (*ifa->ifa_getifa)(ifa, rt_getkey(rt));
                   rt_replace_ifa(rt, ifa);
                   return ifa;
           }
   }
   
   static void
   rt_set_ifa1(struct rtentry *rt, struct ifaddr *ifa)
   {
           rt->rt_ifa = ifa;
           if (ifa->ifa_seqno != NULL)
                   rt->rt_ifa_seqno = *ifa->ifa_seqno;
   }
   
   void
   rt_replace_ifa(struct rtentry *rt, struct ifaddr *ifa)
   {
           IFAREF(ifa);
           IFAFREE(rt->rt_ifa);
           rt_set_ifa1(rt, ifa);
   }
   
   static void
   rt_set_ifa(struct rtentry *rt, struct ifaddr *ifa)
   {
           IFAREF(ifa);
           rt_set_ifa1(rt, ifa);
   }
   
 void  void
 rtable_init(void **table)  rtable_init(void **table)
Line 162  route_init(void)
Line 234  route_init(void)
         rtable_init((void **)rt_tables);          rtable_init((void **)rt_tables);
 }  }
   
   void
   rtflushall(int family)
   {
           int s;
           struct domain *dom;
           struct route *ro;
   
           if (rtcache_debug())
                   printf("%s: enter\n", __func__);
   
           if ((dom = pffinddomain(family)) == NULL)
                   return;
   
           s = splnet();
           while ((ro = LIST_FIRST(&dom->dom_rtcache)) != NULL) {
                   KASSERT(ro->ro_rt != NULL);
                   rtcache_clear(ro);
           }
           splx(s);
   }
   
   void
   rtflush(struct route *ro)
   {
           int s = splnet();
           KASSERT(ro->ro_rt != NULL);
           KASSERT(rtcache_getdst(ro) != NULL);
   
           RTFREE(ro->ro_rt);
           ro->ro_rt = NULL;
   
           LIST_REMOVE(ro, ro_rtcache_next);
           splx(s);
   
   #if 0
           if (rtcache_debug()) {
                   printf("%s: flushing %s\n", __func__,
                       inet_ntoa((satocsin(rtcache_getdst(ro)))->sin_addr));
           }
   #endif
   }
   
   void
   rtcache(struct route *ro)
   {
           int s;
           struct domain *dom;
   
           KASSERT(ro->ro_rt != NULL);
           KASSERT(rtcache_getdst(ro) != NULL);
   
           if ((dom = pffinddomain(rtcache_getdst(ro)->sa_family)) == NULL)
                   return;
   
           s = splnet();
           LIST_INSERT_HEAD(&dom->dom_rtcache, ro, ro_rtcache_next);
           splx(s);
   }
   
 /*  /*
  * Packet routing routines.   * Packet routing routines.
  */   */
 void  void
 rtalloc(struct route *ro)  rtalloc(struct route *ro)
 {  {
         if (ro->ro_rt && ro->ro_rt->rt_ifp && (ro->ro_rt->rt_flags & RTF_UP))          if (ro->ro_rt != NULL) {
                 return;                          /* XXX */                  if (ro->ro_rt->rt_ifp != NULL &&
         ro->ro_rt = rtalloc1(&ro->ro_dst, 1);                      (ro->ro_rt->rt_flags & RTF_UP) != 0)
                           return;
                   rtflush(ro);
           }
           if (rtcache_getdst(ro) == NULL ||
               (ro->ro_rt = rtalloc1(rtcache_getdst(ro), 1)) == NULL)
                   return;
           rtcache(ro);
 }  }
   
 struct rtentry *  struct rtentry *
Line 179  rtalloc1(const struct sockaddr *dst, int
Line 317  rtalloc1(const struct sockaddr *dst, int
         struct radix_node_head *rnh = rt_tables[dst->sa_family];          struct radix_node_head *rnh = rt_tables[dst->sa_family];
         struct rtentry *rt;          struct rtentry *rt;
         struct radix_node *rn;          struct radix_node *rn;
         struct rtentry *newrt = 0;          struct rtentry *newrt = NULL;
         struct rt_addrinfo info;          struct rt_addrinfo info;
         int  s = splsoftnet(), err = 0, msgtype = RTM_MISS;          int  s = splsoftnet(), err = 0, msgtype = RTM_MISS;
   
Line 187  rtalloc1(const struct sockaddr *dst, int
Line 325  rtalloc1(const struct sockaddr *dst, int
             ((rn->rn_flags & RNF_ROOT) == 0)) {              ((rn->rn_flags & RNF_ROOT) == 0)) {
                 newrt = rt = (struct rtentry *)rn;                  newrt = rt = (struct rtentry *)rn;
                 if (report && (rt->rt_flags & RTF_CLONING)) {                  if (report && (rt->rt_flags & RTF_CLONING)) {
                         err = rtrequest(RTM_RESOLVE, dst, SA(0),                          err = rtrequest(RTM_RESOLVE, dst, NULL, NULL, 0,
                                               SA(0), 0, &newrt);                              &newrt);
                         if (err) {                          if (err) {
                                 newrt = rt;                                  newrt = rt;
                                 rt->rt_refcnt++;                                  rt->rt_refcnt++;
                                 goto miss;                                  goto miss;
                         }                          }
                           KASSERT(newrt != NULL);
                         if ((rt = newrt) && (rt->rt_flags & RTF_XRESOLVE)) {                          if ((rt = newrt) && (rt->rt_flags & RTF_XRESOLVE)) {
                                 msgtype = RTM_RESOLVE;                                  msgtype = RTM_RESOLVE;
                                 goto miss;                                  goto miss;
                         }                          }
                         /* Inform listeners of the new route */                          /* Inform listeners of the new route */
                         memset(&info, 0, sizeof(info));                          memset(&info, 0, sizeof(info));
                         info.rti_info[RTAX_DST] = rt_key(rt);                          info.rti_info[RTAX_DST] = rt_getkey(rt);
                         info.rti_info[RTAX_NETMASK] = rt_mask(rt);                          info.rti_info[RTAX_NETMASK] = rt_mask(rt);
                         info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;                          info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
                         if (rt->rt_ifp != NULL) {                          if (rt->rt_ifp != NULL) {
Line 214  rtalloc1(const struct sockaddr *dst, int
Line 353  rtalloc1(const struct sockaddr *dst, int
         } else {          } else {
                 rtstat.rts_unreach++;                  rtstat.rts_unreach++;
         miss:   if (report) {          miss:   if (report) {
                         memset((caddr_t)&info, 0, sizeof(info));                          memset((void *)&info, 0, sizeof(info));
                         info.rti_info[RTAX_DST] = dst;                          info.rti_info[RTAX_DST] = dst;
                         rt_missmsg(msgtype, &info, 0, err);                          rt_missmsg(msgtype, &info, 0, err);
                 }                  }
         }          }
         splx(s);          splx(s);
         return (newrt);          return newrt;
 }  }
   
 void  void
Line 228  rtfree(struct rtentry *rt)
Line 367  rtfree(struct rtentry *rt)
 {  {
         struct ifaddr *ifa;          struct ifaddr *ifa;
   
         if (rt == 0)          if (rt == NULL)
                 panic("rtfree");                  panic("rtfree");
         rt->rt_refcnt--;          rt->rt_refcnt--;
         if (rt->rt_refcnt <= 0 && (rt->rt_flags & RTF_UP) == 0) {          if (rt->rt_refcnt <= 0 && (rt->rt_flags & RTF_UP) == 0) {
Line 241  rtfree(struct rtentry *rt)
Line 380  rtfree(struct rtentry *rt)
                 }                  }
                 rt_timer_remove_all(rt, 0);                  rt_timer_remove_all(rt, 0);
                 ifa = rt->rt_ifa;                  ifa = rt->rt_ifa;
                   rt->rt_ifa = NULL;
                 IFAFREE(ifa);                  IFAFREE(ifa);
                 Free(rt_key(rt));                  rt->rt_ifp = NULL;
                   rt_destroy(rt);
                 pool_put(&rtentry_pool, rt);                  pool_put(&rtentry_pool, rt);
         }          }
 }  }
Line 263  ifafree(struct ifaddr *ifa)
Line 404  ifafree(struct ifaddr *ifa)
         free(ifa, M_IFADDR);          free(ifa, M_IFADDR);
 }  }
   
   static inline int
   equal(const struct sockaddr *sa1, const struct sockaddr *sa2)
   {
           return sockaddr_cmp(sa1, sa2) == 0;
   }
   
 /*  /*
  * Force a routing table entry to the specified   * Force a routing table entry to the specified
  * destination to go through the given gateway.   * destination to go through the given gateway.
Line 278  rtredirect(const struct sockaddr *dst, c
Line 425  rtredirect(const struct sockaddr *dst, c
 {  {
         struct rtentry *rt;          struct rtentry *rt;
         int error = 0;          int error = 0;
         u_quad_t *stat = 0;          u_quad_t *stat = NULL;
         struct rt_addrinfo info;          struct rt_addrinfo info;
         struct ifaddr *ifa;          struct ifaddr *ifa;
   
         /* verify the gateway is directly reachable */          /* verify the gateway is directly reachable */
         if ((ifa = ifa_ifwithnet(gateway)) == 0) {          if ((ifa = ifa_ifwithnet(gateway)) == NULL) {
                 error = ENETUNREACH;                  error = ENETUNREACH;
                 goto out;                  goto out;
         }          }
Line 294  rtredirect(const struct sockaddr *dst, c
Line 441  rtredirect(const struct sockaddr *dst, c
          * we have a routing loop, perhaps as a result of an interface           * we have a routing loop, perhaps as a result of an interface
          * going down recently.           * going down recently.
          */           */
 #define equal(a1, a2) \  
         ((a1)->sa_len == (a2)->sa_len && \  
          memcmp((a1), (a2), (a1)->sa_len) == 0)  
         if (!(flags & RTF_DONE) && rt &&          if (!(flags & RTF_DONE) && rt &&
              (!equal(src, rt->rt_gateway) || rt->rt_ifa != ifa))               (!equal(src, rt->rt_gateway) || rt->rt_ifa != ifa))
                 error = EINVAL;                  error = EINVAL;
Line 310  rtredirect(const struct sockaddr *dst, c
Line 454  rtredirect(const struct sockaddr *dst, c
          * which use routing redirects generated by smart gateways           * which use routing redirects generated by smart gateways
          * to dynamically build the routing tables.           * to dynamically build the routing tables.
          */           */
         if ((rt == 0) || (rt_mask(rt) && rt_mask(rt)->sa_len < 2))          if (rt == NULL || (rt_mask(rt) && rt_mask(rt)->sa_len < 2))
                 goto create;                  goto create;
         /*          /*
          * Don't listen to the redirect if it's           * Don't listen to the redirect if it's
Line 323  rtredirect(const struct sockaddr *dst, c
Line 467  rtredirect(const struct sockaddr *dst, c
                          * Create new route, rather than smashing route to net.                           * Create new route, rather than smashing route to net.
                          */                           */
                 create:                  create:
                         if (rt)                          if (rt != NULL)
                                 rtfree(rt);                                  rtfree(rt);
                         flags |=  RTF_GATEWAY | RTF_DYNAMIC;                          flags |=  RTF_GATEWAY | RTF_DYNAMIC;
                         info.rti_info[RTAX_DST] = dst;                          info.rti_info[RTAX_DST] = dst;
Line 344  rtredirect(const struct sockaddr *dst, c
Line 488  rtredirect(const struct sockaddr *dst, c
                         rt->rt_flags |= RTF_MODIFIED;                          rt->rt_flags |= RTF_MODIFIED;
                         flags |= RTF_MODIFIED;                          flags |= RTF_MODIFIED;
                         stat = &rtstat.rts_newgateway;                          stat = &rtstat.rts_newgateway;
                         rt_setgate(rt, rt_key(rt), gateway);                          rt_setgate(rt, gateway);
                 }                  }
         } else          } else
                 error = EHOSTUNREACH;                  error = EHOSTUNREACH;
 done:  done:
         if (rt) {          if (rt) {
                 if (rtp && !error)                  if (rtp != NULL && !error)
                         *rtp = rt;                          *rtp = rt;
                 else                  else
                         rtfree(rt);                          rtfree(rt);
Line 360  out:
Line 504  out:
                 rtstat.rts_badredirect++;                  rtstat.rts_badredirect++;
         else if (stat != NULL)          else if (stat != NULL)
                 (*stat)++;                  (*stat)++;
         memset((caddr_t)&info, 0, sizeof(info));          memset(&info, 0, sizeof(info));
         info.rti_info[RTAX_DST] = dst;          info.rti_info[RTAX_DST] = dst;
         info.rti_info[RTAX_GATEWAY] = gateway;          info.rti_info[RTAX_GATEWAY] = gateway;
         info.rti_info[RTAX_NETMASK] = netmask;          info.rti_info[RTAX_NETMASK] = netmask;
Line 382  rtdeletemsg(struct rtentry *rt)
Line 526  rtdeletemsg(struct rtentry *rt)
          * deleted.  That will allow the information being reported to           * deleted.  That will allow the information being reported to
          * be accurate (and consistent with route_output()).           * be accurate (and consistent with route_output()).
          */           */
         memset((caddr_t)&info, 0, sizeof(info));          memset(&info, 0, sizeof(info));
         info.rti_info[RTAX_DST] = rt_key(rt);          info.rti_info[RTAX_DST] = rt_getkey(rt);
         info.rti_info[RTAX_NETMASK] = rt_mask(rt);          info.rti_info[RTAX_NETMASK] = rt_mask(rt);
         info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;          info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
         info.rti_flags = rt->rt_flags;          info.rti_flags = rt->rt_flags;
Line 396  rtdeletemsg(struct rtentry *rt)
Line 540  rtdeletemsg(struct rtentry *rt)
                 rt->rt_refcnt++;                  rt->rt_refcnt++;
                 rtfree(rt);                  rtfree(rt);
         }          }
         return (error);          return error;
 }  }
   
 static int  static int
 rtflushclone1(struct radix_node *rn, void *arg)  rtflushclone1(struct rtentry *rt, void *arg)
 {  {
         struct rtentry *rt, *parent;          struct rtentry *parent;
   
         rt = (struct rtentry *)rn;  
         parent = (struct rtentry *)arg;          parent = (struct rtentry *)arg;
         if ((rt->rt_flags & RTF_CLONED) != 0 && rt->rt_parent == parent)          if ((rt->rt_flags & RTF_CLONED) != 0 && rt->rt_parent == parent)
                 rtdeletemsg(rt);                  rtdeletemsg(rt);
Line 412  rtflushclone1(struct radix_node *rn, voi
Line 555  rtflushclone1(struct radix_node *rn, voi
 }  }
   
 static void  static void
 rtflushclone(struct radix_node_head *rnh, struct rtentry *parent)  rtflushclone(sa_family_t family, struct rtentry *parent)
 {  {
   
 #ifdef DIAGNOSTIC  #ifdef DIAGNOSTIC
         if (!parent || (parent->rt_flags & RTF_CLONING) == 0)          if (!parent || (parent->rt_flags & RTF_CLONING) == 0)
                 panic("rtflushclone: called with a non-cloning route");                  panic("rtflushclone: called with a non-cloning route");
         if (!rnh->rnh_walktree)  
                 panic("rtflushclone: no rnh_walktree");  
 #endif  #endif
         rnh->rnh_walktree(rnh, rtflushclone1, (void *)parent);          rt_walktree(family, rtflushclone1, (void *)parent);
 }  }
   
 /*  /*
  * Routing table ioctl interface.   * Routing table ioctl interface.
  */   */
 int  int
 rtioctl(u_long req, caddr_t data, struct proc *p)  rtioctl(u_long req, void *data, struct lwp *l)
 {  {
         return (EOPNOTSUPP);          return EOPNOTSUPP;
 }  }
   
 struct ifaddr *  struct ifaddr *
Line 446  ifa_ifwithroute(int flags, const struct 
Line 587  ifa_ifwithroute(int flags, const struct 
                  * as our clue to the interface.  Otherwise                   * as our clue to the interface.  Otherwise
                  * we can use the local address.                   * we can use the local address.
                  */                   */
                 ifa = 0;                  ifa = NULL;
                 if (flags & RTF_HOST)                  if (flags & RTF_HOST)
                         ifa = ifa_ifwithdstaddr(dst);                          ifa = ifa_ifwithdstaddr(dst);
                 if (ifa == 0)                  if (ifa == NULL)
                         ifa = ifa_ifwithaddr(gateway);                          ifa = ifa_ifwithaddr(gateway);
         } else {          } else {
                 /*                  /*
Line 459  ifa_ifwithroute(int flags, const struct 
Line 600  ifa_ifwithroute(int flags, const struct 
                  */                   */
                 ifa = ifa_ifwithdstaddr(gateway);                  ifa = ifa_ifwithdstaddr(gateway);
         }          }
         if (ifa == 0)          if (ifa == NULL)
                 ifa = ifa_ifwithnet(gateway);                  ifa = ifa_ifwithnet(gateway);
         if (ifa == 0) {          if (ifa == NULL) {
                 struct rtentry *rt = rtalloc1(dst, 0);                  struct rtentry *rt = rtalloc1(dst, 0);
                 if (rt == 0)                  if (rt == NULL)
                         return (0);                          return NULL;
                 rt->rt_refcnt--;                  rt->rt_refcnt--;
                 if ((ifa = rt->rt_ifa) == 0)                  if ((ifa = rt->rt_ifa) == NULL)
                         return (0);                          return NULL;
         }          }
         if (ifa->ifa_addr->sa_family != dst->sa_family) {          if (ifa->ifa_addr->sa_family != dst->sa_family) {
                 struct ifaddr *oifa = ifa;                  struct ifaddr *oifa = ifa;
Line 475  ifa_ifwithroute(int flags, const struct 
Line 616  ifa_ifwithroute(int flags, const struct 
                 if (ifa == 0)                  if (ifa == 0)
                         ifa = oifa;                          ifa = oifa;
         }          }
         return (ifa);          return ifa;
 }  }
   
 #define ROUNDUP(a) (a>0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))  #define ROUNDUP(a) (a>0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
Line 494  rtrequest(int req, const struct sockaddr
Line 635  rtrequest(int req, const struct sockaddr
         return rtrequest1(req, &info, ret_nrt);          return rtrequest1(req, &info, ret_nrt);
 }  }
   
 /*  
  * These (questionable) definitions of apparent local variables apply  
  * to the next function.  XXXXXX!!!  
  */  
 #define dst     info->rti_info[RTAX_DST]  
 #define gateway info->rti_info[RTAX_GATEWAY]  
 #define netmask info->rti_info[RTAX_NETMASK]  
 #define ifaaddr info->rti_info[RTAX_IFA]  
 #define ifpaddr info->rti_info[RTAX_IFP]  
 #define flags   info->rti_flags  
   
 int  int
 rt_getifa(struct rt_addrinfo *info)  rt_getifa(struct rt_addrinfo *info)
 {  {
         struct ifaddr *ifa;          struct ifaddr *ifa;
         int error = 0;          const struct sockaddr *dst = info->rti_info[RTAX_DST];
           const struct sockaddr *gateway = info->rti_info[RTAX_GATEWAY];
           const struct sockaddr *ifaaddr = info->rti_info[RTAX_IFA];
           const struct sockaddr *ifpaddr = info->rti_info[RTAX_IFP];
           int flags = info->rti_flags;
   
         /*          /*
          * ifp may be specified by sockaddr_dl when protocol address           * ifp may be specified by sockaddr_dl when protocol address
Line 533  rt_getifa(struct rt_addrinfo *info)
Line 667  rt_getifa(struct rt_addrinfo *info)
                 else if (sa != NULL)                  else if (sa != NULL)
                         info->rti_ifa = ifa_ifwithroute(flags, sa, sa);                          info->rti_ifa = ifa_ifwithroute(flags, sa, sa);
         }          }
         if ((ifa = info->rti_ifa) != NULL) {          if ((ifa = info->rti_ifa) == NULL)
                 if (info->rti_ifp == NULL)                  return ENETUNREACH;
                         info->rti_ifp = ifa->ifa_ifp;          if (ifa->ifa_getifa != NULL)
         } else                  info->rti_ifa = ifa = (*ifa->ifa_getifa)(ifa, dst);
                 error = ENETUNREACH;          if (info->rti_ifp == NULL)
         return (error);                  info->rti_ifp = ifa->ifa_ifp;
           return 0;
 }  }
   
 int  int
Line 550  rtrequest1(int req, struct rt_addrinfo *
Line 685  rtrequest1(int req, struct rt_addrinfo *
         struct radix_node *rn;          struct radix_node *rn;
         struct radix_node_head *rnh;          struct radix_node_head *rnh;
         struct ifaddr *ifa;          struct ifaddr *ifa;
         struct sockaddr *ndst;          struct sockaddr_storage maskeddst;
         struct sockaddr_storage deldst;          const struct sockaddr *dst = info->rti_info[RTAX_DST];
           const struct sockaddr *gateway = info->rti_info[RTAX_GATEWAY];
           const struct sockaddr *netmask = info->rti_info[RTAX_NETMASK];
           int flags = info->rti_flags;
 #define senderr(x) { error = x ; goto bad; }  #define senderr(x) { error = x ; goto bad; }
   
         if ((rnh = rt_tables[dst->sa_family]) == 0)          if ((rnh = rt_tables[dst->sa_family]) == NULL)
                 senderr(ESRCH);                  senderr(ESRCH);
         if (flags & RTF_HOST)          if (flags & RTF_HOST)
                 netmask = 0;                  netmask = NULL;
         switch (req) {          switch (req) {
         case RTM_DELETE:          case RTM_DELETE:
                 if (netmask) {                  if (netmask) {
                         rt_maskedcopy(dst, (struct sockaddr *)&deldst, netmask);                          rt_maskedcopy(dst, (struct sockaddr *)&maskeddst,
                         dst = (struct sockaddr *)&deldst;                              netmask);
                           dst = (struct sockaddr *)&maskeddst;
                 }                  }
                 if ((rn = rnh->rnh_lookup(dst, netmask, rnh)) == 0)                  if ((rn = rnh->rnh_lookup(dst, netmask, rnh)) == NULL)
                         senderr(ESRCH);                          senderr(ESRCH);
                 rt = (struct rtentry *)rn;                  rt = (struct rtentry *)rn;
                 if ((rt->rt_flags & RTF_CLONING) != 0) {                  if ((rt->rt_flags & RTF_CLONING) != 0) {
                         /* clean up any cloned children */                          /* clean up any cloned children */
                         rtflushclone(rnh, rt);                          rtflushclone(dst->sa_family, rt);
                 }                  }
                 if ((rn = rnh->rnh_deladdr(dst, netmask, rnh)) == 0)                  if ((rn = rnh->rnh_deladdr(dst, netmask, rnh)) == NULL)
                         senderr(ESRCH);                          senderr(ESRCH);
                 if (rn->rn_flags & (RNF_ACTIVE | RNF_ROOT))                  if (rn->rn_flags & (RNF_ACTIVE | RNF_ROOT))
                         panic ("rtrequest delete");                          panic ("rtrequest delete");
                 rt = (struct rtentry *)rn;                  rt = (struct rtentry *)rn;
                 if (rt->rt_gwroute) {                  if (rt->rt_gwroute) {
                         rt = rt->rt_gwroute; RTFREE(rt);                          RTFREE(rt->rt_gwroute);
                         (rt = (struct rtentry *)rn)->rt_gwroute = 0;                          rt->rt_gwroute = NULL;
                 }                  }
                 if (rt->rt_parent) {                  if (rt->rt_parent) {
                         rt->rt_parent->rt_refcnt--;                          rt->rt_parent->rt_refcnt--;
Line 597  rtrequest1(int req, struct rt_addrinfo *
Line 736  rtrequest1(int req, struct rt_addrinfo *
                 break;                  break;
   
         case RTM_RESOLVE:          case RTM_RESOLVE:
                 if (ret_nrt == 0 || (rt = *ret_nrt) == 0)                  if (ret_nrt == NULL || (rt = *ret_nrt) == NULL)
                         senderr(EINVAL);                          senderr(EINVAL);
                 if ((rt->rt_flags & RTF_CLONING) == 0)                  if ((rt->rt_flags & RTF_CLONING) == 0)
                         senderr(EINVAL);                          senderr(EINVAL);
Line 605  rtrequest1(int req, struct rt_addrinfo *
Line 744  rtrequest1(int req, struct rt_addrinfo *
                 flags = rt->rt_flags & ~(RTF_CLONING | RTF_STATIC);                  flags = rt->rt_flags & ~(RTF_CLONING | RTF_STATIC);
                 flags |= RTF_CLONED;                  flags |= RTF_CLONED;
                 gateway = rt->rt_gateway;                  gateway = rt->rt_gateway;
                 if ((netmask = rt->rt_genmask) == 0)                  flags |= RTF_HOST;
                         flags |= RTF_HOST;  
                 goto makeroute;                  goto makeroute;
   
         case RTM_ADD:          case RTM_ADD:
                 if (info->rti_ifa == 0 && (error = rt_getifa(info)))                  if (info->rti_ifa == NULL && (error = rt_getifa(info)))
                         senderr(error);                          senderr(error);
                 ifa = info->rti_ifa;                  ifa = info->rti_ifa;
         makeroute:          makeroute:
                   /* Already at splsoftnet() so pool_get/pool_put are safe */
                 rt = pool_get(&rtentry_pool, PR_NOWAIT);                  rt = pool_get(&rtentry_pool, PR_NOWAIT);
                 if (rt == 0)                  if (rt == NULL)
                         senderr(ENOBUFS);                          senderr(ENOBUFS);
                 Bzero(rt, sizeof(*rt));                  Bzero(rt, sizeof(*rt));
                 rt->rt_flags = RTF_UP | flags;                  rt->rt_flags = RTF_UP | flags;
                 LIST_INIT(&rt->rt_timer);                  LIST_INIT(&rt->rt_timer);
                 if (rt_setgate(rt, dst, gateway)) {                  RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, __LINE__,
                       (void *)rt->_rt_key);
                   if (rt_setkey(rt, dst, M_NOWAIT) == NULL ||
                       rt_setgate(rt, gateway) != 0) {
                         pool_put(&rtentry_pool, rt);                          pool_put(&rtentry_pool, rt);
                         senderr(ENOBUFS);                          senderr(ENOBUFS);
                 }                  }
                 ndst = rt_key(rt);                  RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, __LINE__,
                       (void *)rt->_rt_key);
                 if (netmask) {                  if (netmask) {
                         rt_maskedcopy(dst, ndst, netmask);                          rt_maskedcopy(dst, (struct sockaddr *)&maskeddst,
                 } else                              netmask);
                         Bcopy(dst, ndst, dst->sa_len);                          rt_setkey(rt, (struct sockaddr *)&maskeddst, M_NOWAIT);
                 IFAREF(ifa);                          RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__,
                 rt->rt_ifa = ifa;                              __LINE__, (void *)rt->_rt_key);
                   } else {
                           rt_setkey(rt, dst, M_NOWAIT);
                           RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__,
                               __LINE__, (void *)rt->_rt_key);
                   }
                   rt_set_ifa(rt, ifa);
                   RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__,
                       __LINE__, (void *)rt->_rt_key);
                 rt->rt_ifp = ifa->ifa_ifp;                  rt->rt_ifp = ifa->ifa_ifp;
                 if (req == RTM_RESOLVE) {                  if (req == RTM_RESOLVE) {
                         rt->rt_rmx = (*ret_nrt)->rt_rmx; /* copy metrics */                          rt->rt_rmx = (*ret_nrt)->rt_rmx; /* copy metrics */
                         rt->rt_parent = *ret_nrt;                          rt->rt_parent = *ret_nrt;
                         rt->rt_parent->rt_refcnt++;                          rt->rt_parent->rt_refcnt++;
                 }                  }
                 rn = rnh->rnh_addaddr(ndst, netmask, rnh, rt->rt_nodes);                  RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__,
                 if (rn == NULL && (crt = rtalloc1(ndst, 0)) != NULL) {                      __LINE__, (void *)rt->_rt_key);
                   rn = rnh->rnh_addaddr(rt_getkey(rt), netmask, rnh,
                       rt->rt_nodes);
                   RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__,
                       __LINE__, (void *)rt->_rt_key);
                   if (rn == NULL && (crt = rtalloc1(rt_getkey(rt), 0)) != NULL) {
                         /* overwrite cloned route */                          /* overwrite cloned route */
                         if ((crt->rt_flags & RTF_CLONED) != 0) {                          if ((crt->rt_flags & RTF_CLONED) != 0) {
                                 rtdeletemsg(crt);                                  rtdeletemsg(crt);
                                 rn = rnh->rnh_addaddr(ndst,                                  rn = rnh->rnh_addaddr(rt_getkey(rt),
                                     netmask, rnh, rt->rt_nodes);                                      netmask, rnh, rt->rt_nodes);
                         }                          }
                         RTFREE(crt);                          RTFREE(crt);
                           RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__,
                               __LINE__, (void *)rt->_rt_key);
                 }                  }
                 if (rn == 0) {                  RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__,
                       __LINE__, (void *)rt->_rt_key);
                   if (rn == NULL) {
                         IFAFREE(ifa);                          IFAFREE(ifa);
                         if ((rt->rt_flags & RTF_CLONED) != 0 && rt->rt_parent)                          if ((rt->rt_flags & RTF_CLONED) != 0 && rt->rt_parent)
                                 rtfree(rt->rt_parent);                                  rtfree(rt->rt_parent);
                         if (rt->rt_gwroute)                          if (rt->rt_gwroute)
                                 rtfree(rt->rt_gwroute);                                  rtfree(rt->rt_gwroute);
                         Free(rt_key(rt));                          rt_destroy(rt);
                         pool_put(&rtentry_pool, rt);                          pool_put(&rtentry_pool, rt);
                         senderr(EEXIST);                          senderr(EEXIST);
                 }                  }
                   RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__,
                       __LINE__, (void *)rt->_rt_key);
                 if (ifa->ifa_rtrequest)                  if (ifa->ifa_rtrequest)
                         ifa->ifa_rtrequest(req, rt, info);                          ifa->ifa_rtrequest(req, rt, info);
                   RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__,
                       __LINE__, (void *)rt->_rt_key);
                 if (ret_nrt) {                  if (ret_nrt) {
                         *ret_nrt = rt;                          *ret_nrt = rt;
                         rt->rt_refcnt++;                          rt->rt_refcnt++;
                 }                  }
                 if ((rt->rt_flags & RTF_CLONING) != 0) {                  if ((rt->rt_flags & RTF_CLONING) != 0) {
                         /* clean up any cloned children */                          /* clean up any cloned children */
                         rtflushclone(rnh, rt);                          rtflushclone(dst->sa_family, rt);
                   }
                   rtflushall(dst->sa_family);
                   break;
           case RTM_GET:
                   if (netmask != NULL) {
                           rt_maskedcopy(dst, (struct sockaddr *)&maskeddst,
                               netmask);
                           dst = (struct sockaddr *)&maskeddst;
                   }
                   rn = rnh->rnh_lookup(dst, netmask, rnh);
                   if (rn == NULL || (rn->rn_flags & RNF_ROOT) != 0)
                           senderr(ESRCH);
                   if (ret_nrt != NULL) {
                           rt = (struct rtentry *)rn;
                           *ret_nrt = rt;
                           rt->rt_refcnt++;
                 }                  }
                 break;                  break;
         }          }
 bad:  bad:
         splx(s);          splx(s);
         return (error);          return error;
 }  }
   
 #undef dst  
 #undef gateway  
 #undef netmask  
 #undef ifaaddr  
 #undef ifpaddr  
 #undef flags  
   
 int  int
 rt_setgate( struct rtentry *rt0, const struct sockaddr *dst,  rt_setgate(struct rtentry *rt, const struct sockaddr *gate)
         const struct sockaddr *gate)  
 {  {
         char *new, *old;          KASSERT(rt != rt->rt_gwroute);
         u_int dlen = ROUNDUP(dst->sa_len), glen = ROUNDUP(gate->sa_len);  
         struct rtentry *rt = rt0;          KASSERT(rt->_rt_key != NULL);
           RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__,
         if (rt->rt_gateway == 0 || glen > ROUNDUP(rt->rt_gateway->sa_len)) {              __LINE__, (void *)rt->_rt_key);
                 old = (caddr_t)rt_key(rt);  
                 R_Malloc(new, caddr_t, dlen + glen);  
                 if (new == 0)  
                         return 1;  
                 Bzero(new, dlen + glen);  
                 rt->rt_nodes->rn_key = new;  
         } else {  
                 new = __UNCONST(rt->rt_nodes->rn_key); /*XXXUNCONST*/  
                 old = 0;  
         }  
         Bcopy(gate, (rt->rt_gateway = (struct sockaddr *)(new + dlen)), glen);  
         if (old) {  
                 Bcopy(dst, new, dlen);  
                 Free(old);  
         }  
         if (rt->rt_gwroute) {          if (rt->rt_gwroute) {
                 rt = rt->rt_gwroute; RTFREE(rt);                  RTFREE(rt->rt_gwroute);
                 rt = rt0; rt->rt_gwroute = 0;                  rt->rt_gwroute = NULL;
         }          }
           KASSERT(rt->_rt_key != NULL);
           RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__,
               __LINE__, (void *)rt->_rt_key);
           if (rt->rt_gateway != NULL)
                   sockaddr_free(rt->rt_gateway);
           KASSERT(rt->_rt_key != NULL);
           RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__,
               __LINE__, (void *)rt->_rt_key);
           if ((rt->rt_gateway = sockaddr_dup(gate, M_NOWAIT)) == NULL)
                   return ENOMEM;
           KASSERT(rt->_rt_key != NULL);
           RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__,
               __LINE__, (void *)rt->_rt_key);
   
         if (rt->rt_flags & RTF_GATEWAY) {          if (rt->rt_flags & RTF_GATEWAY) {
                   KASSERT(rt->_rt_key != NULL);
                   RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__,
                       __LINE__, (void *)rt->_rt_key);
                 rt->rt_gwroute = rtalloc1(gate, 1);                  rt->rt_gwroute = rtalloc1(gate, 1);
                 /*                  /*
                  * If we switched gateways, grab the MTU from the new                   * If we switched gateways, grab the MTU from the new
Line 718  rt_setgate( struct rtentry *rt0, const s
Line 893  rt_setgate( struct rtentry *rt0, const s
                  * Note that, if the MTU of gateway is 0, we will reset the                   * Note that, if the MTU of gateway is 0, we will reset the
                  * MTU of the route to run PMTUD again from scratch. XXX                   * MTU of the route to run PMTUD again from scratch. XXX
                  */                   */
                   KASSERT(rt->_rt_key != NULL);
                   RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__,
                       __LINE__, (void *)rt->_rt_key);
                 if (rt->rt_gwroute                  if (rt->rt_gwroute
                     && !(rt->rt_rmx.rmx_locks & RTV_MTU)                      && !(rt->rt_rmx.rmx_locks & RTV_MTU)
                     && rt->rt_rmx.rmx_mtu                      && rt->rt_rmx.rmx_mtu
Line 725  rt_setgate( struct rtentry *rt0, const s
Line 903  rt_setgate( struct rtentry *rt0, const s
                         rt->rt_rmx.rmx_mtu = rt->rt_gwroute->rt_rmx.rmx_mtu;                          rt->rt_rmx.rmx_mtu = rt->rt_gwroute->rt_rmx.rmx_mtu;
                 }                  }
         }          }
           KASSERT(rt->_rt_key != NULL);
           RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__,
               __LINE__, (void *)rt->_rt_key);
         return 0;          return 0;
 }  }
   
Line 732  void
Line 913  void
 rt_maskedcopy(const struct sockaddr *src, struct sockaddr *dst,  rt_maskedcopy(const struct sockaddr *src, struct sockaddr *dst,
         const struct sockaddr *netmask)          const struct sockaddr *netmask)
 {  {
         const u_char *cp1 = (const u_char *)src;          const char *netmaskp = &netmask->sa_data[0],
         u_char *cp2 = (u_char *)dst;                     *srcp = &src->sa_data[0];
         const u_char *cp3 = (const u_char *)netmask;          char *dstp = &dst->sa_data[0];
         u_char *cplim = cp2 + *cp3;          const char *maskend = dstp + MIN(netmask->sa_len, src->sa_len);
         u_char *cplim2 = cp2 + *cp1;          const char *srcend = dstp + src->sa_len;
   
         *cp2++ = *cp1++; *cp2++ = *cp1++; /* copies sa_len & sa_family */          dst->sa_len = src->sa_len;
         cp3 += 2;          dst->sa_family = src->sa_family;
         if (cplim > cplim2)  
                 cplim = cplim2;          while (dstp < maskend)
         while (cp2 < cplim)                  *dstp++ = *srcp++ & *netmaskp++;
                 *cp2++ = *cp1++ & *cp3++;          if (dstp < srcend)
         if (cp2 < cplim2)                  memset(dstp, 0, (size_t)(srcend - dstp));
                 memset(cp2, 0, (unsigned)(cplim2 - cp2));  
 }  }
   
 /*  /*
Line 757  rtinit(struct ifaddr *ifa, int cmd, int 
Line 937  rtinit(struct ifaddr *ifa, int cmd, int 
 {  {
         struct rtentry *rt;          struct rtentry *rt;
         struct sockaddr *dst, *odst;          struct sockaddr *dst, *odst;
         struct sockaddr_storage deldst;          struct sockaddr_storage maskeddst;
         struct rtentry *nrt = 0;          struct rtentry *nrt = NULL;
         int error;          int error;
         struct rt_addrinfo info;          struct rt_addrinfo info;
   
Line 767  rtinit(struct ifaddr *ifa, int cmd, int 
Line 947  rtinit(struct ifaddr *ifa, int cmd, int 
                 if ((flags & RTF_HOST) == 0 && ifa->ifa_netmask) {                  if ((flags & RTF_HOST) == 0 && ifa->ifa_netmask) {
                         /* Delete subnet route for this interface */                          /* Delete subnet route for this interface */
                         odst = dst;                          odst = dst;
                         dst = (struct sockaddr *)&deldst;                          dst = (struct sockaddr *)&maskeddst;
                         rt_maskedcopy(odst, dst, ifa->ifa_netmask);                          rt_maskedcopy(odst, dst, ifa->ifa_netmask);
                 }                  }
                 if ((rt = rtalloc1(dst, 0)) != NULL) {                  if ((rt = rtalloc1(dst, 0)) != NULL) {
                         rt->rt_refcnt--;                          rt->rt_refcnt--;
                         if (rt->rt_ifa != ifa)                          if (rt->rt_ifa != ifa)
                                 return (flags & RTF_HOST ? EHOSTUNREACH                                  return (flags & RTF_HOST) ? EHOSTUNREACH
                                                         : ENETUNREACH);                                                          : ENETUNREACH;
                 }                  }
         }          }
         memset(&info, 0, sizeof(info));          memset(&info, 0, sizeof(info));
Line 804  rtinit(struct ifaddr *ifa, int cmd, int 
Line 984  rtinit(struct ifaddr *ifa, int cmd, int 
                                 rt->rt_ifa);                                  rt->rt_ifa);
                         if (rt->rt_ifa->ifa_rtrequest)                          if (rt->rt_ifa->ifa_rtrequest)
                                 rt->rt_ifa->ifa_rtrequest(RTM_DELETE, rt, NULL);                                  rt->rt_ifa->ifa_rtrequest(RTM_DELETE, rt, NULL);
                         IFAFREE(rt->rt_ifa);                          rt_replace_ifa(rt, ifa);
                         rt->rt_ifa = ifa;  
                         rt->rt_ifp = ifa->ifa_ifp;                          rt->rt_ifp = ifa->ifa_ifp;
                         IFAREF(ifa);  
                         if (ifa->ifa_rtrequest)                          if (ifa->ifa_rtrequest)
                                 ifa->ifa_rtrequest(RTM_ADD, rt, NULL);                                  ifa->ifa_rtrequest(RTM_ADD, rt, NULL);
                 }                  }
                 rt_newaddrmsg(cmd, ifa, error, nrt);                  rt_newaddrmsg(cmd, ifa, error, nrt);
         }          }
         return (error);          return error;
 }  }
   
 /*  /*
Line 833  static int rt_init_done = 0;
Line 1011  static int rt_init_done = 0;
                         (*r->rtt_func)(r->rtt_rt, r);                   \                          (*r->rtt_func)(r->rtt_rt, r);                   \
                 } else {                                                \                  } else {                                                \
                         rtrequest((int) RTM_DELETE,                     \                          rtrequest((int) RTM_DELETE,                     \
                                   (struct sockaddr *)rt_key(r->rtt_rt), \                                    rt_getkey(r->rtt_rt),                 \
                                   0, 0, 0, 0);                          \                                    0, 0, 0, 0);                          \
                 }                                                       \                  }                                                       \
         } while (/*CONSTCOND*/0)          } while (/*CONSTCOND*/0)
Line 851  rt_timer_init(void)
Line 1029  rt_timer_init(void)
         assert(rt_init_done == 0);          assert(rt_init_done == 0);
   
         LIST_INIT(&rttimer_queue_head);          LIST_INIT(&rttimer_queue_head);
         callout_init(&rt_timer_ch);          callout_init(&rt_timer_ch, 0);
         callout_reset(&rt_timer_ch, hz, rt_timer_timer, NULL);          callout_reset(&rt_timer_ch, hz, rt_timer_timer, NULL);
         rt_init_done = 1;          rt_init_done = 1;
 }  }
Line 866  rt_timer_queue_create(u_int timeout)
Line 1044  rt_timer_queue_create(u_int timeout)
   
         R_Malloc(rtq, struct rttimer_queue *, sizeof *rtq);          R_Malloc(rtq, struct rttimer_queue *, sizeof *rtq);
         if (rtq == NULL)          if (rtq == NULL)
                 return (NULL);                  return NULL;
         Bzero(rtq, sizeof *rtq);          Bzero(rtq, sizeof *rtq);
   
         rtq->rtq_timeout = timeout;          rtq->rtq_timeout = timeout;
Line 874  rt_timer_queue_create(u_int timeout)
Line 1052  rt_timer_queue_create(u_int timeout)
         TAILQ_INIT(&rtq->rtq_head);          TAILQ_INIT(&rtq->rtq_head);
         LIST_INSERT_HEAD(&rttimer_queue_head, rtq, rtq_link);          LIST_INSERT_HEAD(&rttimer_queue_head, rtq, rtq_link);
   
         return (rtq);          return rtq;
 }  }
   
 void  void
Line 894  rt_timer_queue_remove_all(struct rttimer
Line 1072  rt_timer_queue_remove_all(struct rttimer
                 TAILQ_REMOVE(&rtq->rtq_head, r, rtt_next);                  TAILQ_REMOVE(&rtq->rtq_head, r, rtt_next);
                 if (destroy)                  if (destroy)
                         RTTIMER_CALLOUT(r);                          RTTIMER_CALLOUT(r);
                   /* we are already at splsoftnet */
                 pool_put(&rttimer_pool, r);                  pool_put(&rttimer_pool, r);
                 if (rtq->rtq_count > 0)                  if (rtq->rtq_count > 0)
                         rtq->rtq_count--;                          rtq->rtq_count--;
Line 936  rt_timer_remove_all(struct rtentry *rt, 
Line 1115  rt_timer_remove_all(struct rtentry *rt, 
                         r->rtt_queue->rtq_count--;                          r->rtt_queue->rtq_count--;
                 else                  else
                         printf("rt_timer_remove_all: rtq_count reached 0\n");                          printf("rt_timer_remove_all: rtq_count reached 0\n");
                   /* we are already at splsoftnet */
                 pool_put(&rttimer_pool, r);                  pool_put(&rttimer_pool, r);
         }          }
 }  }
Line 946  rt_timer_add(struct rtentry *rt,
Line 1126  rt_timer_add(struct rtentry *rt,
         struct rttimer_queue *queue)          struct rttimer_queue *queue)
 {  {
         struct rttimer *r;          struct rttimer *r;
         long current_time;  
         int s;          int s;
   
         s = splclock();  
         current_time = mono_time.tv_sec;  
         splx(s);  
   
         /*          /*
          * If there's already a timer with this action, destroy it before           * If there's already a timer with this action, destroy it before
          * we add a new one.           * we add a new one.
          */           */
         for (r = LIST_FIRST(&rt->rt_timer); r != NULL;          LIST_FOREACH(r, &rt->rt_timer, rtt_link) {
              r = LIST_NEXT(r, rtt_link)) {                  if (r->rtt_func == func)
                 if (r->rtt_func == func) {                          break;
                         LIST_REMOVE(r, rtt_link);          }
                         TAILQ_REMOVE(&r->rtt_queue->rtq_head, r, rtt_next);          if (r != NULL) {
                         if (r->rtt_queue->rtq_count > 0)                  LIST_REMOVE(r, rtt_link);
                                 r->rtt_queue->rtq_count--;                  TAILQ_REMOVE(&r->rtt_queue->rtq_head, r, rtt_next);
                         else                  if (r->rtt_queue->rtq_count > 0)
                                 printf("rt_timer_add: rtq_count reached 0\n");                          r->rtt_queue->rtq_count--;
                         pool_put(&rttimer_pool, r);                  else
                         break;  /* only one per list, so we can quit... */                          printf("rt_timer_add: rtq_count reached 0\n");
                 }          } else {
                   s = splsoftnet();
                   r = pool_get(&rttimer_pool, PR_NOWAIT);
                   splx(s);
                   if (r == NULL)
                           return ENOBUFS;
         }          }
   
         r = pool_get(&rttimer_pool, PR_NOWAIT);          memset(r, 0, sizeof(*r));
         if (r == NULL)  
                 return (ENOBUFS);  
         Bzero(r, sizeof(*r));  
   
         r->rtt_rt = rt;          r->rtt_rt = rt;
         r->rtt_time = current_time;          r->rtt_time = time_uptime;
         r->rtt_func = func;          r->rtt_func = func;
         r->rtt_queue = queue;          r->rtt_queue = queue;
         LIST_INSERT_HEAD(&rt->rt_timer, r, rtt_link);          LIST_INSERT_HEAD(&rt->rt_timer, r, rtt_link);
         TAILQ_INSERT_TAIL(&queue->rtq_head, r, rtt_next);          TAILQ_INSERT_TAIL(&queue->rtq_head, r, rtt_next);
         r->rtt_queue->rtq_count++;          r->rtt_queue->rtq_count++;
   
         return (0);          return 0;
 }  }
   
 /* ARGSUSED */  /* ARGSUSED */
Line 993  rt_timer_timer(void *arg)
Line 1170  rt_timer_timer(void *arg)
 {  {
         struct rttimer_queue *rtq;          struct rttimer_queue *rtq;
         struct rttimer *r;          struct rttimer *r;
         long current_time;  
         int s;          int s;
   
         s = splclock();  
         current_time = mono_time.tv_sec;  
         splx(s);  
   
         s = splsoftnet();          s = splsoftnet();
         for (rtq = LIST_FIRST(&rttimer_queue_head); rtq != NULL;          LIST_FOREACH(rtq, &rttimer_queue_head, rtq_link) {
              rtq = LIST_NEXT(rtq, rtq_link)) {  
                 while ((r = TAILQ_FIRST(&rtq->rtq_head)) != NULL &&                  while ((r = TAILQ_FIRST(&rtq->rtq_head)) != NULL &&
                     (r->rtt_time + rtq->rtq_timeout) < current_time) {                      (r->rtt_time + rtq->rtq_timeout) < time_uptime) {
                         LIST_REMOVE(r, rtt_link);                          LIST_REMOVE(r, rtt_link);
                         TAILQ_REMOVE(&rtq->rtq_head, r, rtt_next);                          TAILQ_REMOVE(&rtq->rtq_head, r, rtt_next);
                         RTTIMER_CALLOUT(r);                          RTTIMER_CALLOUT(r);
Line 1019  rt_timer_timer(void *arg)
Line 1190  rt_timer_timer(void *arg)
   
         callout_reset(&rt_timer_ch, hz, rt_timer_timer, NULL);          callout_reset(&rt_timer_ch, hz, rt_timer_timer, NULL);
 }  }
   
   #ifdef RTCACHE_DEBUG
   #ifndef RTCACHE_DEBUG_SIZE
   #define RTCACHE_DEBUG_SIZE (1024 * 1024)
   #endif
   static const char *cache_caller[RTCACHE_DEBUG_SIZE];
   static struct route *cache_entry[RTCACHE_DEBUG_SIZE];
   size_t cache_cur;
   #endif
   
   #ifdef RTCACHE_DEBUG
   static void
   _rtcache_init_debug(const char *caller, struct route *ro, int flag)
   #else
   static void
   _rtcache_init(struct route *ro, int flag)
   #endif
   {
   #ifdef RTCACHE_DEBUG
           size_t i;
           for (i = 0; i < cache_cur; ++i) {
                   if (cache_entry[i] == ro)
                           panic("Reinit of route %p, initialised from %s", ro, cache_caller[i]);
           }
   #endif
   
           if (rtcache_getdst(ro) == NULL)
                   return;
           ro->ro_rt = rtalloc1(rtcache_getdst(ro), flag);
           if (ro->ro_rt != NULL) {
   #ifdef RTCACHE_DEBUG
                   if (cache_cur == RTCACHE_DEBUG_SIZE)
                           panic("Route cache debug overflow");
                   cache_caller[cache_cur] = caller;
                   cache_entry[cache_cur] = ro;
                   ++cache_cur;
   #endif
                   rtcache(ro);
           }
   }
   
   #ifdef RTCACHE_DEBUG
   void
   rtcache_init_debug(const char *caller, struct route *ro)
   {
           _rtcache_init_debug(caller, ro, 1);
   }
   
   void
   rtcache_init_noclone_debug(const char *caller, struct route *ro)
   {
           _rtcache_init_debug(caller, ro, 0);
   }
   
   void
   rtcache_update(struct route *ro, int clone)
   {
           rtcache_clear(ro);
           _rtcache_init_debug(__func__, ro, clone);
   }
   #else
   void
   rtcache_init(struct route *ro)
   {
           _rtcache_init(ro, 1);
   }
   
   void
   rtcache_init_noclone(struct route *ro)
   {
           _rtcache_init(ro, 0);
   }
   
   void
   rtcache_update(struct route *ro, int clone)
   {
           rtcache_clear(ro);
           _rtcache_init(ro, clone);
   }
   #endif
   
   #ifdef RTCACHE_DEBUG
   void
   rtcache_copy_debug(const char *caller, struct route *new_ro, const struct route *old_ro)
   #else
   void
   rtcache_copy(struct route *new_ro, const struct route *old_ro)
   #endif
   {
           /* XXX i doubt this DTRT any longer --dyoung */
   #ifdef RTCACHE_DEBUG
           size_t i;
   
           for (i = 0; i < cache_cur; ++i) {
                   if (cache_entry[i] == new_ro)
                           panic("Copy to initalised route %p (before %s)", new_ro, cache_caller[i]);
           }
   #endif
   
           if (rtcache_getdst(old_ro) == NULL ||
               rtcache_setdst(new_ro, rtcache_getdst(old_ro)) != 0)
                   return;
           new_ro->ro_rt = old_ro->ro_rt;
           if (new_ro->ro_rt != NULL) {
   #ifdef RTCACHE_DEBUG
                   if (cache_cur == RTCACHE_DEBUG_SIZE)
                           panic("Route cache debug overflow");
                   cache_caller[cache_cur] = caller;
                   cache_entry[cache_cur] = new_ro;
                   ++cache_cur;
   #endif
                   rtcache(new_ro);
                   ++new_ro->ro_rt->rt_refcnt;
           }
   }
   
   void
   rtcache_clear(struct route *ro)
   {
   #ifdef RTCACHE_DEBUG
           size_t j, i = cache_cur;
           for (i = j = 0; i < cache_cur; ++i, ++j) {
                   if (cache_entry[i] == ro) {
                           if (ro->ro_rt == NULL)
                                   panic("Route cache manipulated (allocated by %s)", cache_caller[i]);
                           --j;
                   } else {
                           cache_caller[j] = cache_caller[i];
                           cache_entry[j] = cache_entry[i];
                   }
           }
           if (ro->ro_rt != NULL) {
                   if (i != j + 1)
                           panic("Wrong entries after rtcache_free: %zu (expected %zu)", j, i - 1);
                   --cache_cur;
           }
   #endif
   
           if (ro->ro_rt != NULL)
                   rtflush(ro);
           ro->ro_rt = NULL;
   }
   
   struct rtentry *
   rtcache_lookup2(struct route *ro, const struct sockaddr *dst, int clone,
       int *hitp)
   {
           const struct sockaddr *odst;
   
           odst = rtcache_getdst(ro);
   
           if (odst == NULL)
                   ;
           else if (sockaddr_cmp(odst, dst) != 0)
                   rtcache_free(ro);
           else if (rtcache_down(ro))
                   rtcache_clear(ro);
   
           if (ro->ro_rt == NULL) {
                   *hitp = 0;
                   rtcache_setdst(ro, dst);
                   _rtcache_init(ro, clone);
           } else
                   *hitp = 1;
   
           return ro->ro_rt;
   }
   
   void
   rtcache_free(struct route *ro)
   {
           rtcache_clear(ro);
           if (ro->ro_sa != NULL) {
                   sockaddr_free(ro->ro_sa);
                   ro->ro_sa = NULL;
           }
   }
   
   int
   rtcache_setdst(struct route *ro, const struct sockaddr *sa)
   {
           KASSERT(sa != NULL);
   
           if (ro->ro_sa != NULL && ro->ro_sa->sa_family == sa->sa_family) {
                   rtcache_clear(ro);
                   if (sockaddr_copy(ro->ro_sa, ro->ro_sa->sa_len, sa) != NULL)
                           return 0;
                   sockaddr_free(ro->ro_sa);
           } else if (ro->ro_sa != NULL)
                   rtcache_free(ro);       /* free ro_sa, wrong family */
   
           if ((ro->ro_sa = sockaddr_dup(sa, M_NOWAIT)) == NULL)
                   return ENOMEM;
           return 0;
   }
   
   static int
   rt_walktree_visitor(struct radix_node *rn, void *v)
   {
           struct rtwalk *rw = (struct rtwalk *)v;
   
           return (*rw->rw_f)((struct rtentry *)rn, rw->rw_v);
   }
   
   int
   rt_walktree(sa_family_t family, int (*f)(struct rtentry *, void *), void *v)
   {
           struct radix_node_head *rnh = rt_tables[family];
           struct rtwalk rw;
   
           if (rnh == NULL)
                   return 0;
   
           rw.rw_f = f;
           rw.rw_v = v;
   
           return rn_walktree(rnh, rt_walktree_visitor, &rw);
   }

Legend:
Removed from v.1.66  
changed lines
  Added in v.1.66.2.4

CVSweb <webmaster@jp.NetBSD.org>