1*25202Skarels #ifdef RCSIDENT 2*25202Skarels static char rcsident[] = "$Header: ip_output.c,v 1.28 85/07/31 09:32:09 walsh Exp $"; 3*25202Skarels #endif 4*25202Skarels 5*25202Skarels #include "../h/param.h" 6*25202Skarels #include "../h/dir.h" 7*25202Skarels #include "../h/user.h" 8*25202Skarels #include "../h/mbuf.h" 9*25202Skarels #include "../h/socket.h" 10*25202Skarels #include "../h/socketvar.h" 11*25202Skarels #include "../h/protosw.h" 12*25202Skarels #include "../h/domain.h" 13*25202Skarels #include "../h/ioctl.h" 14*25202Skarels #include "../h/syslog.h" 15*25202Skarels 16*25202Skarels #include "../net/if.h" 17*25202Skarels #include "../net/route.h" 18*25202Skarels 19*25202Skarels #include "../bbnnet/in.h" 20*25202Skarels #include "../bbnnet/net.h" 21*25202Skarels #include "../bbnnet/in_pcb.h" 22*25202Skarels #include "../bbnnet/in_var.h" 23*25202Skarels #include "../bbnnet/ip.h" 24*25202Skarels #include "../bbnnet/icmp.h" 25*25202Skarels 26*25202Skarels /* 27*25202Skarels * If you're going to a specific host or via a gateway, the routing 28*25202Skarels * entry gateway field holds the best way to get there. Otherwise, 29*25202Skarels * the routing entry tells you how to get onto that net -- it has 30*25202Skarels * the net address portion of our local host: 31*25202Skarels * 32*25202Skarels * On bbn-labs-b: 33*25202Skarels * 34*25202Skarels * rt_dst rt_gateway flags 35*25202Skarels * il0 => 0x00000b80 0x2010b80 UP 36*25202Skarels * imp0 => 0x00000008 0x2000708 UP 37*25202Skarels * loop => 0x0000007f 0x100007f UP 38*25202Skarels * 39*25202Skarels * So you can see that the rt_gateway is our local address, and the 40*25202Skarels * rt_dst may be the net number of the media. If it's a route 41*25202Skarels * to a net, the other guy is on this net and you want to route the 42*25202Skarels * packet to him anyway. 43*25202Skarels * 44*25202Skarels * gateway 0 0x1000b80 UP, RTF_GATEWAY 45*25202Skarels */ 46*25202Skarels 47*25202Skarels #define IF_SEND(ifp, mp, rt, retval) \ 48*25202Skarels {\ 49*25202Skarels static struct sockaddr_in tmproute = {AF_INET}; \ 50*25202Skarels \ 51*25202Skarels if (! ((ifp)->if_flags & IFF_UP)){ \ 52*25202Skarels /* goes with PRC_IFDOWN in in.c */ \ 53*25202Skarels m_freem(mp); \ 54*25202Skarels retval = ENETUNREACH; \ 55*25202Skarels } else if ((rt)->rt_flags & (RTF_GATEWAY|RTF_HOST)) \ 56*25202Skarels retval = (*(ifp)->if_output)(ifp, mp, &(rt)->rt_gateway); \ 57*25202Skarels else { \ 58*25202Skarels tmproute.sin_addr.s_addr = (mtod(mp, struct ip *))->ip_dst.s_addr; \ 59*25202Skarels retval = (*(ifp)->if_output)(ifp, mp, (struct sockaddr *) &tmproute); \ 60*25202Skarels }} 61*25202Skarels 62*25202Skarels if_send(ifp, mp, rt) 63*25202Skarels register struct ifnet *ifp; 64*25202Skarels register struct mbuf *mp; 65*25202Skarels register struct rtentry *rt; 66*25202Skarels { 67*25202Skarels int retval; 68*25202Skarels 69*25202Skarels IF_SEND (ifp, mp, rt, retval); 70*25202Skarels return (retval); 71*25202Skarels } 72*25202Skarels 73*25202Skarels 74*25202Skarels /* 75*25202Skarels * Find a route to this destination. Given the source and destination 76*25202Skarels * addresses, it returns a local net address 77*25202Skarels * to send to (either the address of the destination itself or a gateway). 78*25202Skarels * Taken mostly from rtalloc; expanded to route according to 79*25202Skarels * both ends of the connection. 80*25202Skarels */ 81*25202Skarels 82*25202Skarels 83*25202Skarels struct rtentry *ip_route(src, dst) 84*25202Skarels struct in_addr *src; 85*25202Skarels struct in_addr *dst; 86*25202Skarels { 87*25202Skarels register struct rtentry *rt; 88*25202Skarels register struct mbuf *m; 89*25202Skarels register unsigned hash; 90*25202Skarels net_t snet, dnet; 91*25202Skarels int doinghost; 92*25202Skarels struct rtentry *rtmin; 93*25202Skarels struct mbuf **table; 94*25202Skarels static struct in_addr wildcard; 95*25202Skarels 96*25202Skarels /* get network parts of src and dest addresses */ 97*25202Skarels 98*25202Skarels snet = iptonet(*src); 99*25202Skarels dnet = iptonet(*dst); 100*25202Skarels 101*25202Skarels rtmin = NULL; 102*25202Skarels hash = HOSTHASH(dst->s_addr); 103*25202Skarels table = rthost; 104*25202Skarels doinghost = TRUE; 105*25202Skarels again : 106*25202Skarels for (m = table[hash % RTHASHSIZ]; m; m = m->m_next) 107*25202Skarels { 108*25202Skarels rt = mtod(m, struct rtentry *); 109*25202Skarels if (rt->rt_hash != hash) 110*25202Skarels continue; 111*25202Skarels if (! (rt->rt_flags & RTF_UP)) 112*25202Skarels continue; 113*25202Skarels if (! (rt->rt_ifp->if_flags & IFF_UP)) 114*25202Skarels continue; 115*25202Skarels if (rt->rt_dst.sa_family != AF_INET) 116*25202Skarels continue; 117*25202Skarels 118*25202Skarels /* packets go out an interface with our local IP address */ 119*25202Skarels if (iptonet(((struct sockaddr_in *)&(rt->rt_gateway))->sin_addr) != snet) 120*25202Skarels continue; 121*25202Skarels 122*25202Skarels /* does this route get us there? */ 123*25202Skarels if (doinghost) 124*25202Skarels { 125*25202Skarels if (((struct sockaddr_in *)&(rt->rt_dst))->sin_addr.s_addr != 126*25202Skarels dst->s_addr) 127*25202Skarels continue; 128*25202Skarels } 129*25202Skarels else 130*25202Skarels { 131*25202Skarels /* 132*25202Skarels * iptonet == 0 => smart gateway (route to anywhere) 133*25202Skarels * iptonet != 0 => gateway to another net (route to net) 134*25202Skarels */ 135*25202Skarels if (iptonet(((struct sockaddr_in *)&(rt->rt_dst))->sin_addr) != dnet) 136*25202Skarels continue; 137*25202Skarels } 138*25202Skarels 139*25202Skarels /* and try to share load across gateways */ 140*25202Skarels if (rtmin == NULL) 141*25202Skarels rtmin = rt; 142*25202Skarels else if (rt->rt_use < rtmin->rt_use) 143*25202Skarels rtmin = rt; 144*25202Skarels } 145*25202Skarels 146*25202Skarels if (rtmin == NULL) 147*25202Skarels { 148*25202Skarels if (doinghost) 149*25202Skarels { 150*25202Skarels doinghost = FALSE; 151*25202Skarels hash = NETHASH(*dst), table = rtnet; 152*25202Skarels goto again; 153*25202Skarels } 154*25202Skarels /* 155*25202Skarels * Check for wildcard gateway, by convention network 0. 156*25202Skarels */ 157*25202Skarels if (dst != &wildcard) 158*25202Skarels { 159*25202Skarels hash = 0; 160*25202Skarels dst = &wildcard; 161*25202Skarels dnet = 0; 162*25202Skarels goto again; 163*25202Skarels } 164*25202Skarels rtstat.rts_unreach++; 165*25202Skarels return(NULL); 166*25202Skarels } 167*25202Skarels 168*25202Skarels rtmin->rt_refcnt++; 169*25202Skarels if (dst == &wildcard) 170*25202Skarels rtstat.rts_wildcard++; 171*25202Skarels return(rtmin); 172*25202Skarels } 173*25202Skarels 174*25202Skarels 175*25202Skarels /* 176*25202Skarels * Ip_send is called from the higher protocol layer (TCP/RDP/UDP) and is passed 177*25202Skarels * an mbuf chain containing a packet to send to the local network. The first 178*25202Skarels * mbuf contains the protocol header and an IP header which is partially 179*25202Skarels * filled in. After determining a route (outgoing interface + first hop) for 180*25202Skarels * the packet, it is fragmented (if necessary) and sent to the local net 181*25202Skarels * through the local net send routine. 182*25202Skarels * 183*25202Skarels * For non-raw output, caller should have stuffed: 184*25202Skarels * ip protocol type, type of service, source addr, destin addr 185*25202Skarels * 186*25202Skarels * ip_tos is left to caller so that people using raw sockets can do whatever 187*25202Skarels * they please. (They don't have an inpcb in which to store such info.) 188*25202Skarels * 189*25202Skarels * The asis argument is TRUE for raw output and the gateway (packet forwarding) 190*25202Skarels * code. It indicates that the IP header is fully constructed. 191*25202Skarels * 192*25202Skarels * Errors at the IP layer and below occur synchronously, and can be reported 193*25202Skarels * back via subroutine return values. Higher level protocols should remember 194*25202Skarels * that if they do things asynchronous to a system call (ie., packet 195*25202Skarels * retransmission) that they should post error back to user via advise_user() 196*25202Skarels * so that user gets error next time he rendezvous with the kernel. 197*25202Skarels */ 198*25202Skarels ip_send(inp, mp, len, asis) 199*25202Skarels struct inpcb *inp; 200*25202Skarels register struct mbuf *mp; 201*25202Skarels register int len; 202*25202Skarels int asis; 203*25202Skarels { 204*25202Skarels register struct ip *p; 205*25202Skarels register struct ifnet *ifp; 206*25202Skarels register struct rtentry *rt; 207*25202Skarels register int hlen; 208*25202Skarels int free_route = FALSE; 209*25202Skarels int retval; 210*25202Skarels 211*25202Skarels p = mtod(mp, struct ip *); /* -> ip header */ 212*25202Skarels /* 213*25202Skarels * Find route for datagram if one has not been assigned. 214*25202Skarels */ 215*25202Skarels if ((rt = inp->inp_route.ro_rt) == NULL) 216*25202Skarels { 217*25202Skarels if ((rt = ip_route(&p->ip_src, &p->ip_dst)) == NULL) 218*25202Skarels { 219*25202Skarels if (asis || (p->ip_src.s_addr == INADDR_ANY)) 220*25202Skarels { 221*25202Skarels /* 222*25202Skarels * asis: forwarding a packet not sourced by us 223*25202Skarels * eg., by raw interface and user level repeater process 224*25202Skarels * INADDR_ANY: sending icmp packet for which 225*25202Skarels * we're trying to avoid routing twice. 226*25202Skarels */ 227*25202Skarels struct route tmproute; 228*25202Skarels struct sockaddr_in *sin; 229*25202Skarels 230*25202Skarels bzero ((caddr_t) &tmproute, sizeof(tmproute)); 231*25202Skarels sin = (struct sockaddr_in *) &tmproute.ro_dst; 232*25202Skarels sin->sin_family = AF_INET; 233*25202Skarels sin->sin_addr.s_addr = p->ip_dst.s_addr; 234*25202Skarels rtalloc (&tmproute); 235*25202Skarels rt = tmproute.ro_rt; 236*25202Skarels 237*25202Skarels if (rt && (p->ip_src.s_addr == INADDR_ANY)) 238*25202Skarels p->ip_src = IA_INADDR(in_iafromif(rt->rt_ifp)); 239*25202Skarels } 240*25202Skarels 241*25202Skarels if (rt == NULL) 242*25202Skarels { 243*25202Skarels m_freem(mp); 244*25202Skarels return(ENETUNREACH); 245*25202Skarels } 246*25202Skarels } 247*25202Skarels free_route = TRUE; 248*25202Skarels } 249*25202Skarels ifp = rt->rt_ifp; 250*25202Skarels 251*25202Skarels /* 252*25202Skarels * Copy ip source route to header. Know asis must be FALSE, if do. 253*25202Skarels */ 254*25202Skarels if (inp->inp_optlen > 0) 255*25202Skarels { 256*25202Skarels char *q; 257*25202Skarels 258*25202Skarels if (mp->m_off - inp->inp_optlen >= MMINOFF) 259*25202Skarels { 260*25202Skarels struct in_addr *ipa; 261*25202Skarels 262*25202Skarels mp->m_off -= inp->inp_optlen; 263*25202Skarels mp->m_len += inp->inp_optlen; 264*25202Skarels q = (char *) p; 265*25202Skarels p = (struct ip *) (q - inp->inp_optlen); 266*25202Skarels bcopy(q, (caddr_t)p, sizeof(struct ip)); 267*25202Skarels bcopy(inp->inp_options, (caddr_t)(p+1), (unsigned)inp->inp_optlen); 268*25202Skarels /* 269*25202Skarels * And replate eventual destination with first hop. 270*25202Skarels * Eventual destination is in source route just 271*25202Skarels * copied in. 272*25202Skarels */ 273*25202Skarels ipa = (struct in_addr *) (&inp->inp_options[0]); 274*25202Skarels p->ip_dst = ipa[inp->inp_optlen/sizeof(struct in_addr)]; 275*25202Skarels } 276*25202Skarels else 277*25202Skarels log(KERN_RECOV, "ip_send: optlen %d inpcb 0x%x\n", 278*25202Skarels (int)inp->inp_optlen, inp); 279*25202Skarels } 280*25202Skarels 281*25202Skarels /* 282*25202Skarels * fill in ip header fields 283*25202Skarels */ 284*25202Skarels if (asis) 285*25202Skarels { 286*25202Skarels /* 287*25202Skarels * RAW OUTPUT. Must get len, hlen, off from packet header. 288*25202Skarels * Byte swap is ugly (since we must swap back below), but 289*25202Skarels * necessary in case we must fragment. 290*25202Skarels */ 291*25202Skarels hlen = p->ip_hl << IP_HLSHIFT; 292*25202Skarels len = ntohs(p->ip_len); 293*25202Skarels p->ip_off = ntohs(p->ip_off); 294*25202Skarels } 295*25202Skarels else 296*25202Skarels { 297*25202Skarels static u_short next_ip_id; /* some day RDP may want to force for rxmit */ 298*25202Skarels 299*25202Skarels hlen = sizeof(struct ip) + inp->inp_optlen; 300*25202Skarels len += hlen; 301*25202Skarels p->ip_v = IPVERSION; 302*25202Skarels p->ip_hl = hlen >> IP_HLSHIFT; 303*25202Skarels p->ip_off = 0; 304*25202Skarels p->ip_ttl = MAXTTL; /* ### should come from route */ 305*25202Skarels p->ip_id = htons(next_ip_id++); 306*25202Skarels } 307*25202Skarels 308*25202Skarels /* 309*25202Skarels * let ip_frag do the send if needed, otherwise do it directly. 310*25202Skarels */ 311*25202Skarels 312*25202Skarels /* for testing IP reassembly code */ 313*25202Skarels #ifdef FORCE_FRAG 314*25202Skarels #define MTU(ifp) (((ifp)->if_mtu >> FORCE_FRAG) & (~3)) 315*25202Skarels #else 316*25202Skarels #define MTU(ifp) (ifp)->if_mtu 317*25202Skarels #endif 318*25202Skarels 319*25202Skarels if (len > MTU(ifp)) 320*25202Skarels { 321*25202Skarels p->ip_len = len; 322*25202Skarels retval = ip_frag(p, ifp, rt, hlen); 323*25202Skarels } 324*25202Skarels else 325*25202Skarels { 326*25202Skarels /* 327*25202Skarels * complete header, byte swap, and send to local net 328*25202Skarels */ 329*25202Skarels p->ip_len = htons((u_short)len); 330*25202Skarels p->ip_off = htons(p->ip_off); 331*25202Skarels /* 332*25202Skarels * No reason not to have kernel checksum, even for raw packets. 333*25202Skarels */ 334*25202Skarels p->ip_sum = 0; 335*25202Skarels p->ip_sum = in_cksum(dtom(p), hlen); 336*25202Skarels IF_SEND (ifp, mp, rt, retval); 337*25202Skarels } 338*25202Skarels 339*25202Skarels rt->rt_use ++; /* Yet another IP packet sent away */ 340*25202Skarels 341*25202Skarels if (free_route) 342*25202Skarels { 343*25202Skarels struct socket *so; 344*25202Skarels 345*25202Skarels if ((so = inp->inp_socket) && 346*25202Skarels (so->so_proto->pr_flags & PR_CONNREQUIRED)) 347*25202Skarels /* 348*25202Skarels * Found a new route after old one pinged out. 349*25202Skarels */ 350*25202Skarels inp->inp_route.ro_rt = rt; 351*25202Skarels else 352*25202Skarels rtfree(rt); 353*25202Skarels } 354*25202Skarels 355*25202Skarels return(retval); 356*25202Skarels } 357*25202Skarels 358*25202Skarels /* 359*25202Skarels * Ip_frag is called with a packet with a completed ip header 360*25202Skarels * (except for checksum). It fragments the packet, inserts the 361*25202Skarels * IP checksum, and calls the appropriate local net output routine 362*25202Skarels * to send it to the net. 363*25202Skarels * 364*25202Skarels * Previously, when there was only one kind of mbuf, it tried to 365*25202Skarels * reduce space requirements by recycling the chain to be fragmented. 366*25202Skarels * Preserving this approach is overly complicated, and should mbufs 367*25202Skarels * change again, cause problems. Therefore, have switched to copying 368*25202Skarels * the chain to be fragmented. 369*25202Skarels */ 370*25202Skarels ip_frag(p, ifp, rt, hlen) 371*25202Skarels register struct ip *p; 372*25202Skarels struct ifnet *ifp; 373*25202Skarels struct rtentry *rt; 374*25202Skarels register int hlen; 375*25202Skarels { 376*25202Skarels register struct mbuf *m; /* original chunk */ 377*25202Skarels register struct mbuf *mhdr; /* fragment */ 378*25202Skarels register struct ip *fip; /* the fragment IP header */ 379*25202Skarels int off; /* offset into entire IP datagram */ 380*25202Skarels int here; /* offset into this chunk of it */ 381*25202Skarels register int len; /* length of data in this chunk */ 382*25202Skarels int flags; /* of this chunk to fragment */ 383*25202Skarels int max; /* max data length in a fragment */ 384*25202Skarels int fdlen; /* actual fragment data length */ 385*25202Skarels int error; 386*25202Skarels 387*25202Skarels m = dtom(p); 388*25202Skarels 389*25202Skarels if (p->ip_off & ip_df) 390*25202Skarels { /* can't fragment */ 391*25202Skarels m_freem(m); 392*25202Skarels return(EMSGSIZE); 393*25202Skarels } 394*25202Skarels max = MTU(ifp) - hlen; /* max data length in frag */ 395*25202Skarels len = p->ip_len - hlen; /* data length */ 396*25202Skarels 397*25202Skarels /* 398*25202Skarels * this only needs to be this complicated if we are handed 399*25202Skarels * an already-fragmented packet 400*25202Skarels */ 401*25202Skarels flags = p->ip_off&(ip_mf|ip_df); /* save old flags */ 402*25202Skarels p->ip_off &= ~flags; /* take them out of ip_off */ 403*25202Skarels off = p->ip_off << IP_OFFSHIFT; /* fragment offset */ 404*25202Skarels here = hlen; 405*25202Skarels error = 0; 406*25202Skarels 407*25202Skarels while (len > 0) 408*25202Skarels { 409*25202Skarels /* 410*25202Skarels * Allocate mbuf for fragment IP header 411*25202Skarels */ 412*25202Skarels mhdr = m_get(M_DONTWAIT, MT_HEADER); 413*25202Skarels if (mhdr == NULL) 414*25202Skarels { 415*25202Skarels error = ENOBUFS; 416*25202Skarels break; 417*25202Skarels } 418*25202Skarels /* 419*25202Skarels * get copy of data for fragment 420*25202Skarels */ 421*25202Skarels if (len < max) 422*25202Skarels fdlen = len; 423*25202Skarels else 424*25202Skarels fdlen = max & (~7); /* 7 == 2^IP_OFFSHIFT -1 */ 425*25202Skarels mhdr->m_next = m_copy(m, here, fdlen); 426*25202Skarels if (mhdr->m_next == NULL) 427*25202Skarels { 428*25202Skarels m_free(mhdr); 429*25202Skarels error = ENOBUFS; 430*25202Skarels break; 431*25202Skarels } 432*25202Skarels /* 433*25202Skarels * build the header for this fragment and ship it off. 434*25202Skarels */ 435*25202Skarels mhdr->m_len = hlen; 436*25202Skarels mhdr->m_off = MMAXOFF - hlen; 437*25202Skarels fip = mtod(mhdr, struct ip *); 438*25202Skarels bcopy((caddr_t)p, (caddr_t)fip, (unsigned)hlen); 439*25202Skarels fip->ip_off = off >> IP_OFFSHIFT; 440*25202Skarels if (fdlen >= len) 441*25202Skarels /* it's the last fragment */ 442*25202Skarels fip->ip_off |= flags; 443*25202Skarels else 444*25202Skarels fip->ip_off |= ip_mf; 445*25202Skarels fip->ip_off = htons((u_short)fip->ip_off); 446*25202Skarels fip->ip_len = htons((u_short)fdlen + hlen); 447*25202Skarels fip->ip_sum = 0; 448*25202Skarels fip->ip_sum = in_cksum(mhdr, hlen); 449*25202Skarels if (error = if_send (ifp, mhdr, rt)) 450*25202Skarels break; 451*25202Skarels 452*25202Skarels /* 453*25202Skarels * and get ready for next pass through the loop 454*25202Skarels */ 455*25202Skarels len -= fdlen; 456*25202Skarels off += fdlen; 457*25202Skarels here += fdlen; 458*25202Skarels } 459*25202Skarels 460*25202Skarels m_freem(m); 461*25202Skarels return (error); 462*25202Skarels } 463*25202Skarels 464*25202Skarels /* 465*25202Skarels * Current connection should use a new path. 466*25202Skarels */ 467*25202Skarels struct rtentry *ip_reroute(inp) 468*25202Skarels register struct inpcb *inp; 469*25202Skarels { 470*25202Skarels register struct route *ro = &inp->inp_route; 471*25202Skarels 472*25202Skarels rtfree(ro->ro_rt); 473*25202Skarels return(ro->ro_rt = ip_route(&inp->inp_laddr, &inp->inp_faddr)); 474*25202Skarels } 475*25202Skarels 476*25202Skarels /* 477*25202Skarels * A gateway has gone down. Change route used by all connections currently 478*25202Skarels * using it. 479*25202Skarels */ 480*25202Skarels ip_gdown(addr) 481*25202Skarels u_long addr; 482*25202Skarels { 483*25202Skarels register struct protosw *psw; 484*25202Skarels 485*25202Skarels for(psw=inetdomain.dom_protosw; psw < inetdomain.dom_protoswNPROTOSW; psw++) 486*25202Skarels if (psw->pr_type != SOCK_RAW) 487*25202Skarels if (psw->pr_ctlinput) 488*25202Skarels (*(psw->pr_ctlinput)) (PRC_GWDOWN, addr); 489*25202Skarels } 490*25202Skarels 491*25202Skarels /* 492*25202Skarels * Called from protocol ctlinput routine. This way, IP/ICMP don't need to know 493*25202Skarels * about protocol's head of inpcbs... for all the protocols. 494*25202Skarels */ 495*25202Skarels in_gdown (head, addr) 496*25202Skarels register struct inpcb *head; 497*25202Skarels u_long addr; 498*25202Skarels { 499*25202Skarels register struct inpcb *inp; 500*25202Skarels register struct rtentry *rt; 501*25202Skarels 502*25202Skarels if (head == NULL) 503*25202Skarels return; 504*25202Skarels 505*25202Skarels for(inp = head->inp_next; inp != head; inp = inp->inp_next) 506*25202Skarels { 507*25202Skarels if (rt = inp->inp_route.ro_rt) 508*25202Skarels { 509*25202Skarels if (rt->rt_flags & RTF_GATEWAY) 510*25202Skarels { 511*25202Skarels if (((struct sockaddr_in *) &rt->rt_gateway)->sin_addr.s_addr == addr) 512*25202Skarels { 513*25202Skarels /* 514*25202Skarels * Don't remove route permanently, since want to catch 515*25202Skarels * the gateway when it reboots: 516*25202Skarels * -- rtrequest (SIOCDELRT, rt) -- 517*25202Skarels * 518*25202Skarels * make sure rtfree() not remove route mbuf 519*25202Skarels * incrementing reference count here, and decrementing 520*25202Skarels * when timeout on reinstatement goes off. Cannot call 521*25202Skarels * rtfree with zero reference count when have not done 522*25202Skarels * SIOCDELRT. 523*25202Skarels */ 524*25202Skarels if (rt->rt_flags & RTF_UP) 525*25202Skarels { 526*25202Skarels rt->rt_flags &= ~RTF_UP; 527*25202Skarels rt->rt_flags |= RTF_REINSTATE; 528*25202Skarels rt->irt_gdown = RT_REINSTATE; 529*25202Skarels rt->rt_refcnt ++; 530*25202Skarels } 531*25202Skarels 532*25202Skarels if (!ip_reroute(inp)) 533*25202Skarels advise_user(inp->inp_socket, ENETUNREACH); 534*25202Skarels 535*25202Skarels } 536*25202Skarels } 537*25202Skarels } 538*25202Skarels } 539*25202Skarels } 540