-
- case RTM_ADD:
- if (gate == 0)
- senderr(EINVAL);
-
-#ifdef __APPLE__
-/* XXX LD11JUL02 Special case for AOL 5.1.2 connectivity issue to AirPort BS (Radar 2969954)
- * AOL is adding a circular route ("10.0.1.1/32 10.0.1.1") when establishing its ppp tunnel
- * to the AP BaseStation by removing the default gateway and replacing it with their tunnel entry point.
- * There is no apparent reason to add this route as there is a valid 10.0.1.1/24 route to the BS.
- * That circular route was ignored on previous version of MacOS X because of a routing bug
- * corrected with the merge to FreeBSD4.4 (a route generated from an RTF_CLONING route had the RTF_WASCLONED
- * flag set but did not have a reference to the parent route) and that entry was left in the RT. This workaround is
- * made in order to provide binary compatibility with AOL.
- * If we catch a process adding a circular route with a /32 from the routing socket, we error it out instead of
- * confusing the routing table with a wrong route to the previous default gateway
- */
-{
- extern int check_routeselfref;
-#define satosinaddr(sa) (((struct sockaddr_in *)sa)->sin_addr.s_addr)
-
- if (check_routeselfref && (dst && dst->sa_family == AF_INET) &&
- (netmask && satosinaddr(netmask) == INADDR_BROADCAST) &&
- (gate && satosinaddr(dst) == satosinaddr(gate))) {
- log(LOG_WARNING, "route_output: circular route %ld.%ld.%ld.%ld/32 ignored\n",
- (ntohl(satosinaddr(gate)>>24))&0xff,
- (ntohl(satosinaddr(gate)>>16))&0xff,
- (ntohl(satosinaddr(gate)>>8))&0xff,
- (ntohl(satosinaddr(gate)))&0xff);
-
- senderr(EINVAL);
+ case RTM_ADD:
+ if (info.rti_info[RTAX_GATEWAY] == NULL)
+ senderr(EINVAL);
+
+ error = rtrequest_scoped_locked(RTM_ADD,
+ info.rti_info[RTAX_DST], info.rti_info[RTAX_GATEWAY],
+ info.rti_info[RTAX_NETMASK], rtm->rtm_flags, &saved_nrt,
+ ifscope);
+ if (error == 0 && saved_nrt != NULL) {
+ RT_LOCK(saved_nrt);
+ /*
+ * If the route request specified an interface with
+ * IFA and/or IFP, we set the requested interface on
+ * the route with rt_setif. It would be much better
+ * to do this inside rtrequest, but that would
+ * require passing the desired interface, in some
+ * form, to rtrequest. Since rtrequest is called in
+ * so many places (roughly 40 in our source), adding
+ * a parameter is to much for us to swallow; this is
+ * something for the FreeBSD developers to tackle.
+ * Instead, we let rtrequest compute whatever
+ * interface it wants, then come in behind it and
+ * stick in the interface that we really want. This
+ * works reasonably well except when rtrequest can't
+ * figure out what interface to use (with
+ * ifa_withroute) and returns ENETUNREACH. Ideally
+ * it shouldn't matter if rtrequest can't figure out
+ * the interface if we're going to explicitly set it
+ * ourselves anyway. But practically we can't
+ * recover here because rtrequest will not do any of
+ * the work necessary to add the route if it can't
+ * find an interface. As long as there is a default
+ * route that leads to some interface, rtrequest will
+ * find an interface, so this problem should be
+ * rarely encountered.
+ * dwiggins@bbn.com
+ */
+ rt_setif(saved_nrt,
+ info.rti_info[RTAX_IFP], info.rti_info[RTAX_IFA],
+ info.rti_info[RTAX_GATEWAY], ifscope);
+ (void)rt_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx, saved_nrt);
+ saved_nrt->rt_rmx.rmx_locks &= ~(rtm->rtm_inits);
+ saved_nrt->rt_rmx.rmx_locks |=
+ (rtm->rtm_inits & rtm->rtm_rmx.rmx_locks);
+ saved_nrt->rt_genmask = info.rti_info[RTAX_GENMASK];
+ RT_REMREF_LOCKED(saved_nrt);
+ RT_UNLOCK(saved_nrt);
+ }
+ break;
+
+ case RTM_DELETE:
+ error = rtrequest_scoped_locked(RTM_DELETE,
+ info.rti_info[RTAX_DST], info.rti_info[RTAX_GATEWAY],
+ info.rti_info[RTAX_NETMASK], rtm->rtm_flags, &saved_nrt,
+ ifscope);
+ if (error == 0) {
+ rt = saved_nrt;
+ RT_LOCK(rt);
+ goto report;
+ }
+ break;
+
+ case RTM_GET:
+ case RTM_CHANGE:
+ case RTM_LOCK:
+ rnh = rt_tables[info.rti_info[RTAX_DST]->sa_family];
+ if (rnh == NULL)
+ senderr(EAFNOSUPPORT);
+ /*
+ * Lookup the best match based on the key-mask pair;
+ * callee adds a reference and checks for root node.
+ */
+ rt = rt_lookup(TRUE, info.rti_info[RTAX_DST],
+ info.rti_info[RTAX_NETMASK], rnh, ifscope);
+ if (rt == NULL)
+ senderr(ESRCH);
+ RT_LOCK(rt);
+
+ /*
+ * Holding rnh_lock here prevents the possibility of
+ * ifa from changing (e.g. in_ifinit), so it is safe
+ * to access its ifa_addr (down below) without locking.
+ */
+ switch (rtm->rtm_type) {
+ case RTM_GET: {
+ kauth_cred_t cred;
+ struct ifaddr *ifa2;
+report:
+ cred = kauth_cred_proc_ref(current_proc());
+ ifa2 = NULL;
+ RT_LOCK_ASSERT_HELD(rt);
+ info.rti_info[RTAX_DST] = rt_key(rt);
+ dst_sa_family = info.rti_info[RTAX_DST]->sa_family;
+ info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
+ info.rti_info[RTAX_NETMASK] = rt_mask(rt);
+ info.rti_info[RTAX_GENMASK] = rt->rt_genmask;
+ if (rtm->rtm_addrs & (RTA_IFP | RTA_IFA)) {
+ ifp = rt->rt_ifp;
+ if (ifp != NULL) {
+ ifnet_lock_shared(ifp);
+ ifa2 = ifp->if_lladdr;
+ info.rti_info[RTAX_IFP] =
+ ifa2->ifa_addr;
+ IFA_ADDREF(ifa2);
+ ifnet_lock_done(ifp);
+ info.rti_info[RTAX_IFA] =
+ rt->rt_ifa->ifa_addr;
+ rtm->rtm_index = ifp->if_index;
+ } else {
+ info.rti_info[RTAX_IFP] = NULL;
+ info.rti_info[RTAX_IFA] = NULL;
+ }
+ } else if ((ifp = rt->rt_ifp) != NULL) {
+ rtm->rtm_index = ifp->if_index;