``ipforward_rt'' is going away but rather than sending a big diff,
here's the first step.

This diff replaces in_rtaddr() by rtalloc(9).  Note that since the code
here is interested in rt_ifa it has to call rtisvalid(9) to prevent a
NULL-dereference in case of a stale ``ifa''.

For the same reason rtfree(9) has to be called *after* the pointer has
been dereferenced.  Because the reference on ``rt'' acts as a proxy for
``ifa''.

ok?

Index: netinet/ip_input.c
===================================================================
RCS file: /cvs/src/sys/netinet/ip_input.c,v
retrieving revision 1.269
diff -u -p -r1.269 ip_input.c
--- netinet/ip_input.c  29 Mar 2016 10:34:42 -0000      1.269
+++ netinet/ip_input.c  11 Apr 2016 13:10:51 -0000
@@ -1013,6 +1013,8 @@ int
 ip_dooptions(struct mbuf *m, struct ifnet *ifp)
 {
        struct ip *ip = mtod(m, struct ip *);
+       unsigned int rtableid = m->m_pkthdr.ph_rtableid;
+       struct rtentry *rt;
        struct sockaddr_in ipaddr;
        u_char *cp;
        struct ip_timestamp ipt;
@@ -1108,19 +1110,31 @@ ip_dooptions(struct mbuf *m, struct ifne
                                m->m_pkthdr.ph_rtableid))) == NULL)
                                ia = ifatoia(ifa_ifwithnet(sintosa(&ipaddr),
                                    m->m_pkthdr.ph_rtableid));
-                       } else
+                               if (ia == NULL) {
+                                       type = ICMP_UNREACH;
+                                       code = ICMP_UNREACH_SRCFAIL;
+                                       goto bad;
+                               }
+                               memcpy(cp + off, &ia->ia_addr.sin_addr,
+                                   sizeof(struct in_addr));
+                               cp[IPOPT_OFFSET] += sizeof(struct in_addr);
+                       } else {
                                /* keep packet in the virtual instance */
-                               ia = ip_rtaddr(ipaddr.sin_addr,
-                                   m->m_pkthdr.ph_rtableid);
-                       if (ia == NULL) {
-                               type = ICMP_UNREACH;
-                               code = ICMP_UNREACH_SRCFAIL;
-                               goto bad;
+                               rt = rtalloc(sintosa(&ipaddr), RT_RESOLVE,
+                                   rtableid);
+                               if (!rtisvalid(rt)) {
+                                       type = ICMP_UNREACH;
+                                       code = ICMP_UNREACH_SRCFAIL;
+                                       rtfree(rt);
+                                       goto bad;
+                               }
+                               ia = ifatoia(rt->rt_ifa);
+                               memcpy(cp + off, &ia->ia_addr.sin_addr,
+                                   sizeof(struct in_addr));
+                               rtfree(rt);
+                               cp[IPOPT_OFFSET] += sizeof(struct in_addr);
                        }
                        ip->ip_dst = ipaddr.sin_addr;
-                       memcpy(cp + off, &ia->ia_addr.sin_addr,
-                           sizeof(struct in_addr));
-                       cp[IPOPT_OFFSET] += sizeof(struct in_addr);
                        /*
                         * Let ip_intr's mcast routing check handle mcast pkts
                         */
@@ -1152,16 +1166,17 @@ ip_dooptions(struct mbuf *m, struct ifne
                         * use the incoming interface (should be same).
                         * Again keep the packet inside the virtual instance.
                         */
-                       if ((ia = ifatoia(ifa_ifwithaddr(sintosa(&ipaddr),
-                           m->m_pkthdr.ph_rtableid))) == NULL &&
-                           (ia = ip_rtaddr(ipaddr.sin_addr,
-                           m->m_pkthdr.ph_rtableid)) == NULL) {
+                       rt = rtalloc(sintosa(&ipaddr), RT_RESOLVE, rtableid);
+                       if (!rtisvalid(rt)) {
                                type = ICMP_UNREACH;
                                code = ICMP_UNREACH_HOST;
+                               rtfree(rt);
                                goto bad;
                        }
+                       ia = ifatoia(rt->rt_ifa);
                        memcpy(cp + off, &ia->ia_addr.sin_addr,
                            sizeof(struct in_addr));
+                       rtfree(rt);
                        cp[IPOPT_OFFSET] += sizeof(struct in_addr);
                        break;
 
@@ -1234,34 +1249,6 @@ bad:
        icmp_error(m, type, code, 0, 0);
        ipstat.ips_badoptions++;
        return (1);
-}
-
-/*
- * Given address of next destination (final or next hop),
- * return internet address info of interface to be used to get there.
- */
-struct in_ifaddr *
-ip_rtaddr(struct in_addr dst, u_int rtableid)
-{
-       struct sockaddr_in *sin;
-
-       sin = satosin(&ipforward_rt.ro_dst);
-
-       if (ipforward_rt.ro_rt == 0 || dst.s_addr != sin->sin_addr.s_addr) {
-               if (ipforward_rt.ro_rt) {
-                       rtfree(ipforward_rt.ro_rt);
-                       ipforward_rt.ro_rt = NULL;
-               }
-               sin->sin_family = AF_INET;
-               sin->sin_len = sizeof(*sin);
-               sin->sin_addr = dst;
-
-               ipforward_rt.ro_rt = rtalloc(&ipforward_rt.ro_dst,
-                   RT_RESOLVE, rtableid);
-       }
-       if (ipforward_rt.ro_rt == 0)
-               return (NULL);
-       return (ifatoia(ipforward_rt.ro_rt->rt_ifa));
 }
 
 /*
Index: netinet/ip_var.h
===================================================================
RCS file: /cvs/src/sys/netinet/ip_var.h,v
retrieving revision 1.61
diff -u -p -r1.61 ip_var.h
--- netinet/ip_var.h    3 Dec 2015 21:11:53 -0000       1.61
+++ netinet/ip_var.h    11 Apr 2016 13:10:51 -0000
@@ -189,8 +189,6 @@ int  ip_output(struct mbuf *, struct mbu
 int     ip_pcbopts(struct mbuf **, struct mbuf *);
 struct mbuf *
         ip_reass(struct ipqent *, struct ipq *);
-struct in_ifaddr *
-        ip_rtaddr(struct in_addr, u_int);
 u_int16_t
         ip_randomid(void);
 void    ip_send(struct mbuf *);

Reply via email to