Index: net/route.c =================================================================== RCS file: /home/ncvs/src/sys/net/route.c,v retrieving revision 1.109 diff -u -r1.109 route.c --- net/route.c 28 Jun 2005 23:32:22 -0000 1.109 +++ net/route.c 14 Jul 2005 09:42:00 -0000 @@ -1255,7 +1255,8 @@ * Their values are meaningful ONLY if no error is returned. */ int -rt_check(struct rtentry **lrt, struct rtentry **lrt0, struct sockaddr *dst) +rt_check0(struct rtentry **lrt, struct rtentry **lrt0, struct sockaddr *dst, + int locked) { #define senderr(x) { error = x ; goto bad; } struct rtentry *rt; @@ -1302,11 +1303,14 @@ error = (rt->rt_flags & RTF_REJECT) && (rt->rt_rmx.rmx_expire == 0 || time_second < rt->rt_rmx.rmx_expire); - RT_UNLOCK(rt); - if (error) + if (error) { + RT_UNLOCK(rt); senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH); + } + if (locked == 0) + RT_UNLOCK(rt); } - *lrt = rt; /* NB: return unlocked */ + *lrt = rt; /* NB: return unlocked, if locked is 0 */ *lrt0 = rt0; return (0); bad: @@ -1315,5 +1319,11 @@ #undef senderr } +int +rt_check(struct rtentry **lrt, struct rtentry **lrt0, struct sockaddr *dst) +{ + return rt_check0(lrt, lrt0, dst, 0); +} + /* This must be before ip6_init2(), which is now SI_ORDER_MIDDLE */ SYSINIT(route, SI_SUB_PROTO_DOMAIN, SI_ORDER_THIRD, route_init, 0); Index: net/route.h =================================================================== RCS file: /home/ncvs/src/sys/net/route.h,v retrieving revision 1.63 diff -u -r1.63 route.h --- net/route.h 7 Jan 2005 01:45:35 -0000 1.63 +++ net/route.h 14 Jul 2005 09:38:48 -0000 @@ -353,6 +353,8 @@ struct sockaddr *, struct sockaddr *, int, struct rtentry **); int rtrequest1(int, struct rt_addrinfo *, struct rtentry **); int rt_check(struct rtentry **, struct rtentry **, struct sockaddr *); +int rt_check0(struct rtentry **, struct rtentry **, struct sockaddr *, + int); #endif #endif Index: netinet/if_ether.c =================================================================== RCS file: /home/ncvs/src/sys/netinet/if_ether.c,v retrieving revision 1.137 diff -u -r1.137 if_ether.c --- netinet/if_ether.c 5 Jun 2005 03:13:12 -0000 1.137 +++ netinet/if_ether.c 14 Jul 2005 10:51:23 -0000 @@ -125,7 +125,7 @@ static void arpintr(struct mbuf *); static void arptfree(struct llinfo_arp *); static void arptimer(void *); -static struct llinfo_arp +static struct rtentry *arplookup(u_long, int, int); #ifdef INET static void in_arpinput(struct mbuf *); @@ -369,33 +369,41 @@ struct llinfo_arp *la = 0; struct sockaddr_dl *sdl; int error; - struct rtentry *rt; + struct rtentry *rt = NULL; - error = rt_check(&rt, &rt0, dst); + error = rt_check0(&rt, &rt0, dst, 1); if (error) { m_freem(m); return error; } + KASSERT(rt != NULL, ("arpresolve: must not happen")); if (m->m_flags & M_BCAST) { /* broadcast */ + RT_UNLOCK(rt); (void)memcpy(desten, ifp->if_broadcastaddr, ifp->if_addrlen); return (0); } if (m->m_flags & M_MCAST && ifp->if_type != IFT_ARCNET) {/* multicast */ + RT_UNLOCK(rt); ETHER_MAP_IP_MULTICAST(&SIN(dst)->sin_addr, desten); return (0); } - if (rt) + if ((la = (struct llinfo_arp *)rt->rt_llinfo) == NULL) { + RT_UNLOCK(rt); + rt = arplookup(SIN(dst)->sin_addr.s_addr, 1, 0); + if (rt == NULL) { + log(LOG_DEBUG, + "arpresolve: can't allocate route for %s\n", + inet_ntoa(SIN(dst)->sin_addr)); + m_freem(m); + return (EINVAL); /* XXX */ + } la = (struct llinfo_arp *)rt->rt_llinfo; - if (la == 0) { - la = arplookup(SIN(dst)->sin_addr.s_addr, 1, 0); - if (la) - rt = la->la_rt; - } - if (la == 0 || rt == 0) { - log(LOG_DEBUG, "arpresolve: can't allocate llinfo for %s%s%s\n", - inet_ntoa(SIN(dst)->sin_addr), la ? "la" : "", - rt ? "rt" : ""); + } + if (la == NULL) { + RT_UNLOCK(rt); + log(LOG_DEBUG, "arpresolve: can't allocate llinfo for %s\n", + inet_ntoa(SIN(dst)->sin_addr)); m_freem(m); return (EINVAL); /* XXX */ } @@ -419,7 +427,7 @@ IF_LLADDR(ifp)); la->la_preempt--; } - + RT_UNLOCK(rt); bcopy(LLADDR(sdl), desten, sdl->sdl_alen); return (0); } @@ -430,6 +438,7 @@ * not going to be sending out an arp request. */ if (ifp->if_flags & (IFF_NOARP | IFF_STATICARP)) { + RT_UNLOCK(rt); m_freem(m); return (EINVAL); } @@ -442,7 +451,6 @@ m_freem(la->la_hold); la->la_hold = m; if (rt->rt_expire) { - RT_LOCK(rt); rt->rt_flags &= ~RTF_REJECT; if (la->la_asked == 0 || rt->rt_expire != time_second) { rt->rt_expire = time_second; @@ -459,8 +467,8 @@ } } - RT_UNLOCK(rt); } + RT_UNLOCK(rt); return (EWOULDBLOCK); } @@ -543,7 +551,7 @@ struct ifnet *ifp = m->m_pkthdr.rcvif; struct iso88025_header *th = (struct iso88025_header *)0; struct iso88025_sockaddr_dl_data *trld; - struct llinfo_arp *la = 0; + struct llinfo_arp *la = NULL; struct rtentry *rt; struct ifaddr *ifa; struct in_ifaddr *ia; @@ -640,8 +648,12 @@ } if (ifp->if_flags & IFF_STATICARP) goto reply; - la = arplookup(isaddr.s_addr, itaddr.s_addr == myaddr.s_addr, 0); - if (la && (rt = la->la_rt) && (sdl = SDL(rt->rt_gateway))) { + rt = arplookup(isaddr.s_addr, itaddr.s_addr == myaddr.s_addr, 0); + if (rt != NULL) + la = (struct llinfo_arp *)rt->rt_llinfo; + if (la && (sdl = SDL(rt->rt_gateway))) { + struct mbuf *hold; + /* the following is not an error when doing bridging */ if (!bridged && rt->rt_ifp != ifp #ifdef DEV_CARP @@ -654,6 +666,7 @@ rt->rt_ifp->if_xname, ifp->if_addrlen, (u_char *)ar_sha(ah), ":", ifp->if_xname); + RT_UNLOCK(rt); goto reply; } if (sdl->sdl_alen && @@ -670,6 +683,7 @@ "arp: %*D attempts to modify permanent entry for %s on %s\n", ifp->if_addrlen, (u_char *)ar_sha(ah), ":", inet_ntoa(isaddr), ifp->if_xname); + RT_UNLOCK(rt); goto reply; } } @@ -690,6 +704,7 @@ "arp from %*D: addr len: new %d, i/f %d (ignored)", ifp->if_addrlen, (u_char *) ar_sha(ah), ":", ah->ar_hln, ifp->if_addrlen); + RT_UNLOCK(rt); goto reply; } (void)memcpy(LLADDR(sdl), ar_sha(ah), @@ -725,17 +740,16 @@ m->m_pkthdr.len += 8; th->rcf = trld->trld_rcf; } - RT_LOCK(rt); if (rt->rt_expire) rt->rt_expire = time_second + arpt_keep; rt->rt_flags &= ~RTF_REJECT; - RT_UNLOCK(rt); la->la_asked = 0; la->la_preempt = arp_maxtries; - if (la->la_hold) { - (*ifp->if_output)(ifp, la->la_hold, rt_key(rt), rt); - la->la_hold = 0; - } + hold = la->la_hold; + la->la_hold = NULL; + RT_UNLOCK(rt); + if (hold) + (*ifp->if_output)(ifp, hold, rt_key(rt), rt); } reply: if (op != ARPOP_REQUEST) @@ -745,8 +759,8 @@ (void)memcpy(ar_tha(ah), ar_sha(ah), ah->ar_hln); (void)memcpy(ar_sha(ah), enaddr, ah->ar_hln); } else { - la = arplookup(itaddr.s_addr, 0, SIN_PROXY); - if (la == NULL) { + rt = arplookup(itaddr.s_addr, 0, SIN_PROXY); + if (rt == NULL) { struct sockaddr_in sin; if (!arp_proxyall) @@ -799,9 +813,9 @@ inet_ntoa(itaddr)); #endif } else { - rt = la->la_rt; - (void)memcpy(ar_tha(ah), ar_sha(ah), ah->ar_hln); sdl = SDL(rt->rt_gateway); + RT_UNLOCK(rt); + (void)memcpy(ar_tha(ah), ar_sha(ah), ah->ar_hln); (void)memcpy(ar_sha(ah), LLADDR(sdl), ah->ar_hln); } } @@ -850,7 +864,7 @@ /* * Lookup or enter a new address in arptab. */ -static struct llinfo_arp * +static struct rtentry * arplookup(addr, create, proxy) u_long addr; int create, proxy; @@ -895,8 +909,7 @@ #undef ISDYNCLONE } else { RT_REMREF(rt); - RT_UNLOCK(rt); - return ((struct llinfo_arp *)rt->rt_llinfo); + return (rt); } }