``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 *);