Bug 141134 - [ppp] "ioctl (SIOCAIFADDR): File exists" error when configuring ppp interfaces
Summary: [ppp] "ioctl (SIOCAIFADDR): File exists" error when configuring ppp interfaces
Status: Closed FIXED
Alias: None
Product: Base System
Classification: Unclassified
Component: kern (show other bugs)
Version: 8.0-RELEASE
Hardware: Any Any
: Normal Affects Only Me
Assignee: Qing Li
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2009-12-03 12:00 UTC by Alexander Zagrebin
Modified: 2010-01-05 22:42 UTC (History)
0 users

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Alexander Zagrebin 2009-12-03 12:00:11 UTC
I use mpd 5.3 (ports/net/mpd5) as vpn server.
After upgrading to 8.0-RELEASE from 7.2-RELEASE I began to receive complaints from users. They says, that the first attempt to connect to our vpn server always fails, and only the second attempt is successful.
The log files confirms this.
I have found how to reproduce this problem with command line.

I'll create the interface tun10:

# ifconfig tun10 create inet 192.168.100.1 192.168.100.10 netmask 0xffffffff
# ifconfig tun10
tun10: flags=8051<UP,POINTOPOINT,RUNNING,MULTICAST> metric 0 mtu 1500
        inet 192.168.100.1 --> 192.168.100.10 netmask 0xffffffff
# netstat -rn
..
192.168.100.1      link#13            UHS         0        0    lo0
192.168.100.10     link#13            UH          0        0  tun10
..
# ping -c1 192.168.100.1
PING 192.168.100.1 (192.168.100.1): 56 data bytes
64 bytes from 192.168.100.1: icmp_seq=0 ttl=64 time=0.050 ms

--- 192.168.100.1 ping statistics ---
1 packets transmitted, 1 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 0.050/0.050/0.050/0.000 ms

All right.
The interface was successfully created, loopback route was added, and i can ping self.
Now I'll create the interface tun11 for another peer:

# ifconfig tun11 create inet 192.168.100.1 192.168.100.11 netmask 0xffffffff
ifconfig: ioctl (SIOCAIFADDR): File exists
# ifconfig tun11
tun11: flags=8051<UP,POINTOPOINT,RUNNING,MULTICAST> metric 0 mtu 1500
        inet 192.168.100.1 --> 192.168.100.11 netmask 0xffffffff
# netstat -rn
..
192.168.100.1      link#13            UHS         0        1    lo0
192.168.100.10     link#13            UH          0        0  tun10
192.168.100.11     link#14            UH          0        0  tun11
..

The first problem:
ifconfig returned error, but interface was successfully configured.
The same error, returned from ioctl, forces ppp daemon to terminate ipcp and disconnect a peer.

Now I'll destroy tun11 and will create it again or will reconfigure it with the same parameters (the result is the same):

# ifconfig tun11 destroy
# ifconfig tun11 create inet 192.168.100.1 192.168.100.11 netmask 0xffffffff
or
# ifconfig tun11 inet 192.168.100.1 192.168.100.11 netmask 0xffffffff
# netstat -rn
..
192.168.100.1      link#14            UHS         0        0    lo0
192.168.100.10     link#13            UH          0        0  tun10
192.168.100.11     link#14            UH          0        0  tun11
..

There is no error from ifconfig now. It's strange.
loopback route was changed.
This explains why the second attempt of a peer to connect is successful.
If we'll create additional interfaces (tun12,tun13, etc), the behavior will the same.

The second problem:
Suppose the peer on tun11 terminates her session.
# ifconfig tun11 destroy
# netstat -rn
..
192.168.100.10     link#13            UH          0        0  tun10
..
# ping -c1 192.168.100.1
PING 192.168.100.1 (192.168.100.1): 56 data bytes

--- 192.168.100.1 ping statistics ---
1 packets transmitted, 0 packets received, 100.0% packet loss

So loopback route to 192.168.100.1 was deleted and I'll can't ping self. It's correct for destroyed tun11 (link#14), but as still there is the tun10 (link#13), we need loopback route to 192.168.100.1

After looking to the sources and doing some debugging I have found, that the first problem (EEXIST from ioctl) occurs because of call ifa_add_loopback_route
from in_ifinit (in.c:928). So I temporary disabled adding loopback routes via 
net.link.ether.inet.useloopback, but this is bad idea.

Fix: 

To prevent adding of loopback routes I use
sysctl net.link.ether.inet.useloopback=0
How-To-Repeat: See the "full description"
Comment 1 Mark Linimon freebsd_committer freebsd_triage 2009-12-03 23:42:59 UTC
Responsible Changed
From-To: freebsd-bugs->freebsd-net

Over to maintainer(s).
Comment 2 Qing Li freebsd_committer freebsd_triage 2009-12-04 18:05:10 UTC
Responsible Changed
From-To: freebsd-net->qingli

Take ownership of this bug.
Comment 3 dfilter service freebsd_committer freebsd_triage 2010-01-05 22:16:13 UTC
Author: qingli
Date: Tue Jan  5 22:14:55 2010
New Revision: 201614
URL: http://svn.freebsd.org/changeset/base/201614

Log:
  MFC r201282, r201543
  
  r201282
  -------
  The proxy arp entries could not be added into the system over the
  IFF_POINTOPOINT link types. The reason was due to the routing
  entry returned from the kernel covering the remote end is of an
  interface type that does not support ARP. This patch fixes this
  problem by providing a hint to the kernel routing code, which
  indicates the prefix route instead of the PPP host route should
  be returned to the caller. Since a host route to the local end
  point is also added into the routing table, and there could be
  multiple such instantiations due to multiple PPP links can be
  created with the same local end IP address, this patch also fixes
  the loopback route installation failure problem observed prior to
  this patch. The reference count of loopback route to local end would
  be either incremented or decremented. The first instantiation would
  create the entry and the last removal would delete the route entry.
  
  r201543
  -------
  The IFA_RTSELF address flag marks a loopback route has been installed
  for the interface address. This marker is necessary to properly support
  PPP types of links where multiple links can have the same local end
  IP address. The IFA_RTSELF flag bit maps to the RTF_HOST value, which
  was combined into the route flag bits during prefix installation in
  IPv6. This inclusion causing the prefix route to be unusable. This
  patch fixes this bug by excluding the IFA_RTSELF flag during route
  installation.
  
  PR:		ports/141342, kern/141134

Modified:
  stable/8/sys/net/if_llatbl.c
  stable/8/sys/net/if_llatbl.h
  stable/8/sys/net/if_var.h
  stable/8/sys/net/route.c
  stable/8/sys/net/route.h
  stable/8/sys/net/rtsock.c
  stable/8/sys/netinet/in.c
  stable/8/sys/netinet6/in6.c
  stable/8/sys/netinet6/nd6_rtr.c
  stable/8/usr.sbin/arp/arp.c
Directory Properties:
  stable/8/   (props changed)
  stable/8/ObsoleteFiles.inc   (props changed)
  stable/8/UPDATING   (props changed)
  stable/8/bin/   (props changed)
  stable/8/bin/csh/   (props changed)
  stable/8/bin/pax/   (props changed)
  stable/8/bin/ps/   (props changed)
  stable/8/bin/sh/   (props changed)
  stable/8/cddl/compat/opensolaris/   (props changed)
  stable/8/cddl/contrib/opensolaris/   (props changed)
  stable/8/cddl/contrib/opensolaris/cmd/zdb/   (props changed)
  stable/8/cddl/contrib/opensolaris/cmd/zfs/   (props changed)
  stable/8/cddl/contrib/opensolaris/lib/libzfs/   (props changed)
  stable/8/cddl/lib/libnvpair/   (props changed)
  stable/8/contrib/bind9/   (props changed)
  stable/8/contrib/bsnmp/   (props changed)
  stable/8/contrib/bzip2/   (props changed)
  stable/8/contrib/cpio/   (props changed)
  stable/8/contrib/csup/   (props changed)
  stable/8/contrib/ee/   (props changed)
  stable/8/contrib/expat/   (props changed)
  stable/8/contrib/file/   (props changed)
  stable/8/contrib/gcc/   (props changed)
  stable/8/contrib/gdb/   (props changed)
  stable/8/contrib/gdtoa/   (props changed)
  stable/8/contrib/less/   (props changed)
  stable/8/contrib/libpcap/   (props changed)
  stable/8/contrib/ncurses/   (props changed)
  stable/8/contrib/netcat/   (props changed)
  stable/8/contrib/ntp/   (props changed)
  stable/8/contrib/openbsm/   (props changed)
  stable/8/contrib/openpam/   (props changed)
  stable/8/contrib/pf/   (props changed)
  stable/8/contrib/sendmail/   (props changed)
  stable/8/contrib/tcpdump/   (props changed)
  stable/8/contrib/tcsh/   (props changed)
  stable/8/contrib/top/   (props changed)
  stable/8/contrib/top/install-sh   (props changed)
  stable/8/contrib/traceroute/   (props changed)
  stable/8/contrib/wpa/   (props changed)
  stable/8/crypto/openssh/   (props changed)
  stable/8/crypto/openssl/   (props changed)
  stable/8/etc/   (props changed)
  stable/8/games/factor/   (props changed)
  stable/8/games/fortune/   (props changed)
  stable/8/games/fortune/datfiles/   (props changed)
  stable/8/gnu/usr.bin/groff/   (props changed)
  stable/8/gnu/usr.bin/patch/   (props changed)
  stable/8/include/   (props changed)
  stable/8/kerberos5/lib/libgssapi_krb5/   (props changed)
  stable/8/kerberos5/lib/libgssapi_spnego/   (props changed)
  stable/8/lib/bind/   (props changed)
  stable/8/lib/csu/   (props changed)
  stable/8/lib/libarchive/   (props changed)
  stable/8/lib/libc/   (props changed)
  stable/8/lib/libc/stdtime/   (props changed)
  stable/8/lib/libdevinfo/   (props changed)
  stable/8/lib/libdisk/   (props changed)
  stable/8/lib/libexpat/   (props changed)
  stable/8/lib/libfetch/   (props changed)
  stable/8/lib/libjail/   (props changed)
  stable/8/lib/libkvm/   (props changed)
  stable/8/lib/libpmc/   (props changed)
  stable/8/lib/libradius/   (props changed)
  stable/8/lib/libstand/   (props changed)
  stable/8/lib/libtacplus/   (props changed)
  stable/8/lib/libthr/   (props changed)
  stable/8/lib/libusb/   (props changed)
  stable/8/lib/libusb/usb.h   (props changed)
  stable/8/lib/libutil/   (props changed)
  stable/8/libexec/rtld-elf/   (props changed)
  stable/8/release/   (props changed)
  stable/8/release/doc/   (props changed)
  stable/8/release/doc/en_US.ISO8859-1/hardware/   (props changed)
  stable/8/sbin/   (props changed)
  stable/8/sbin/atacontrol/   (props changed)
  stable/8/sbin/bsdlabel/   (props changed)
  stable/8/sbin/camcontrol/   (props changed)
  stable/8/sbin/ddb/   (props changed)
  stable/8/sbin/dhclient/   (props changed)
  stable/8/sbin/fsck/   (props changed)
  stable/8/sbin/geom/   (props changed)
  stable/8/sbin/ifconfig/   (props changed)
  stable/8/sbin/ipfw/   (props changed)
  stable/8/sbin/mksnap_ffs/   (props changed)
  stable/8/sbin/mount/   (props changed)
  stable/8/sbin/mount_cd9660/   (props changed)
  stable/8/sbin/mount_msdosfs/   (props changed)
  stable/8/sbin/mount_nfs/   (props changed)
  stable/8/sbin/umount/   (props changed)
  stable/8/secure/usr.bin/bdes/   (props changed)
  stable/8/share/man/man3/   (props changed)
  stable/8/share/man/man4/   (props changed)
  stable/8/share/man/man4/de.4   (props changed)
  stable/8/share/man/man5/   (props changed)
  stable/8/share/man/man7/   (props changed)
  stable/8/share/man/man8/   (props changed)
  stable/8/share/man/man9/   (props changed)
  stable/8/share/misc/   (props changed)
  stable/8/share/timedef/   (props changed)
  stable/8/share/zoneinfo/   (props changed)
  stable/8/sys/   (props changed)
  stable/8/sys/amd64/include/xen/   (props changed)
  stable/8/sys/cddl/contrib/opensolaris/   (props changed)
  stable/8/sys/contrib/dev/acpica/   (props changed)
  stable/8/sys/contrib/pf/   (props changed)
  stable/8/sys/dev/xen/xenpci/   (props changed)
  stable/8/tools/kerneldoc/subsys/   (props changed)
  stable/8/tools/regression/bin/sh/   (props changed)
  stable/8/tools/regression/lib/libc/   (props changed)
  stable/8/tools/regression/lib/msun/test-conj.t   (props changed)
  stable/8/tools/regression/poll/   (props changed)
  stable/8/tools/regression/priv/   (props changed)
  stable/8/tools/regression/usr.bin/pkill/pgrep-_g.t   (props changed)
  stable/8/tools/regression/usr.bin/pkill/pgrep-_s.t   (props changed)
  stable/8/tools/regression/usr.bin/pkill/pkill-_g.t   (props changed)
  stable/8/tools/tools/ath/common/dumpregs.h   (props changed)
  stable/8/tools/tools/ath/common/dumpregs_5210.c   (props changed)
  stable/8/tools/tools/ath/common/dumpregs_5211.c   (props changed)
  stable/8/tools/tools/ath/common/dumpregs_5212.c   (props changed)
  stable/8/tools/tools/ath/common/dumpregs_5416.c   (props changed)
  stable/8/tools/tools/termcap/termcap.pl   (props changed)
  stable/8/tools/tools/vimage/   (props changed)
  stable/8/usr.bin/calendar/   (props changed)
  stable/8/usr.bin/calendar/calendars/calendar.freebsd   (props changed)
  stable/8/usr.bin/csup/   (props changed)
  stable/8/usr.bin/find/   (props changed)
  stable/8/usr.bin/finger/   (props changed)
  stable/8/usr.bin/fstat/   (props changed)
  stable/8/usr.bin/gcore/   (props changed)
  stable/8/usr.bin/gzip/   (props changed)
  stable/8/usr.bin/kdump/   (props changed)
  stable/8/usr.bin/locale/   (props changed)
  stable/8/usr.bin/look/   (props changed)
  stable/8/usr.bin/netstat/   (props changed)
  stable/8/usr.bin/perror/   (props changed)
  stable/8/usr.bin/procstat/   (props changed)
  stable/8/usr.bin/systat/   (props changed)
  stable/8/usr.bin/unifdef/   (props changed)
  stable/8/usr.bin/vmstat/   (props changed)
  stable/8/usr.bin/w/   (props changed)
  stable/8/usr.bin/whois/   (props changed)
  stable/8/usr.sbin/   (props changed)
  stable/8/usr.sbin/Makefile   (props changed)
  stable/8/usr.sbin/acpi/   (props changed)
  stable/8/usr.sbin/arp/   (props changed)
  stable/8/usr.sbin/bsnmpd/   (props changed)
  stable/8/usr.sbin/cdcontrol/   (props changed)
  stable/8/usr.sbin/crashinfo/   (props changed)
  stable/8/usr.sbin/cron/   (props changed)
  stable/8/usr.sbin/diskinfo/   (props changed)
  stable/8/usr.sbin/dumpcis/cardinfo.h   (props changed)
  stable/8/usr.sbin/dumpcis/cis.h   (props changed)
  stable/8/usr.sbin/freebsd-update/   (props changed)
  stable/8/usr.sbin/inetd/   (props changed)
  stable/8/usr.sbin/iostat/   (props changed)
  stable/8/usr.sbin/jail/   (props changed)
  stable/8/usr.sbin/jls/   (props changed)
  stable/8/usr.sbin/lpr/   (props changed)
  stable/8/usr.sbin/makefs/ffs/ffs_bswap.c   (props changed)
  stable/8/usr.sbin/makefs/ffs/ffs_subr.c   (props changed)
  stable/8/usr.sbin/makefs/ffs/ufs_bswap.h   (props changed)
  stable/8/usr.sbin/makefs/getid.c   (props changed)
  stable/8/usr.sbin/mfiutil/mfiutil.8   (props changed)
  stable/8/usr.sbin/ndp/   (props changed)
  stable/8/usr.sbin/ntp/   (props changed)
  stable/8/usr.sbin/ppp/   (props changed)
  stable/8/usr.sbin/pstat/   (props changed)
  stable/8/usr.sbin/service/   (props changed)
  stable/8/usr.sbin/sysinstall/   (props changed)
  stable/8/usr.sbin/syslogd/   (props changed)
  stable/8/usr.sbin/traceroute6/   (props changed)
  stable/8/usr.sbin/usbconfig/   (props changed)
  stable/8/usr.sbin/wpa/   (props changed)
  stable/8/usr.sbin/zic/   (props changed)

Modified: stable/8/sys/net/if_llatbl.c
==============================================================================
--- stable/8/sys/net/if_llatbl.c	Tue Jan  5 21:14:48 2010	(r201613)
+++ stable/8/sys/net/if_llatbl.c	Tue Jan  5 22:14:55 2010	(r201614)
@@ -274,7 +274,9 @@ lla_rt_output(struct rt_msghdr *rtm, str
 #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",

Modified: stable/8/sys/net/if_llatbl.h
==============================================================================
--- stable/8/sys/net/if_llatbl.h	Tue Jan  5 21:14:48 2010	(r201613)
+++ stable/8/sys/net/if_llatbl.h	Tue Jan  5 22:14:55 2010	(r201614)
@@ -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 *);

Modified: stable/8/sys/net/if_var.h
==============================================================================
--- stable/8/sys/net/if_var.h	Tue Jan  5 21:14:48 2010	(r201613)
+++ stable/8/sys/net/if_var.h	Tue Jan  5 22:14:55 2010	(r201614)
@@ -712,6 +712,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

Modified: stable/8/sys/net/route.c
==============================================================================
--- stable/8/sys/net/route.c	Tue Jan  5 21:14:48 2010	(r201613)
+++ stable/8/sys/net/route.c	Tue Jan  5 22:14:55 2010	(r201614)
@@ -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)
@@ -1315,7 +1313,7 @@ rt_setgate(struct rtentry *rt, struct so
 	return (0);
 }
 
-static void
+void
 rt_maskedcopy(struct sockaddr *src, struct sockaddr *dst, struct sockaddr *netmask)
 {
 	register u_char *cp1 = (u_char *)src;

Modified: stable/8/sys/net/route.h
==============================================================================
--- stable/8/sys/net/route.h	Tue Jan  5 21:14:48 2010	(r201613)
+++ stable/8/sys/net/route.h	Tue Jan  5 22:14:55 2010	(r201614)
@@ -384,6 +384,7 @@ void	 rt_missmsg(int, struct rt_addrinfo
 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:

Modified: stable/8/sys/net/rtsock.c
==============================================================================
--- stable/8/sys/net/rtsock.c	Tue Jan  5 21:14:48 2010	(r201613)
+++ stable/8/sys/net/rtsock.c	Tue Jan  5 22:14:55 2010	(r201614)
@@ -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 sock
 			}
 		}
 #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);

Modified: stable/8/sys/netinet/in.c
==============================================================================
--- stable/8/sys/netinet/in.c	Tue Jan  5 21:14:48 2010	(r201613)
+++ stable/8/sys/netinet/in.c	Tue Jan  5 22:14:55 2010	(r201614)
@@ -924,9 +924,25 @@ in_ifinit(struct ifnet *ifp, struct in_i
 	/*
 	 * 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 *l
 
 
 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, co
 
 	/* 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
 		 * 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);

Modified: stable/8/sys/netinet6/in6.c
==============================================================================
--- stable/8/sys/netinet6/in6.c	Tue Jan  5 21:14:48 2010	(r201613)
+++ stable/8/sys/netinet6/in6.c	Tue Jan  5 22:14:55 2010	(r201614)
@@ -1196,8 +1196,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);
@@ -1758,6 +1762,8 @@ in6_ifinit(struct ifnet *ifp, struct in6
 		|| (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). */
@@ -2340,7 +2346,9 @@ in6_lltable_prefix_free(struct lltable *
 }
 
 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];
@@ -2408,7 +2416,7 @@ in6_lltable_lookup(struct lltable *llt, 
 		 * 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);

Modified: stable/8/sys/netinet6/nd6_rtr.c
==============================================================================
--- stable/8/sys/netinet6/nd6_rtr.c	Tue Jan  5 21:14:48 2010	(r201613)
+++ stable/8/sys/netinet6/nd6_rtr.c	Tue Jan  5 22:14:55 2010	(r201614)
@@ -1631,7 +1631,7 @@ nd6_prefix_onlink(struct nd_prefix *pr)
 	bzero(&mask6, sizeof(mask6));
 	mask6.sin6_len = sizeof(mask6);
 	mask6.sin6_addr = pr->ndpr_mask;
-	rtflags = ifa->ifa_flags | RTF_UP;
+	rtflags = (ifa->ifa_flags & ~IFA_RTSELF) | RTF_UP;
 	error = rtrequest(RTM_ADD, (struct sockaddr *)&pr->ndpr_prefix,
 	    ifa->ifa_addr, (struct sockaddr *)&mask6, rtflags, &rt);
 	if (error == 0) {

Modified: stable/8/usr.sbin/arp/arp.c
==============================================================================
--- stable/8/usr.sbin/arp/arp.c	Tue Jan  5 21:14:48 2010	(r201613)
+++ stable/8/usr.sbin/arp/arp.c	Tue Jan  5 22:14:55 2010	(r201614)
@@ -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
  */
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
Comment 4 Qing Li freebsd_committer freebsd_triage 2010-01-05 22:42:40 UTC
State Changed
From-To: open->closed

The fix has been committed.