/* * Get rid of old routes. When draining, this deletes everything, even when * the timeout is not expired yet. When updating, this makes sure that * nothing has a timeout longer than the current value of rtq_reallyold. */ static int in6_rtqkill(struct radix_node *rn, void *rock) { struct rtqk_arg *ap = rock; struct rtentry *rt = (struct rtentry *)rn; int err; if (rt->rt_flags & RTPRF_OURS) { ap->found++; if (ap->draining || rt->rt_rmx.rmx_expire <= time_second) { if (rt->rt_refcnt > 0) panic("rtqkill route really not free"); err = rtrequest(RTM_DELETE, rt_key(rt), rt->rt_gateway, rt_mask(rt), rt->rt_flags, NULL); if (err) log(LOG_WARNING, "in6_rtqkill: error %d", err); else ap->killed++; } else { if (ap->updating && (rt->rt_rmx.rmx_expire - time_second > rtq_reallyold)) { rt->rt_rmx.rmx_expire = time_second + rtq_reallyold; } ap->nextstop = lmin(ap->nextstop, rt->rt_rmx.rmx_expire); } } return 0; }
/* * Check for alternatives when higher level complains * about service problems. For now, invalidate cached * routing information. If the route was created dynamically * (by a redirect), time to try a default gateway again. */ void in6_losing(struct in6pcb *in6p) { struct rtentry *rt; struct rt_addrinfo info; if (in6p->in6p_af != AF_INET6) return; if ((rt = rtcache_validate(&in6p->in6p_route)) == NULL) return; memset(&info, 0, sizeof(info)); info.rti_info[RTAX_DST] = rtcache_getdst(&in6p->in6p_route); info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; info.rti_info[RTAX_NETMASK] = rt_mask(rt); rt_missmsg(RTM_LOSING, &info, rt->rt_flags, 0); if (rt->rt_flags & RTF_DYNAMIC) { (void)rtrequest(RTM_DELETE, rt_getkey(rt), rt->rt_gateway, rt_mask(rt), rt->rt_flags, NULL); } /* * A new route can be allocated * the next time output is attempted. */ rtcache_free(&in6p->in6p_route); }
/* * On last reference drop, mark the route as belong to us so that it can be * timed out. */ static void in_clsroute(struct radix_node *rn, struct radix_node_head *head) { struct rtentry *rt = (struct rtentry *)rn; if(!(rt->rt_flags & RTF_UP)) return; /* prophylactic measures */ if((rt->rt_flags & (RTF_LLINFO | RTF_HOST)) != RTF_HOST) return; if((rt->rt_flags & (RTF_WASCLONED | RTPRF_OURS)) != RTF_WASCLONED) return; /* * As requested by David Greenman: * If rtq_reallyold is 0, just delete the route without * waiting for a timeout cycle to kill it. */ if(rtq_reallyold != 0) { rt->rt_flags |= RTPRF_OURS; rt->rt_rmx.rmx_expire = time_second + rtq_reallyold; } else { rtrequest(RTM_DELETE, (struct sockaddr *)rt_key(rt), rt->rt_gateway, rt_mask(rt), rt->rt_flags, 0); } }
static int in_ifadownkill(struct radix_node *rn, void *xap) { struct in_ifadown_arg *ap = xap; struct rtentry *rt = (struct rtentry *)rn; int err; if (rt->rt_ifa == ap->ifa && !(rt->rt_flags & RTF_STATIC)) { /* * We need to disable the automatic prune that happens * in this case in rtrequest() because it will blow * away the pointers that rn_walktree() needs in order * continue our descent. We will end up deleting all * the routes that rtrequest() would have in any case, * so that behavior is not needed there. */ rt->rt_flags &= ~RTF_PRCLONING; err = rtrequest(RTM_DELETE, (struct sockaddr *)rt_key(rt), rt->rt_gateway, rt_mask(rt), rt->rt_flags, 0); if (err) { log(LOG_WARNING, "in_ifadownkill: error %d\n", err); } } return 0; }
/* * Install a default route to the passed IP address. */ static void nfs_boot_defrt(struct in_addr *gw_ip) { struct sockaddr dst, gw, mask; struct sockaddr_in *sin; int error; /* Destination: (default) */ memset((void *)&dst, 0, sizeof(dst)); dst.sa_len = sizeof(dst); dst.sa_family = AF_INET; /* Gateway: */ memset((void *)&gw, 0, sizeof(gw)); sin = (struct sockaddr_in *)&gw; sin->sin_len = sizeof(*sin); sin->sin_family = AF_INET; sin->sin_addr.s_addr = gw_ip->s_addr; /* Mask: (zero length) */ /* XXX - Just pass a null pointer? */ memset(&mask, 0, sizeof(mask)); /* add, dest, gw, mask, flags, 0 */ error = rtrequest(RTM_ADD, &dst, &gw, &mask, (RTF_UP | RTF_GATEWAY | RTF_STATIC), NULL); if (error) { printf("nfs_boot: add route, error=%d\n", error); error = 0; } }
/* * Check for alternatives when higher level complains * about service problems. For now, invalidate cached * routing information. If the route was created dynamically * (by a redirect), time to try a default gateway again. */ void in_losing(struct inpcb *inp) { register struct rtentry *rt; struct rt_addrinfo info; if ((rt = inp->inp_route.ro_rt)) { inp->inp_route.ro_rt = 0; bzero((caddr_t)&info, sizeof(info)); info.rti_info[RTAX_DST] = (struct sockaddr *)&inp->inp_route.ro_dst; info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; info.rti_info[RTAX_NETMASK] = rt_mask(rt); rt_missmsg(RTM_LOSING, &info, rt->rt_flags, 0); if (rt->rt_flags & RTF_DYNAMIC) (void) rtrequest(RTM_DELETE, rt_key(rt), rt->rt_gateway, rt_mask(rt), rt->rt_flags, (struct rtentry **)0); else /* * A new route can be allocated * the next time output is attempted. */ rtfree(rt); } }
struct rtentry * rtalloc1(struct sockaddr *dst, int report, u_int tableid) { struct radix_node_head *rnh; struct rtentry *rt; struct radix_node *rn; struct rtentry *newrt = 0; struct rt_addrinfo info; int s = splsoftnet(), err = 0, msgtype = RTM_MISS; rnh = rt_gettable(dst->sa_family, tableid); if (rnh && (rn = rnh->rnh_matchaddr((caddr_t)dst, rnh)) && ((rn->rn_flags & RNF_ROOT) == 0)) { newrt = rt = (struct rtentry *)rn; if (report && (rt->rt_flags & RTF_CLONING)) { err = rtrequest(RTM_RESOLVE, dst, SA(NULL), SA(NULL), 0, &newrt, tableid); if (err) { newrt = rt; rt->rt_refcnt++; goto miss; } if ((rt = newrt) && (rt->rt_flags & RTF_XRESOLVE)) { msgtype = RTM_RESOLVE; goto miss; } /* Inform listeners of the new route */ bzero(&info, sizeof(info)); info.rti_info[RTAX_DST] = rt_key(rt); info.rti_info[RTAX_NETMASK] = rt_mask(rt); info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; if (rt->rt_ifp != NULL) { info.rti_info[RTAX_IFP] = TAILQ_FIRST(&rt->rt_ifp->if_addrlist)->ifa_addr; info.rti_info[RTAX_IFA] = rt->rt_ifa->ifa_addr; } rt_missmsg(RTM_ADD, &info, rt->rt_flags, rt->rt_ifp, 0, tableid); } else rt->rt_refcnt++; } else { if (dst->sa_family != PF_KEY) rtstat.rts_unreach++; /* * IP encapsulation does lots of lookups where we don't need nor want * the RTM_MISSes that would be generated. It causes RTM_MISS storms * sent upward breaking user-level routing queries. */ miss: if (report && dst->sa_family != PF_KEY) { bzero((caddr_t)&info, sizeof(info)); info.rti_info[RTAX_DST] = dst; rt_missmsg(msgtype, &info, 0, NULL, err, tableid); } } splx(s); return (newrt); }
//------------------------------------------------------------------------------ // FUNCTION // // // DESCRIPTION // // // PARAMETERS // // // RETURN // // //------------------------------------------------------------------------------ static int ifart_delete( struct radix_node *rn, struct in_addr *addr ) { struct rtentry *rt = (struct rtentry *)rn; if (((struct sockaddr_in *)rt_key(rt))->sin_addr.s_addr == addr->s_addr) { rtrequest(RTM_DELETE, rt_key(rt), rt->rt_gateway, rt_mask(rt), rt->rt_flags, NULL); } return 0; }
//------------------------------------------------------------------------------ // FUNCTION // // // DESCRIPTION // // // PARAMETERS // // // RETURN // // //------------------------------------------------------------------------------ static int ifprt_delete( struct radix_node *rn, void *ifp ) { struct rtentry *rt = (struct rtentry *)rn; if(rt->rt_ifp == ifp) { rtrequest(RTM_DELETE, rt_key(rt), rt->rt_gateway, rt_mask(rt), rt->rt_flags, NULL); } return 0; }
//------------------------------------------------------------------------------ // FUNCTION // // // DESCRIPTION // // // PARAMETERS // // // RETURN // // //------------------------------------------------------------------------------ static int staticrt_delete( struct radix_node *rn, void *vifp ) { struct rtentry *rt = (struct rtentry *)rn; if((rt->rt_flags & RTF_STATIC) && !(rt->rt_flags & RTF_LLINFO)) { rtrequest(RTM_DELETE, rt_key(rt), rt->rt_gateway, rt_mask(rt), 0, NULL); } return 0; }
static int nfs_boot_delroute(struct rtentry *rt, void *w) { int error; if ((void *)rt->rt_ifp != w) return 0; error = rtrequest(RTM_DELETE, rt_getkey(rt), NULL, rt_mask(rt), 0, NULL); if (error != 0) printf("%s: del route, error=%d\n", __func__, error); return 0; }
struct rtentry * rtalloc2(struct sockaddr *dst, int report, int howstrict) { struct radix_node_head *rnh; struct rtentry *rt; struct radix_node *rn; struct rtentry *newrt = 0; struct rt_addrinfo info; int s = splnet(), err = 0, msgtype = RTM_MISS; rnh = rt_gettable(dst->sa_family, 0); if (rnh && (rn = rnh->rnh_matchaddr((caddr_t)dst, rnh)) && ((rn->rn_flags & RNF_ROOT) == 0)) { newrt = rt = (struct rtentry *)rn; if (report && (rt->rt_flags & RTF_CLONING) && okaytoclone(rt->rt_flags, howstrict)) { err = rtrequest(RTM_RESOLVE, dst, SA(0), SA(0), 0, &newrt, 0); if (err) { newrt = rt; rt->rt_refcnt++; goto miss; } if ((rt = newrt) && (rt->rt_flags & RTF_XRESOLVE)) { msgtype = RTM_RESOLVE; goto miss; } } else rt->rt_refcnt++; } else { rtstat.rts_unreach++; miss: if (report) { bzero((caddr_t)&info, sizeof(info)); info.rti_info[RTAX_DST] = dst; rt_missmsg(msgtype, &info, 0, NULL, err, 0); } } splx(s); return (newrt); }
void IPCP::RemoveRoutes() { // note: netstack creates and deletes destination route automatically if(fDefaultRoute) { struct sockaddr_in netmask; memset(&netmask, 0, sizeof(struct sockaddr_in)); netmask.sin_family = AF_INET; netmask.sin_addr.s_addr = fLocalRequests.netmask; netmask.sin_len = sizeof(struct sockaddr_in); if(rtrequest(RTM_DELETE, (struct sockaddr*) &netmask, (struct sockaddr*) &fGateway, (struct sockaddr*) &netmask, RTF_UP | RTF_GATEWAY, &fDefaultRoute) != B_OK) ERROR("IPCP: RemoveRoutes(): could not remove default/subnet route!\n"); fDefaultRoute = NULL; } }
/* * On last reference drop, mark the route as belong to us so that it can be * timed out. */ static void in6_clsroute(struct radix_node *rn, struct radix_node_head *head) { struct rtentry *rt = (struct rtentry *)rn; if (!(rt->rt_flags & RTF_UP)) return; /* prophylactic measures */ if ((rt->rt_flags & (RTF_LLINFO | RTF_HOST)) != RTF_HOST) return; if ((rt->rt_flags & (RTF_WASCLONED | RTPRF_OURS)) != RTF_WASCLONED) return; /* * As requested by David Greenman: * If rtq_reallyold is 0, just delete the route without * waiting for a timeout cycle to kill it. */ if (rtq_reallyold != 0) { rt->rt_flags |= RTPRF_OURS; rt->rt_rmx.rmx_expire = time_second + rtq_reallyold; } else { #ifdef __FreeBSD__ rtexpunge(rt); #else struct rtentry *dummy; /* * rtrequest() would recursively call rtfree() without the * dummy entry argument, causing duplicated free. */ rtrequest(RTM_DELETE, (struct sockaddr *)rt_key(rt), rt->rt_gateway, rt_mask(rt), rt->rt_flags, &dummy); #endif } }
static int aa_dosingleroute(struct ifaddr *ifa, struct at_addr *at_addr, struct at_addr *at_mask, int cmd, int flags) { struct sockaddr_at addr, mask; bzero(&addr, sizeof(addr)); bzero(&mask, sizeof(mask)); addr.sat_family = AF_APPLETALK; addr.sat_len = sizeof(struct sockaddr_at); addr.sat_addr.s_net = at_addr->s_net; addr.sat_addr.s_node = at_addr->s_node; mask.sat_family = AF_APPLETALK; mask.sat_len = sizeof(struct sockaddr_at); mask.sat_addr.s_net = at_mask->s_net; mask.sat_addr.s_node = at_mask->s_node; if (at_mask->s_node) flags |= RTF_HOST; return(rtrequest(cmd, (struct sockaddr *) &addr, (flags & RTF_HOST)?(ifa->ifa_dstaddr):(ifa->ifa_addr), (struct sockaddr *) &mask, flags, NULL)); }
/* * Get rid of old routes. When draining, this deletes everything, even when * the timeout is not expired yet. When updating, this makes sure that * nothing has a timeout longer than the current value of rtq_reallyold. */ static int in_rtqkill(struct radix_node *rn, void *rock) { struct rtqk_arg *ap = rock; struct rtentry *rt = (struct rtentry *)rn; int err; if(rt->rt_flags & RTPRF_OURS) { ap->found++; if(ap->draining || rt->rt_rmx.rmx_expire <= rtems_bsdnet_seconds_since_boot()) { if(rt->rt_refcnt > 0) panic("rtqkill route really not free"); err = rtrequest(RTM_DELETE, (struct sockaddr *)rt_key(rt), rt->rt_gateway, rt_mask(rt), rt->rt_flags, 0); if(err) { log(LOG_WARNING, "in_rtqkill: error %d\n", err); } else { ap->killed++; } } else { if(ap->updating && (rt->rt_rmx.rmx_expire - rtems_bsdnet_seconds_since_boot() > rtq_reallyold)) { rt->rt_rmx.rmx_expire = rtems_bsdnet_seconds_since_boot() + rtq_reallyold; } ap->nextstop = lmin(ap->nextstop, rt->rt_rmx.rmx_expire); } } return 0; }
/* * atm_rtrequest: handle ATM rt request (in support of generic code) * inputs: "req" = request code * "rt" = route entry * "info" = rt_addrinfo */ void atm_rtrequest(int req, struct rtentry *rt, struct rt_addrinfo *info) { struct sockaddr *gate = rt->rt_gateway; struct atm_pseudoioctl api; #ifdef NATM struct sockaddr_in *sin; struct natmpcb *npcb = NULL; struct atm_pseudohdr *aph; #endif static struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK}; int error; if (rt->rt_flags & RTF_GATEWAY) /* link level requests only */ return; switch (req) { case RTM_RESOLVE: /* resolve: only happens when cloning */ kprintf("atm_rtrequest: RTM_RESOLVE request detected?\n"); break; case RTM_ADD: /* * route added by a command (e.g. ifconfig, route, arp...). * * first check to see if this is not a host route, in which * case we are being called via "ifconfig" to set the address. */ if ((rt->rt_flags & RTF_HOST) == 0) { rt_setgate(rt,rt_key(rt),(struct sockaddr *)&null_sdl, RTL_DONTREPORT); gate = rt->rt_gateway; SDL(gate)->sdl_type = rt->rt_ifp->if_type; SDL(gate)->sdl_index = rt->rt_ifp->if_index; break; } if ((rt->rt_flags & RTF_CLONING) != 0) { kprintf("atm_rtrequest: cloning route detected?\n"); break; } if (gate->sa_family != AF_LINK || gate->sa_len < sizeof(null_sdl)) { log(LOG_DEBUG, "atm_rtrequest: bad gateway value"); break; } #ifdef DIAGNOSTIC if (rt->rt_ifp->if_ioctl == NULL) panic("atm null ioctl"); #endif #ifdef NATM /* * let native ATM know we are using this VCI/VPI * (i.e. reserve it) */ sin = (struct sockaddr_in *) rt_key(rt); if (sin->sin_family != AF_INET) goto failed; aph = (struct atm_pseudohdr *) LLADDR(SDL(gate)); npcb = npcb_add(NULL, rt->rt_ifp, ATM_PH_VCI(aph), ATM_PH_VPI(aph)); if (npcb == NULL) goto failed; npcb->npcb_flags |= NPCB_IP; npcb->ipaddr.s_addr = sin->sin_addr.s_addr; /* XXX: move npcb to llinfo when ATM ARP is ready */ rt->rt_llinfo = npcb; rt->rt_flags |= RTF_LLINFO; #endif /* * let the lower level know this circuit is active */ bcopy(LLADDR(SDL(gate)), &api.aph, sizeof(api.aph)); api.rxhand = NULL; ifnet_serialize_all(rt->rt_ifp); error = rt->rt_ifp->if_ioctl(rt->rt_ifp, SIOCATMENA, (caddr_t)&api, NULL); ifnet_deserialize_all(rt->rt_ifp); if (error) { kprintf("atm: couldn't add VC\n"); goto failed; } SDL(gate)->sdl_type = rt->rt_ifp->if_type; SDL(gate)->sdl_index = rt->rt_ifp->if_index; break; failed: #ifdef NATM if (npcb) { npcb_free(npcb, NPCB_DESTROY); rt->rt_llinfo = NULL; rt->rt_flags &= ~RTF_LLINFO; } #endif rtrequest(RTM_DELETE, rt_key(rt), NULL, rt_mask(rt), 0, NULL); break; case RTM_DELETE: #ifdef NATM /* * tell native ATM we are done with this VC */ if (rt->rt_flags & RTF_LLINFO) { npcb_free(rt->rt_llinfo, NPCB_DESTROY); rt->rt_llinfo = NULL; rt->rt_flags &= ~RTF_LLINFO; } #endif /* * tell the lower layer to disable this circuit */ bcopy(LLADDR(SDL(gate)), &api.aph, sizeof(api.aph)); api.rxhand = NULL; ifnet_serialize_all(rt->rt_ifp); rt->rt_ifp->if_ioctl(rt->rt_ifp, SIOCATMDIS, (caddr_t)&api, NULL); ifnet_deserialize_all(rt->rt_ifp); break; } }
int bootpc_adjust_interface(struct ifreq *ireq,struct socket *so, struct sockaddr_in *myaddr, struct sockaddr_in *netmask, struct sockaddr_in *gw, struct proc *procp) { int error; struct sockaddr_in oldgw; struct sockaddr_in olddst; struct sockaddr_in oldmask; struct sockaddr_in *sin; /* Remove old default route to 0.0.0.0 */ bzero((caddr_t) &olddst, sizeof(olddst)); olddst.sin_len=sizeof(olddst); olddst.sin_family=AF_INET; olddst.sin_addr.s_addr = INADDR_ANY; bzero((caddr_t) &oldgw, sizeof(oldgw)); oldgw.sin_len=sizeof(oldgw); oldgw.sin_family=AF_INET; oldgw.sin_addr.s_addr = INADDR_ANY; bzero((caddr_t) &oldmask, sizeof(oldmask)); oldmask.sin_len=sizeof(oldmask); oldmask.sin_family=AF_INET; oldmask.sin_addr.s_addr = INADDR_ANY; error = rtrequest(RTM_DELETE, (struct sockaddr *) &olddst, (struct sockaddr *) &oldgw, (struct sockaddr *) &oldmask, (RTF_UP | RTF_STATIC), NULL); if (error) { printf("nfs_boot: del default route, error=%d\n", error); return error; } /* * Do enough of ifconfig(8) so that the chosen interface * can talk to the servers. (just set the address) */ bcopy(netmask,&ireq->ifr_addr,sizeof(*netmask)); error = ifioctl(so, SIOCSIFNETMASK, (caddr_t)ireq, procp); if (error) { printf("bootpc_adjust_interface: set netmask, error=%s\n", strerror(error)); return error; } /* Broadcast is with host part of IP address all 1's */ sin = (struct sockaddr_in *)&ireq->ifr_addr; bzero((caddr_t)sin, sizeof(*sin)); sin->sin_len = sizeof(*sin); sin->sin_family = AF_INET; sin->sin_addr.s_addr = myaddr->sin_addr.s_addr | ~ netmask->sin_addr.s_addr; error = ifioctl(so, SIOCSIFBRDADDR, (caddr_t)ireq, procp); if (error) { printf("bootpc_adjust_interface: set broadcast addr, error=%s\n", strerror(error)); return error; } bcopy(myaddr,&ireq->ifr_addr,sizeof(*myaddr)); error = ifioctl(so, SIOCSIFADDR, (caddr_t)ireq, procp); if (error) { printf("bootpc_adjust_interface: set if addr, error=%s\n", strerror(error)); return error; } /* Add new default route */ error = rtrequest(RTM_ADD, (struct sockaddr *) &olddst, (struct sockaddr *) gw, (struct sockaddr *) &oldmask, (RTF_UP | RTF_GATEWAY | RTF_STATIC), NULL); if (error) { printf("bootpc_adjust_interface: add net route, error=%d\n", error); } return error; }
int bootpc_fakeup_interface(struct ifreq *ireq,struct socket *so, struct proc *procp) { struct sockaddr_in *sin; int error; struct sockaddr_in dst; struct sockaddr_in gw; struct sockaddr_in mask; /* * Bring up the interface. * * Get the old interface flags and or IFF_UP into them; if * IFF_UP set blindly, interface selection can be clobbered. */ error = ifioctl(so, SIOCGIFFLAGS, (caddr_t)ireq, procp); if (error) { printf("bootpc_fakeup_interface: GIFFLAGS, error=%s\n", strerror(error)); return error; } ireq->ifr_flags |= IFF_UP; error = ifioctl(so, SIOCSIFFLAGS, (caddr_t)ireq, procp); if (error) { printf("bootpc_fakeup_interface: SIFFLAGS, error=%s\n", strerror(error)); return error; } /* * Do enough of ifconfig(8) so that the chosen interface * can talk to the servers. (just set the address) */ /* addr is 0.0.0.0 */ sin = (struct sockaddr_in *)&ireq->ifr_addr; bzero((caddr_t)sin, sizeof(*sin)); sin->sin_len = sizeof(*sin); sin->sin_family = AF_INET; sin->sin_addr.s_addr = INADDR_ANY; error = ifioctl(so, SIOCSIFADDR, (caddr_t)ireq, procp); /* * Ignore a File already exists (EEXIST) error code. This means a * route for the address is already present and is returned on * a second pass to here. */ if (error && (error != EEXIST)) { printf("bootpc_fakeup_interface: set if addr, error=%s\n", strerror(error)); return error; } /* netmask is 0.0.0.0 */ sin = (struct sockaddr_in *)&ireq->ifr_addr; bzero((caddr_t)sin, sizeof(*sin)); sin->sin_len = sizeof(*sin); sin->sin_family = AF_INET; sin->sin_addr.s_addr = INADDR_ANY; error = ifioctl(so, SIOCSIFNETMASK, (caddr_t)ireq, procp); if (error) { printf("bootpc_fakeup_interface: set if netmask, error=%s\n", strerror(error)); return error; } /* Broadcast is 255.255.255.255 */ sin = (struct sockaddr_in *)&ireq->ifr_addr; bzero((caddr_t)sin, sizeof(*sin)); sin->sin_len = sizeof(*sin); sin->sin_family = AF_INET; sin->sin_addr.s_addr = INADDR_BROADCAST; error = ifioctl(so, SIOCSIFBRDADDR, (caddr_t)ireq, procp); if (error) { printf("bootpc_fakeup_interface: set broadcast addr, error=%s\n", strerror(error)); return error; } /* Add default route to 0.0.0.0 so we can send data */ bzero((caddr_t) &dst, sizeof(dst)); dst.sin_len=sizeof(dst); dst.sin_family=AF_INET; dst.sin_addr.s_addr = htonl(0); bzero((caddr_t) &gw, sizeof(gw)); gw.sin_len=sizeof(gw); gw.sin_family=AF_INET; gw.sin_addr.s_addr = htonl(0x0); bzero((caddr_t) &mask, sizeof(mask)); mask.sin_len=sizeof(mask); mask.sin_family=AF_INET; mask.sin_addr.s_addr = htonl(0); error = rtrequest(RTM_ADD, (struct sockaddr *) &dst, (struct sockaddr *) &gw, (struct sockaddr *) &mask, RTF_UP | RTF_STATIC , NULL); if (error && error != EEXIST) printf("bootpc_fakeup_interface: add default route, error=%s\n", strerror(error)); return error; }
void atm_rtrequest(int req, struct rtentry *rt, const struct rt_addrinfo *info) { struct sockaddr *gate = rt->rt_gateway; struct atm_pseudoioctl api; #ifdef NATM const struct sockaddr_in *sin; struct natmpcb *npcb = NULL; const struct atm_pseudohdr *aph; #endif const struct ifnet *ifp = rt->rt_ifp; uint8_t namelen = strlen(ifp->if_xname); uint8_t addrlen = ifp->if_addrlen; if (rt->rt_flags & RTF_GATEWAY) /* link level requests only */ return; switch (req) { case RTM_RESOLVE: /* resolve: only happens when cloning */ printf("atm_rtrequest: RTM_RESOLVE request detected?\n"); break; case RTM_ADD: /* * route added by a command (e.g. ifconfig, route, arp...). * * first check to see if this is not a host route, in which * case we are being called via "ifconfig" to set the address. */ if ((rt->rt_flags & RTF_HOST) == 0) { union { struct sockaddr sa; struct sockaddr_dl sdl; struct sockaddr_storage ss; } u; sockaddr_dl_init(&u.sdl, sizeof(u.ss), ifp->if_index, ifp->if_type, NULL, namelen, NULL, addrlen); rt_setgate(rt, &u.sa); gate = rt->rt_gateway; break; } if ((rt->rt_flags & RTF_CLONING) != 0) { printf("atm_rtrequest: cloning route detected?\n"); break; } if (gate->sa_family != AF_LINK || gate->sa_len < sockaddr_dl_measure(namelen, addrlen)) { log(LOG_DEBUG, "atm_rtrequest: bad gateway value\n"); break; } #ifdef DIAGNOSTIC if (rt->rt_ifp->if_ioctl == NULL) panic("atm null ioctl"); #endif #ifdef NATM /* * let native ATM know we are using this VCI/VPI * (i.e. reserve it) */ sin = satocsin(rt_getkey(rt)); if (sin->sin_family != AF_INET) goto failed; aph = (const struct atm_pseudohdr *)CLLADDR(satosdl(gate)); npcb = npcb_add(NULL, rt->rt_ifp, ATM_PH_VCI(aph), ATM_PH_VPI(aph)); if (npcb == NULL) goto failed; npcb->npcb_flags |= NPCB_IP; npcb->ipaddr.s_addr = sin->sin_addr.s_addr; /* XXX: move npcb to llinfo when ATM ARP is ready */ rt->rt_llinfo = (void *) npcb; rt->rt_flags |= RTF_LLINFO; #endif /* * let the lower level know this circuit is active */ memcpy(&api.aph, CLLADDR(satocsdl(gate)), sizeof(api.aph)); api.rxhand = NULL; if (rt->rt_ifp->if_ioctl(rt->rt_ifp, SIOCATMENA, &api) != 0) { printf("atm: couldn't add VC\n"); goto failed; } satosdl(gate)->sdl_type = rt->rt_ifp->if_type; satosdl(gate)->sdl_index = rt->rt_ifp->if_index; break; failed: #ifdef NATM if (npcb) { npcb_free(npcb, NPCB_DESTROY); rt->rt_llinfo = NULL; rt->rt_flags &= ~RTF_LLINFO; } #endif rtrequest(RTM_DELETE, rt_getkey(rt), NULL, rt_mask(rt), 0, NULL); break; case RTM_DELETE: #ifdef NATM /* * tell native ATM we are done with this VC */ if (rt->rt_flags & RTF_LLINFO) { npcb_free((struct natmpcb *)rt->rt_llinfo, NPCB_DESTROY); rt->rt_llinfo = NULL; rt->rt_flags &= ~RTF_LLINFO; } #endif /* * tell the lower layer to disable this circuit */ memcpy(&api.aph, CLLADDR(satocsdl(gate)), sizeof(api.aph)); api.rxhand = NULL; (void)rt->rt_ifp->if_ioctl(rt->rt_ifp, SIOCATMDIS, &api); break; } }
/* * Do what we need to do when inserting a route. */ static struct radix_node * in_addroute(void *v_arg, void *n_arg, struct radix_node_head *head, struct radix_node *treenodes) { struct rtentry *rt = (struct rtentry *)treenodes; struct sockaddr_in *sin = (struct sockaddr_in *)rt_key(rt); struct radix_node *ret; /* * For IP, all unicast non-host routes are automatically cloning. */ if(IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) rt->rt_flags |= RTF_MULTICAST; if(!(rt->rt_flags & (RTF_HOST | RTF_CLONING | RTF_MULTICAST))) { rt->rt_flags |= RTF_PRCLONING; } /* * A little bit of help for both IP output and input: * For host routes, we make sure that RTF_BROADCAST * is set for anything that looks like a broadcast address. * This way, we can avoid an expensive call to in_broadcast() * in ip_output() most of the time (because the route passed * to ip_output() is almost always a host route). * * We also do the same for local addresses, with the thought * that this might one day be used to speed up ip_input(). * * We also mark routes to multicast addresses as such, because * it's easy to do and might be useful (but this is much more * dubious since it's so easy to inspect the address). (This * is done above.) */ if (rt->rt_flags & RTF_HOST) { if (in_broadcast(sin->sin_addr, rt->rt_ifp)) { rt->rt_flags |= RTF_BROADCAST; } else { #define satosin(sa) ((struct sockaddr_in *)sa) if (satosin(rt->rt_ifa->ifa_addr)->sin_addr.s_addr == sin->sin_addr.s_addr) rt->rt_flags |= RTF_LOCAL; #undef satosin } } if (!rt->rt_rmx.rmx_mtu && !(rt->rt_rmx.rmx_locks & RTV_MTU) && rt->rt_ifp) rt->rt_rmx.rmx_mtu = rt->rt_ifp->if_mtu; ret = rn_addroute(v_arg, n_arg, head, treenodes); if (ret == NULL && rt->rt_flags & RTF_HOST) { struct rtentry *rt2; /* * We are trying to add a host route, but can't. * Find out if it is because of an * ARP entry and delete it if so. */ rt2 = rtalloc1((struct sockaddr *)sin, 0, RTF_CLONING | RTF_PRCLONING); if (rt2) { if (rt2->rt_flags & RTF_LLINFO && rt2->rt_flags & RTF_HOST && rt2->rt_gateway && rt2->rt_gateway->sa_family == AF_LINK) { rtrequest(RTM_DELETE, (struct sockaddr *)rt_key(rt2), rt2->rt_gateway, rt_mask(rt2), rt2->rt_flags, 0); ret = rn_addroute(v_arg, n_arg, head, treenodes); } RTFREE(rt2); } } return ret; }
/* * arp_lookup_route will lookup the route for a given address. * * The address must be for a host on a local network on this interface. * If the returned route is non-NULL, the route is locked and the caller * is responsible for unlocking it and releasing its reference. */ static errno_t arp_lookup_route(const struct in_addr *addr, int create, int proxy, route_t *route, unsigned int ifscope) { struct sockaddr_inarp sin = {sizeof(sin), AF_INET, 0, {0}, {0}, 0, 0}; const char *why = NULL; errno_t error = 0; route_t rt; *route = NULL; sin.sin_addr.s_addr = addr->s_addr; sin.sin_other = proxy ? SIN_PROXY : 0; rt = rtalloc1_scoped((struct sockaddr*)&sin, create, 0, ifscope); if (rt == NULL) return (ENETUNREACH); RT_LOCK(rt); if (rt->rt_flags & RTF_GATEWAY) { why = "host is not on local network"; error = ENETUNREACH; } else if (!(rt->rt_flags & RTF_LLINFO)) { why = "could not allocate llinfo"; error = ENOMEM; } else if (rt->rt_gateway->sa_family != AF_LINK) { why = "gateway route is not ours"; error = EPROTONOSUPPORT; } if (error != 0) { if (create && log_arp_warnings) { char tmp[MAX_IPv4_STR_LEN]; log(LOG_DEBUG, "arplookup link#%d %s failed: %s\n", ifscope, inet_ntop(AF_INET, addr, tmp, sizeof (tmp)), why); } /* * If there are no references to this route, and it is * a cloned route, and not static, and ARP had created * the route, then purge it from the routing table as * it is probably bogus. */ if (rt->rt_refcnt == 1 && (rt->rt_flags & (RTF_WASCLONED | RTF_STATIC)) == RTF_WASCLONED) { /* * Prevent another thread from modiying rt_key, * rt_gateway via rt_setgate() after rt_lock is * dropped by marking the route as defunct. */ rt->rt_flags |= RTF_CONDEMNED; RT_UNLOCK(rt); rtrequest(RTM_DELETE, rt_key(rt), rt->rt_gateway, rt_mask(rt), rt->rt_flags, 0); rtfree(rt); } else { RT_REMREF_LOCKED(rt); RT_UNLOCK(rt); } return (error); } /* * Caller releases reference and does RT_UNLOCK(rt). */ *route = rt; return (0); }
/* * Mount a remote root fs via. nfs. This depends on the info in the * nfs_diskless structure that has been filled in properly by some primary * bootstrap. * It goes something like this: * - do enough of "ifconfig" by calling ifioctl() so that the system * can talk to the server * - If nfs_diskless.mygateway is filled in, use that address as * a default gateway. * - build the rootfs mount point and call mountnfs() to do the rest. * * It is assumed to be safe to read, modify, and write the nfsv3_diskless * structure, as well as other global NFS client variables here, as * nfs_mountroot() will be called once in the boot before any other NFS * client activity occurs. */ int nfs_mountroot(struct mount *mp) { struct thread *td = curthread; struct nfsv3_diskless *nd = &nfsv3_diskless; struct socket *so; struct vnode *vp; struct ifreq ir; int error; u_long l; char buf[128]; char *cp; #if defined(BOOTP_NFSROOT) && defined(BOOTP) bootpc_init(); /* use bootp to get nfs_diskless filled in */ #elif defined(NFS_ROOT) nfs_setup_diskless(); #endif if (nfs_diskless_valid == 0) { return (-1); } if (nfs_diskless_valid == 1) nfs_convert_diskless(); /* * XXX splnet, so networks will receive... */ splnet(); /* * Do enough of ifconfig(8) so that the critical net interface can * talk to the server. */ error = socreate(nd->myif.ifra_addr.sa_family, &so, nd->root_args.sotype, 0, td->td_ucred, td); if (error) panic("nfs_mountroot: socreate(%04x): %d", nd->myif.ifra_addr.sa_family, error); #if 0 /* XXX Bad idea */ /* * We might not have been told the right interface, so we pass * over the first ten interfaces of the same kind, until we get * one of them configured. */ for (i = strlen(nd->myif.ifra_name) - 1; nd->myif.ifra_name[i] >= '0' && nd->myif.ifra_name[i] <= '9'; nd->myif.ifra_name[i] ++) { error = ifioctl(so, SIOCAIFADDR, (caddr_t)&nd->myif, td); if(!error) break; } #endif error = ifioctl(so, SIOCAIFADDR, (caddr_t)&nd->myif, td); if (error) panic("nfs_mountroot: SIOCAIFADDR: %d", error); if ((cp = getenv("boot.netif.mtu")) != NULL) { ir.ifr_mtu = strtol(cp, NULL, 10); bcopy(nd->myif.ifra_name, ir.ifr_name, IFNAMSIZ); freeenv(cp); error = ifioctl(so, SIOCSIFMTU, (caddr_t)&ir, td); if (error) printf("nfs_mountroot: SIOCSIFMTU: %d", error); } soclose(so); /* * If the gateway field is filled in, set it as the default route. * Note that pxeboot will set a default route of 0 if the route * is not set by the DHCP server. Check also for a value of 0 * to avoid panicking inappropriately in that situation. */ if (nd->mygateway.sin_len != 0 && nd->mygateway.sin_addr.s_addr != 0) { struct sockaddr_in mask, sin; bzero((caddr_t)&mask, sizeof(mask)); sin = mask; sin.sin_family = AF_INET; sin.sin_len = sizeof(sin); /* XXX MRT use table 0 for this sort of thing */ CURVNET_SET(TD_TO_VNET(td)); error = rtrequest(RTM_ADD, (struct sockaddr *)&sin, (struct sockaddr *)&nd->mygateway, (struct sockaddr *)&mask, RTF_UP | RTF_GATEWAY, NULL); CURVNET_RESTORE(); if (error) panic("nfs_mountroot: RTM_ADD: %d", error); } /* * Create the rootfs mount point. */ nd->root_args.fh = nd->root_fh; nd->root_args.fhsize = nd->root_fhsize; l = ntohl(nd->root_saddr.sin_addr.s_addr); snprintf(buf, sizeof(buf), "%ld.%ld.%ld.%ld:%s", (l >> 24) & 0xff, (l >> 16) & 0xff, (l >> 8) & 0xff, (l >> 0) & 0xff, nd->root_hostnam); printf("NFS ROOT: %s\n", buf); nd->root_args.hostname = buf; if ((error = nfs_mountdiskless(buf, &nd->root_saddr, &nd->root_args, td, &vp, mp)) != 0) { return (error); } /* * This is not really an nfs issue, but it is much easier to * set hostname here and then let the "/etc/rc.xxx" files * mount the right /var based upon its preset value. */ mtx_lock(&prison0.pr_mtx); strlcpy(prison0.pr_hostname, nd->my_hostnam, sizeof (prison0.pr_hostname)); mtx_unlock(&prison0.pr_mtx); inittodr(ntohl(nd->root_time)); return (0); }
/* * NOTE: in6_ifdetach() does not support loopback if at this moment. * We don't need this function in bsdi, because interfaces are never removed * from the ifnet list in bsdi. */ void in6_ifdetach(struct ifnet *ifp) { struct in6_ifaddr *ia, *oia; struct ifaddr *ifa, *next; struct rtentry *rt; short rtflags; struct in6_multi_mship *imm; /* remove ip6_mrouter stuff */ ip6_mrouter_detach(ifp); /* remove neighbor management table */ nd6_purge(ifp); /* XXX this code is duplicated in in6_purgeif() --dyoung */ /* nuke any of IPv6 addresses we have */ if_purgeaddrs(ifp, AF_INET6, in6_purgeaddr); /* XXX isn't this code is redundant, given the above? --dyoung */ /* XXX doesn't this code replicate code in in6_purgeaddr() ? --dyoung */ /* undo everything done by in6_ifattach(), just in case */ for (ifa = IFADDR_FIRST(ifp); ifa != NULL; ifa = next) { next = IFADDR_NEXT(ifa); if (ifa->ifa_addr->sa_family != AF_INET6 || !IN6_IS_ADDR_LINKLOCAL(&satosin6(&ifa->ifa_addr)->sin6_addr)) { continue; } ia = (struct in6_ifaddr *)ifa; /* * leave from multicast groups we have joined for the interface */ while ((imm = LIST_FIRST(&ia->ia6_memberships)) != NULL) { LIST_REMOVE(imm, i6mm_chain); in6_leavegroup(imm); } /* remove from the routing table */ if ((ia->ia_flags & IFA_ROUTE) && (rt = rtalloc1((struct sockaddr *)&ia->ia_addr, 0))) { rtflags = rt->rt_flags; rtfree(rt); rtrequest(RTM_DELETE, (struct sockaddr *)&ia->ia_addr, (struct sockaddr *)&ia->ia_addr, (struct sockaddr *)&ia->ia_prefixmask, rtflags, NULL); } /* remove from the linked list */ ifa_remove(ifp, &ia->ia_ifa); /* also remove from the IPv6 address chain(itojun&jinmei) */ oia = ia; if (oia == (ia = in6_ifaddr)) in6_ifaddr = ia->ia_next; else { while (ia->ia_next && (ia->ia_next != oia)) ia = ia->ia_next; if (ia->ia_next) ia->ia_next = oia->ia_next; else { nd6log((LOG_ERR, "%s: didn't unlink in6ifaddr from list\n", if_name(ifp))); } } ifafree(&oia->ia_ifa); } /* cleanup multicast address kludge table, if there is any */ in6_purgemkludge(ifp); /* * remove neighbor management table. we call it twice just to make * sure we nuke everything. maybe we need just one call. * XXX: since the first call did not release addresses, some prefixes * might remain. We should call nd6_purge() again to release the * prefixes after removing all addresses above. * (Or can we just delay calling nd6_purge until at this point?) */ nd6_purge(ifp); }
/* * Do what we need to do when inserting a route. */ static struct radix_node * in6_addroute(void *v_arg, void *n_arg, struct radix_node_head *head, struct radix_node *treenodes) { struct rtentry *rt = (struct rtentry *)treenodes; struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)rt_key(rt); struct radix_node *ret; /* * For IPv6, all unicast non-host routes are automatically cloning. */ if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) rt->rt_flags |= RTF_MULTICAST; if (!(rt->rt_flags & (RTF_HOST | RTF_CLONING | RTF_MULTICAST))) { #ifdef RTF_PRCLONING rt->rt_flags |= RTF_PRCLONING; #endif } /* * A little bit of help for both IPv6 output and input: * For local addresses, we make sure that RTF_LOCAL is set, * with the thought that this might one day be used to speed up * ip_input(). * * We also mark routes to multicast addresses as such, because * it's easy to do and might be useful (but this is much more * dubious since it's so easy to inspect the address). (This * is done above.) * * XXX * should elaborate the code. */ if (rt->rt_flags & RTF_HOST) { if (IN6_ARE_ADDR_EQUAL(&satosin6(rt->rt_ifa->ifa_addr) ->sin6_addr, &sin6->sin6_addr)) { rt->rt_flags |= RTF_LOCAL; } } if (!rt->rt_rmx.rmx_mtu && rt->rt_ifp) rt->rt_rmx.rmx_mtu = IN6_LINKMTU(rt->rt_ifp); ret = rn_addroute(v_arg, n_arg, head, treenodes); if (ret == NULL && rt->rt_flags & RTF_HOST) { struct rtentry *rt2; /* * We are trying to add a host route, but can't. * Find out if it is because of an * ARP entry and delete it if so. */ rt2 = rtalloc1((struct sockaddr *)sin6, 0, RTF_CLONING #ifdef RTF_PRCLONING | RTF_PRCLONING #endif ); if (rt2) { if (rt2->rt_flags & RTF_LLINFO && rt2->rt_flags & RTF_HOST && rt2->rt_gateway && rt2->rt_gateway->sa_family == AF_LINK) { #ifdef __FreeBSD__ rtexpunge(rt2); RTFREE_LOCKED(rt2); #else rtrequest(RTM_DELETE, (struct sockaddr *)rt_key(rt2), rt2->rt_gateway, rt_mask(rt2), rt2->rt_flags, 0); #endif ret = rn_addroute(v_arg, n_arg, head, treenodes); } else #ifdef __FreeBSD__ RTFREE_LOCKED(rt2); #else RTFREE(rt2); #endif } } else if (ret == NULL && rt->rt_flags & RTF_CLONING) { struct rtentry *rt2; /* * We are trying to add a net route, but can't. * The following case should be allowed, so we'll make a * special check for this: * Two IPv6 addresses with the same prefix is assigned * to a single interrface. * # ifconfig if0 inet6 3ffe:0501::1 prefix 64 alias (*1) * # ifconfig if0 inet6 3ffe:0501::2 prefix 64 alias (*2) * In this case, (*1) and (*2) want to add the same * net route entry, 3ffe:0501:: -> if0. * This case should not raise an error. */ rt2 = rtalloc1((struct sockaddr *)sin6, 0, RTF_CLONING #ifdef RTF_PRCLONING | RTF_PRCLONING #endif ); if (rt2) { if ((rt2->rt_flags & (RTF_CLONING|RTF_HOST|RTF_GATEWAY)) == RTF_CLONING && rt2->rt_gateway && rt2->rt_gateway->sa_family == AF_LINK && rt2->rt_ifp == rt->rt_ifp) { ret = rt2->rt_nodes; } #ifdef __FreeBSD__ RTFREE_LOCKED(rt2); #else RTFREE(rt2); #endif } } return ret; }
void IPCP::UpdateAddresses() { RemoveRoutes(); if(State() != PPP_OPENED_STATE && !Interface().DoesConnectOnDemand()) return; struct in_aliasreq inreq; struct ifreq ifreqAddress, ifreqDestination; memset(&inreq, 0, sizeof(struct in_aliasreq)); memset(&ifreqAddress, 0, sizeof(struct ifreq)); memset(&ifreqDestination, 0, sizeof(struct ifreq)); memset(&fGateway, 0, sizeof(struct sockaddr_in)); // create local address inreq.ifra_addr.sin_family = AF_INET; if(fLocalRequests.address != INADDR_ANY) inreq.ifra_addr.sin_addr.s_addr = fLocalRequests.address; else if(fLocalConfiguration.address == INADDR_ANY) inreq.ifra_addr.sin_addr.s_addr = 0x010F0F0F; // was: INADDR_BROADCAST else inreq.ifra_addr.sin_addr.s_addr = fLocalConfiguration.address; inreq.ifra_addr.sin_len = sizeof(struct sockaddr_in); memcpy(&ifreqAddress.ifr_addr, &inreq.ifra_addr, sizeof(struct sockaddr_in)); // create destination address fGateway.sin_family = AF_INET; if(fPeerRequests.address != INADDR_ANY) fGateway.sin_addr.s_addr = fPeerRequests.address; else if(fPeerConfiguration.address == INADDR_ANY) fGateway.sin_addr.s_addr = 0x020F0F0F; // was: INADDR_BROADCAST else fGateway.sin_addr.s_addr = fPeerConfiguration.address; fGateway.sin_len = sizeof(struct sockaddr_in); memcpy(&inreq.ifra_dstaddr, &fGateway, sizeof(struct sockaddr_in)); memcpy(&ifreqDestination.ifr_dstaddr, &inreq.ifra_dstaddr, sizeof(struct sockaddr_in)); // create netmask inreq.ifra_mask.sin_family = AF_INET; inreq.ifra_mask.sin_addr.s_addr = fLocalRequests.netmask; inreq.ifra_mask.sin_len = sizeof(struct sockaddr_in); // tell stack to use these values if(in_control(NULL, SIOCAIFADDR, (caddr_t) &inreq, Interface().Ifnet()) != B_OK) ERROR("IPCP: UpdateAddress(): SIOCAIFADDR returned error!\n"); if(in_control(NULL, SIOCSIFADDR, (caddr_t) &ifreqAddress, Interface().Ifnet()) != B_OK) ERROR("IPCP: UpdateAddress(): SIOCSIFADDR returned error!\n"); if(in_control(NULL, SIOCSIFDSTADDR, (caddr_t) &ifreqDestination, Interface().Ifnet()) != B_OK) ERROR("IPCP: UpdateAddress(): SIOCSIFDSTADDR returned error!\n"); memcpy(&inreq.ifra_addr, &inreq.ifra_mask, sizeof(struct sockaddr_in)); // SIOCISFNETMASK wants the netmask to be in ifra_addr if(in_control(NULL, SIOCSIFNETMASK, (caddr_t) &inreq, Interface().Ifnet()) != B_OK) ERROR("IPCP: UpdateAddress(): SIOCSIFNETMASK returned error!\n"); // add default/subnet route if(Side() == PPP_LOCAL_SIDE) { if(rtrequest(RTM_ADD, (struct sockaddr*) &inreq.ifra_mask, (struct sockaddr*) &fGateway, (struct sockaddr*) &inreq.ifra_mask, RTF_UP | RTF_GATEWAY, &fDefaultRoute) != B_OK) ERROR("IPCP: UpdateAddress(): could not add default/subnet route!\n"); --fDefaultRoute->rt_refcnt; } }
/* * Do what we need to do when inserting a route. */ static struct radix_node * in_addroute(void *v_arg, void *n_arg, struct radix_node_head *head, struct radix_node *treenodes) { struct rtentry *rt = (struct rtentry *)treenodes; struct sockaddr_in *sin = (struct sockaddr_in *)rt_key(rt); struct radix_node *ret; /* * For IP, all unicast non-host routes are automatically cloning. */ if(IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) rt->rt_flags |= RTF_MULTICAST; if(!(rt->rt_flags & (RTF_HOST | RTF_CLONING | RTF_MULTICAST))) { rt->rt_flags |= RTF_PRCLONING; } /* * A little bit of help for both IP output and input: * For host routes, we make sure that RTF_BROADCAST * is set for anything that looks like a broadcast address. * This way, we can avoid an expensive call to in_broadcast() * in ip_output() most of the time (because the route passed * to ip_output() is almost always a host route). * * We also do the same for local addresses, with the thought * that this might one day be used to speed up ip_input(). * * We also mark routes to multicast addresses as such, because * it's easy to do and might be useful (but this is much more * dubious since it's so easy to inspect the address). (This * is done above.) */ if (rt->rt_flags & RTF_HOST) { if (in_broadcast(sin->sin_addr, rt->rt_ifp)) { rt->rt_flags |= RTF_BROADCAST; } else { #define satosin(sa) ((struct sockaddr_in *)sa) if (satosin(rt->rt_ifa->ifa_addr)->sin_addr.s_addr == sin->sin_addr.s_addr) rt->rt_flags |= RTF_LOCAL; #undef satosin } } /* * We also specify a send and receive pipe size for every * route added, to help TCP a bit. TCP doesn't actually * want a true pipe size, which would be prohibitive in memory * costs and is hard to compute anyway; it simply uses these * values to size its buffers. So, we fill them in with the * same values that TCP would have used anyway, and allow the * installing program or the link layer to override these values * as it sees fit. This will hopefully allow TCP more * opportunities to save its ssthresh value. */ if (!rt->rt_rmx.rmx_sendpipe && !(rt->rt_rmx.rmx_locks & RTV_SPIPE)) rt->rt_rmx.rmx_sendpipe = tcp_sendspace; if (!rt->rt_rmx.rmx_recvpipe && !(rt->rt_rmx.rmx_locks & RTV_RPIPE)) rt->rt_rmx.rmx_recvpipe = tcp_recvspace; if (!rt->rt_rmx.rmx_mtu && !(rt->rt_rmx.rmx_locks & RTV_MTU) && rt->rt_ifp) rt->rt_rmx.rmx_mtu = rt->rt_ifp->if_mtu; ret = rn_addroute(v_arg, n_arg, head, treenodes); if (ret == NULL && rt->rt_flags & RTF_HOST) { struct rtentry *rt2; /* * We are trying to add a host route, but can't. * Find out if it is because of an * ARP entry and delete it if so. */ rt2 = rtalloc1((struct sockaddr *)sin, 0, RTF_CLONING | RTF_PRCLONING); if (rt2) { if (rt2->rt_flags & RTF_LLINFO && rt2->rt_flags & RTF_HOST && rt2->rt_gateway && rt2->rt_gateway->sa_family == AF_LINK) { rtrequest(RTM_DELETE, (struct sockaddr *)rt_key(rt2), rt2->rt_gateway, rt_mask(rt2), rt2->rt_flags, 0); ret = rn_addroute(v_arg, n_arg, head, treenodes); } RTFREE(rt2); } } return ret; }