summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/net/if_llatbl.c4
-rw-r--r--sys/net/if_llatbl.h2
-rw-r--r--sys/net/if_var.h2
-rw-r--r--sys/net/route.c4
-rw-r--r--sys/net/route.h1
-rw-r--r--sys/net/rtsock.c22
-rw-r--r--sys/netinet/in.c52
-rw-r--r--sys/netinet6/in6.c16
-rw-r--r--usr.sbin/arp/arp.c64
9 files changed, 121 insertions, 46 deletions
diff --git a/sys/net/if_llatbl.c b/sys/net/if_llatbl.c
index 4991c81..5992f6d 100644
--- a/sys/net/if_llatbl.c
+++ b/sys/net/if_llatbl.c
@@ -274,7 +274,9 @@ lla_rt_output(struct rt_msghdr *rtm, struct rt_addrinfo *info)
#ifdef INET
if (dst->sa_family == AF_INET &&
((struct sockaddr_inarp *)dst)->sin_other != 0) {
- struct rtentry *rt = rtalloc1(dst, 0, 0);
+ struct rtentry *rt;
+ ((struct sockaddr_inarp *)dst)->sin_other = 0;
+ rt = rtalloc1(dst, 0, 0);
if (rt == NULL || !(rt->rt_flags & RTF_HOST)) {
log(LOG_INFO, "%s: RTM_ADD publish "
"(proxy only) is invalid\n",
diff --git a/sys/net/if_llatbl.h b/sys/net/if_llatbl.h
index f54c78a..21357eb 100644
--- a/sys/net/if_llatbl.h
+++ b/sys/net/if_llatbl.h
@@ -159,7 +159,7 @@ struct lltable {
const struct sockaddr *mask);
struct llentry * (*llt_lookup)(struct lltable *, u_int flags,
const struct sockaddr *l3addr);
- int (*llt_rtcheck)(struct ifnet *,
+ int (*llt_rtcheck)(struct ifnet *, u_int flags,
const struct sockaddr *);
int (*llt_dump)(struct lltable *,
struct sysctl_req *);
diff --git a/sys/net/if_var.h b/sys/net/if_var.h
index 519e6aa..148d72c 100644
--- a/sys/net/if_var.h
+++ b/sys/net/if_var.h
@@ -710,6 +710,7 @@ struct ifaddr {
struct mtx ifa_mtx;
};
#define IFA_ROUTE RTF_UP /* route installed */
+#define IFA_RTSELF RTF_HOST /* loopback route to self installed */
/* for compatibility with other BSDs */
#define ifa_list ifa_link
@@ -843,6 +844,7 @@ void if_ref(struct ifnet *);
void if_rele(struct ifnet *);
int if_setlladdr(struct ifnet *, const u_char *, int);
void if_up(struct ifnet *);
+/*void ifinit(void);*/ /* declared in systm.h for main() */
int ifioctl(struct socket *, u_long, caddr_t, struct thread *);
int ifpromisc(struct ifnet *, int);
struct ifnet *ifunit(const char *);
diff --git a/sys/net/route.c b/sys/net/route.c
index 027772b..a938c9c 100644
--- a/sys/net/route.c
+++ b/sys/net/route.c
@@ -98,8 +98,6 @@ VNET_DEFINE(struct rtstat, rtstat);
#define V_rttrash VNET(rttrash)
#define V_rtstat VNET(rtstat)
-static void rt_maskedcopy(struct sockaddr *,
- struct sockaddr *, struct sockaddr *);
/* compare two sockaddr structures */
#define sa_equal(a1, a2) (bcmp((a1), (a2), (a1)->sa_len) == 0)
@@ -1322,7 +1320,7 @@ rt_setgate(struct rtentry *rt, struct sockaddr *dst, struct sockaddr *gate)
return (0);
}
-static void
+void
rt_maskedcopy(struct sockaddr *src, struct sockaddr *dst, struct sockaddr *netmask)
{
register u_char *cp1 = (u_char *)src;
diff --git a/sys/net/route.h b/sys/net/route.h
index 9a0bc63..a8ae867 100644
--- a/sys/net/route.h
+++ b/sys/net/route.h
@@ -384,6 +384,7 @@ void rt_missmsg(int, struct rt_addrinfo *, int, int);
void rt_newaddrmsg(int, struct ifaddr *, int, struct rtentry *);
void rt_newmaddrmsg(int, struct ifmultiaddr *);
int rt_setgate(struct rtentry *, struct sockaddr *, struct sockaddr *);
+void rt_maskedcopy(struct sockaddr *, struct sockaddr *, struct sockaddr *);
/*
* Note the following locking behavior:
diff --git a/sys/net/rtsock.c b/sys/net/rtsock.c
index a0677ec..df4f9ae 100644
--- a/sys/net/rtsock.c
+++ b/sys/net/rtsock.c
@@ -60,6 +60,7 @@
#include <net/vnet.h>
#include <netinet/in.h>
+#include <netinet/if_ether.h>
#ifdef INET6
#include <netinet6/scope6_var.h>
#endif
@@ -622,6 +623,27 @@ route_output(struct mbuf *m, struct socket *so)
}
}
#endif
+ /*
+ * If performing proxied L2 entry insertion, and
+ * the actual PPP host entry is found, perform
+ * another search to retrieve the prefix route of
+ * the local end point of the PPP link.
+ */
+ if ((rtm->rtm_flags & RTF_ANNOUNCE) &&
+ (rt->rt_ifp->if_flags & IFF_POINTOPOINT)) {
+ struct sockaddr laddr;
+ rt_maskedcopy(rt->rt_ifa->ifa_addr,
+ &laddr,
+ rt->rt_ifa->ifa_netmask);
+ /*
+ * refactor rt and no lock operation necessary
+ */
+ rt = (struct rtentry *)rnh->rnh_matchaddr(&laddr, rnh);
+ if (rt == NULL) {
+ RADIX_NODE_HEAD_RUNLOCK(rnh);
+ senderr(ESRCH);
+ }
+ }
RT_LOCK(rt);
RT_ADDREF(rt);
RADIX_NODE_HEAD_RUNLOCK(rnh);
diff --git a/sys/netinet/in.c b/sys/netinet/in.c
index 09f2f44..c5317e5 100644
--- a/sys/netinet/in.c
+++ b/sys/netinet/in.c
@@ -924,9 +924,25 @@ in_ifinit(struct ifnet *ifp, struct in_ifaddr *ia, struct sockaddr_in *sin,
/*
* add a loopback route to self
*/
- if (V_useloopback && !(ifp->if_flags & IFF_LOOPBACK))
- error = ifa_add_loopback_route((struct ifaddr *)ia,
+ if (V_useloopback && !(ifp->if_flags & IFF_LOOPBACK)) {
+ struct route ia_ro;
+
+ bzero(&ia_ro, sizeof(ia_ro));
+ *((struct sockaddr_in *)(&ia_ro.ro_dst)) = ia->ia_addr;
+ rtalloc_ign_fib(&ia_ro, 0, 0);
+ if ((ia_ro.ro_rt != NULL) && (ia_ro.ro_rt->rt_ifp != NULL) &&
+ (ia_ro.ro_rt->rt_ifp == V_loif)) {
+ RT_LOCK(ia_ro.ro_rt);
+ RT_ADDREF(ia_ro.ro_rt);
+ RTFREE_LOCKED(ia_ro.ro_rt);
+ } else
+ error = ifa_add_loopback_route((struct ifaddr *)ia,
(struct sockaddr *)&ia->ia_addr);
+ if (error == 0)
+ ia->ia_flags |= IFA_RTSELF;
+ if (ia_ro.ro_rt != NULL)
+ RTFREE(ia_ro.ro_rt);
+ }
return (error);
}
@@ -1043,7 +1059,7 @@ in_scrubprefix(struct in_ifaddr *target)
{
struct in_ifaddr *ia;
struct in_addr prefix, mask, p;
- int error;
+ int error = 0;
struct sockaddr_in prefix0, mask0;
/*
@@ -1057,9 +1073,28 @@ in_scrubprefix(struct in_ifaddr *target)
* deletion is unconditional.
*/
if ((target->ia_addr.sin_addr.s_addr != INADDR_ANY) &&
- !(target->ia_ifp->if_flags & IFF_LOOPBACK)) {
- error = ifa_del_loopback_route((struct ifaddr *)target,
+ !(target->ia_ifp->if_flags & IFF_LOOPBACK) &&
+ (target->ia_flags & IFA_RTSELF)) {
+ struct route ia_ro;
+ int freeit = 0;
+
+ bzero(&ia_ro, sizeof(ia_ro));
+ *((struct sockaddr_in *)(&ia_ro.ro_dst)) = target->ia_addr;
+ rtalloc_ign_fib(&ia_ro, 0, 0);
+ if ((ia_ro.ro_rt != NULL) && (ia_ro.ro_rt->rt_ifp != NULL) &&
+ (ia_ro.ro_rt->rt_ifp == V_loif)) {
+ RT_LOCK(ia_ro.ro_rt);
+ if (ia_ro.ro_rt->rt_refcnt <= 1)
+ freeit = 1;
+ else
+ RT_REMREF(ia_ro.ro_rt);
+ RTFREE_LOCKED(ia_ro.ro_rt);
+ }
+ if (freeit)
+ error = ifa_del_loopback_route((struct ifaddr *)target,
(struct sockaddr *)&target->ia_addr);
+ if (error == 0)
+ target->ia_flags &= ~IFA_RTSELF;
/* remove arp cache */
arp_ifscrub(target->ia_ifp, IA_SIN(target)->sin_addr.s_addr);
}
@@ -1317,7 +1352,7 @@ in_lltable_prefix_free(struct lltable *llt,
static int
-in_lltable_rtcheck(struct ifnet *ifp, const struct sockaddr *l3addr)
+in_lltable_rtcheck(struct ifnet *ifp, u_int flags, const struct sockaddr *l3addr)
{
struct rtentry *rt;
@@ -1326,7 +1361,8 @@ in_lltable_rtcheck(struct ifnet *ifp, const struct sockaddr *l3addr)
/* XXX rtalloc1 should take a const param */
rt = rtalloc1(__DECONST(struct sockaddr *, l3addr), 0, 0);
- if (rt == NULL || (rt->rt_flags & RTF_GATEWAY) || rt->rt_ifp != ifp) {
+ if (rt == NULL || (rt->rt_flags & RTF_GATEWAY) ||
+ ((rt->rt_ifp != ifp) && !(flags & LLE_PUB))) {
#ifdef DIAGNOSTIC
log(LOG_INFO, "IPv4 address: \"%s\" is not on the network\n",
inet_ntoa(((const struct sockaddr_in *)l3addr)->sin_addr));
@@ -1378,7 +1414,7 @@ in_lltable_lookup(struct lltable *llt, u_int flags, const struct sockaddr *l3add
* verify this.
*/
if (!(flags & LLE_IFADDR) &&
- in_lltable_rtcheck(ifp, l3addr) != 0)
+ in_lltable_rtcheck(ifp, flags, l3addr) != 0)
goto done;
lle = in_lltable_new(l3addr, flags);
diff --git a/sys/netinet6/in6.c b/sys/netinet6/in6.c
index 7254c4d..c839efd 100644
--- a/sys/netinet6/in6.c
+++ b/sys/netinet6/in6.c
@@ -1200,8 +1200,12 @@ in6_purgeaddr(struct ifaddr *ifa)
* The check for the current setting of "nd6_useloopback"
* is not needed.
*/
- error = ifa_del_loopback_route((struct ifaddr *)ia,
- (struct sockaddr *)&ia->ia_addr);
+ if (ia->ia_flags & IFA_RTSELF) {
+ error = ifa_del_loopback_route((struct ifaddr *)ia,
+ (struct sockaddr *)&ia->ia_addr);
+ if (error == 0)
+ ia->ia_flags &= ~IFA_RTSELF;
+ }
/* stop DAD processing */
nd6_dad_stop(ifa);
@@ -1762,6 +1766,8 @@ in6_ifinit(struct ifnet *ifp, struct in6_ifaddr *ia,
|| (ifp->if_flags & IFF_LOOPBACK))) {
error = ifa_add_loopback_route((struct ifaddr *)ia,
(struct sockaddr *)&ia->ia_addr);
+ if (error == 0)
+ ia->ia_flags |= IFA_RTSELF;
}
/* Add ownaddr as loopback rtentry, if necessary (ex. on p2p link). */
@@ -2347,7 +2353,9 @@ in6_lltable_prefix_free(struct lltable *llt,
}
static int
-in6_lltable_rtcheck(struct ifnet *ifp, const struct sockaddr *l3addr)
+in6_lltable_rtcheck(struct ifnet *ifp,
+ u_int flags,
+ const struct sockaddr *l3addr)
{
struct rtentry *rt;
char ip6buf[INET6_ADDRSTRLEN];
@@ -2415,7 +2423,7 @@ in6_lltable_lookup(struct lltable *llt, u_int flags,
* verify this.
*/
if (!(flags & LLE_IFADDR) &&
- in6_lltable_rtcheck(ifp, l3addr) != 0)
+ in6_lltable_rtcheck(ifp, flags, l3addr) != 0)
return NULL;
lle = in6_lltable_new(l3addr, flags);
diff --git a/usr.sbin/arp/arp.c b/usr.sbin/arp/arp.c
index 2982f48..61427d3 100644
--- a/usr.sbin/arp/arp.c
+++ b/usr.sbin/arp/arp.c
@@ -326,7 +326,6 @@ set(int argc, char **argv)
doing_proxy = 1;
if (argc && strncmp(argv[1], "only", 3) == 0) {
proxy_only = 1;
- dst->sin_other = SIN_PROXY;
argc--; argv++;
}
} else if (strncmp(argv[0], "blackhole", 9) == 0) {
@@ -365,33 +364,30 @@ set(int argc, char **argv)
sdl_m.sdl_alen = ETHER_ADDR_LEN;
}
}
- for (;;) { /* try at most twice */
- rtm = rtmsg(RTM_GET, dst, &sdl_m);
- if (rtm == NULL) {
- warn("%s", host);
- return (1);
- }
- addr = (struct sockaddr_inarp *)(rtm + 1);
- sdl = (struct sockaddr_dl *)(SA_SIZE(addr) + (char *)addr);
- if (addr->sin_addr.s_addr != dst->sin_addr.s_addr)
- break;
- if (sdl->sdl_family == AF_LINK &&
- !(rtm->rtm_flags & RTF_GATEWAY) &&
- valid_type(sdl->sdl_type) )
- break;
- if (doing_proxy == 0) {
- printf("set: can only proxy for %s\n", host);
- return (1);
- }
- if (dst->sin_other & SIN_PROXY) {
- printf("set: proxy entry exists for non 802 device\n");
- return (1);
- }
- dst->sin_other = SIN_PROXY;
- proxy_only = 1;
+
+ /*
+ * In the case a proxy-arp entry is being added for
+ * a remote end point, the RTF_ANNOUNCE flag in the
+ * RTM_GET command is an indication to the kernel
+ * routing code that the interface associated with
+ * the prefix route covering the local end of the
+ * PPP link should be returned, on which ARP applies.
+ */
+ rtm = rtmsg(RTM_GET, dst, &sdl_m);
+ if (rtm == NULL) {
+ warn("%s", host);
+ return (1);
+ }
+ addr = (struct sockaddr_inarp *)(rtm + 1);
+ sdl = (struct sockaddr_dl *)(SA_SIZE(addr) + (char *)addr);
+ if (addr->sin_addr.s_addr == dst->sin_addr.s_addr) {
+ printf("set: proxy entry exists for non 802 device\n");
+ return (1);
}
- if (sdl->sdl_family != AF_LINK) {
+ if ((sdl->sdl_family != AF_LINK) ||
+ (rtm->rtm_flags & RTF_GATEWAY) ||
+ !valid_type(sdl->sdl_type)) {
printf("cannot intuit interface index and type for %s\n", host);
return (1);
}
@@ -436,7 +432,11 @@ delete(char *host, int do_proxy)
dst = getaddr(host);
if (dst == NULL)
return (1);
- dst->sin_other = do_proxy;
+
+ /*
+ * Perform a regular entry delete first.
+ */
+ flags &= ~RTF_ANNOUNCE;
/*
* setup the data structure to notify the kernel
@@ -471,11 +471,16 @@ delete(char *host, int do_proxy)
break;
}
- if (dst->sin_other & SIN_PROXY) {
+ /*
+ * Regualar entry delete failed, now check if there
+ * is a proxy-arp entry to remove.
+ */
+ if (flags & RTF_ANNOUNCE) {
fprintf(stderr, "delete: cannot locate %s\n",host);
return (1);
}
- dst->sin_other = SIN_PROXY;
+
+ flags |= RTF_ANNOUNCE;
}
rtm->rtm_flags |= RTF_LLDATA;
if (rtmsg(RTM_DELETE, dst, NULL) != NULL) {
@@ -485,6 +490,7 @@ delete(char *host, int do_proxy)
return (1);
}
+
/*
* Search the arp table and do some action on matching entries
*/
OpenPOWER on IntegriCloud