diff options
Diffstat (limited to 'sys/netinet/if_ether.c')
-rw-r--r-- | sys/netinet/if_ether.c | 60 |
1 files changed, 35 insertions, 25 deletions
diff --git a/sys/netinet/if_ether.c b/sys/netinet/if_ether.c index cca016dbb90..9edbda2f4e8 100644 --- a/sys/netinet/if_ether.c +++ b/sys/netinet/if_ether.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_ether.c,v 1.169 2015/09/16 06:58:08 claudio Exp $ */ +/* $OpenBSD: if_ether.c,v 1.170 2015/09/28 08:26:58 mpi Exp $ */ /* $NetBSD: if_ether.c,v 1.31 1996/05/11 12:59:58 mycroft Exp $ */ /* @@ -328,12 +328,12 @@ arpresolve(struct ifnet *ifp, struct rtentry *rt0, struct mbuf *m, struct sockaddr *dst, u_char *desten) { struct arpcom *ac = (struct arpcom *)ifp; - struct llinfo_arp *la; + struct llinfo_arp *la = NULL; struct sockaddr_dl *sdl; struct rtentry *rt = NULL; struct mbuf *mh; char addr[INET_ADDRSTRLEN]; - int error; + int error, created = 0; if (m->m_flags & M_BCAST) { /* broadcast */ memcpy(desten, etherbroadcastaddr, sizeof(etherbroadcastaddr)); @@ -367,27 +367,26 @@ arpresolve(struct ifnet *ifp, struct rtentry *rt0, struct mbuf *m, "local address\n", __func__, inet_ntop(AF_INET, &satosin(dst)->sin_addr, addr, sizeof(addr))); } else { - la = NULL; - if ((rt = arplookup(satosin(dst)->sin_addr.s_addr, 1, 0, - ifp->if_rdomain)) != NULL) + rt = arplookup(satosin(dst)->sin_addr.s_addr, 1, 0, + ifp->if_rdomain); + if (rt != NULL) { + created = 1; la = ((struct llinfo_arp *)rt->rt_llinfo); + } if (la == NULL) log(LOG_DEBUG, "%s: %s: can't allocate llinfo\n", __func__, inet_ntop(AF_INET, &satosin(dst)->sin_addr, addr, sizeof(addr))); } - if (la == NULL || rt == NULL) { - m_freem(m); - return (EINVAL); - } + if (la == NULL || rt == NULL) + goto bad; sdl = SDL(rt->rt_gateway); if (sdl->sdl_alen > 0 && sdl->sdl_alen != ETHER_ADDR_LEN) { log(LOG_DEBUG, "%s: %s: incorrect arp information\n", __func__, inet_ntop(AF_INET, &satosin(dst)->sin_addr, addr, sizeof(addr))); - m_freem(m); - return (EINVAL); + goto bad; } /* * Check the address family and length is valid, the address @@ -396,12 +395,12 @@ arpresolve(struct ifnet *ifp, struct rtentry *rt0, struct mbuf *m, if ((rt->rt_expire == 0 || rt->rt_expire > time_second) && sdl->sdl_family == AF_LINK && sdl->sdl_alen != 0) { memcpy(desten, LLADDR(sdl), sdl->sdl_alen); + if (created) + rtfree(rt); return (0); } - if (ifp->if_flags & IFF_NOARP) { - m_freem(m); - return (EINVAL); - } + if (ifp->if_flags & IFF_NOARP) + goto bad; /* * There is an arptab entry, but no ethernet address @@ -460,7 +459,15 @@ arpresolve(struct ifnet *ifp, struct rtentry *rt0, struct mbuf *m, } } } + if (created) + rtfree(rt); return (EAGAIN); + +bad: + m_freem(m); + if (created) + rtfree(rt); + return (EINVAL); } /* @@ -529,7 +536,7 @@ in_arpinput(struct mbuf *m) struct arpcom *ac; struct ether_header *eh; struct llinfo_arp *la = 0; - struct rtentry *rt; + struct rtentry *rt = NULL; struct ifaddr *ifa; struct sockaddr_dl *sdl; struct sockaddr sa; @@ -725,10 +732,13 @@ in_arpinput(struct mbuf *m) reply: if (op != ARPOP_REQUEST) { out: + rtfree(rt); if_put(ifp); m_freem(m); return; } + + rtfree(rt); if (itaddr.s_addr == myaddr.s_addr) { /* I am the target */ memcpy(ea->arp_tha, ea->arp_sha, sizeof(ea->arp_sha)); @@ -743,6 +753,7 @@ out: memcpy(ea->arp_tha, ea->arp_sha, sizeof(ea->arp_sha)); sdl = SDL(rt->rt_gateway); memcpy(ea->arp_sha, LLADDR(sdl), sizeof(ea->arp_sha)); + rtfree(rt); } memcpy(ea->arp_tpa, ea->arp_spa, sizeof(ea->arp_spa)); @@ -811,15 +822,11 @@ arplookup(u_int32_t addr, int create, int proxy, u_int tableid) rt = rtalloc((struct sockaddr *)&sin, flags, tableid); if (rt == NULL) return (NULL); - rt->rt_refcnt--; if ((rt->rt_flags & RTF_GATEWAY) || (rt->rt_flags & RTF_LLINFO) == 0 || rt->rt_gateway->sa_family != AF_LINK) { - if (create) { - if (rt->rt_refcnt <= 0 && - (rt->rt_flags & RTF_CLONED) != 0) { - rtdeletemsg(rt, tableid); - } - } + if (create && (rt->rt_flags & RTF_CLONED)) + rtdeletemsg(rt, tableid); + rtfree(rt); return (NULL); } return (rt); @@ -842,13 +849,16 @@ arpproxy(struct in_addr in, unsigned int rtableid) /* Check that arp information are correct. */ sdl = (struct sockaddr_dl *)rt->rt_gateway; - if (sdl->sdl_alen != ETHER_ADDR_LEN) + if (sdl->sdl_alen != ETHER_ADDR_LEN) { + rtfree(rt); return (0); + } ifp = rt->rt_ifp; if (!memcmp(LLADDR(sdl), LLADDR(ifp->if_sadl), sdl->sdl_alen)) found = 1; + rtfree(rt); return (found); } |