Subject: sys/net/route.c:rtrequest1() from post-4.4 changes
To: None <tech-net@netbsd.org>
From: Jun-ichiro itojun Hagino <itojun@iijlab.net>
List: tech-net
Date: 01/15/2001 19:52:13
	the following patch should introduce two things from post 4.4BSD
	changes (found in BSD/OS 4.2, in UCB copyrighted portion):
	- sys/net/route.c:rtrequest1()
	- sys/net/route.c:rt_getifa()
	the idea is to pass rt_addrinfo all the way down to rtrequest1().

	if we introduce the following change, we can pass RTAX_IFP with no
	problem from routing socket.  in effect, the following command should
	now honor "-ifp" argument:
	# route add -inet6 default ::1 -ifp gif0
	at this moment we need two commands to do this.
	# route add -inet6 default ::1 
	# route change -inet6 default ::1 -ifp gif0

	does it sound good to introduce the change?

	also, we may want to change two more things:
	- change 3rd arg to ifa->ifa_rtrequest() to struct rt_addrinfo.
	  (after checking misteryous use of 3rd arg)
	- change calls to rtreqeust() to rtrequest1() as much as possible.
	  i believe i've already rewrote enough.

itojun


Index: route.c
===================================================================
RCS file: /cvsroot/kame/kame/netbsd/sys/net/route.c,v
retrieving revision 1.10
retrieving revision 1.15
diff -u -r1.10 -r1.15
--- route.c	2000/12/27 09:50:47	1.10
+++ route.c	2001/01/15 10:46:24	1.15
@@ -202,6 +202,17 @@
 				msgtype = RTM_RESOLVE;
 				goto miss;
 			}
+			/* Inform listeners of the new route */
+			bzero(&info, sizeof(info));
+			info.rti_info[RTAX_DST] = rt_key(rt);
+			info.rti_info[RTAX_NETMASK] = rt_mask(rt);
+			info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
+			if (rt->rt_ifp != NULL) {
+				info.rti_info[RTAX_IFP] = 
+				    rt->rt_ifp->if_addrlist.tqh_first->ifa_addr;
+				info.rti_info[RTAX_IFA] = rt->rt_ifa->ifa_addr;
+			}
+			rt_missmsg(RTM_ADD, &info, rt->rt_flags, 0);
 		} else
 			rt->rt_refcnt++;
 	} else {
@@ -317,10 +328,18 @@
 			 * Create new route, rather than smashing route to net.
 			 */
 		create:
+			if (rt)
+				rtfree(rt);
 			flags |=  RTF_GATEWAY | RTF_DYNAMIC;
-			error = rtrequest((int)RTM_ADD, dst, gateway,
-				    netmask, flags,
-				    (struct rtentry **)0);
+			info.rti_info[RTAX_DST] = dst;
+			info.rti_info[RTAX_GATEWAY] = gateway;
+			info.rti_info[RTAX_NETMASK] = netmask;
+			info.rti_ifa = ifa;
+			info.rti_flags = flags;
+			rt = NULL;
+			error = rtrequest1(RTM_ADD, &info, &rt);
+			if (rt != NULL)
+				flags = rt->rt_flags;
 			stat = &rtstat.rts_dynamic;
 		} else {
 			/*
@@ -420,6 +439,70 @@
 	struct sockaddr *dst, *gateway, *netmask;
 	struct rtentry **ret_nrt;
 {
+	struct rt_addrinfo info;
+
+	bzero(&info, sizeof(info));
+	info.rti_flags = flags;
+	info.rti_info[RTAX_DST] = dst;
+	info.rti_info[RTAX_GATEWAY] = gateway;
+	info.rti_info[RTAX_NETMASK] = netmask;
+	return rtrequest1(req, &info, ret_nrt);
+}
+
+/*
+ * These (questionable) definitions of apparent local variables apply
+ * to the next function.  XXXXXX!!!
+ */
+#define dst	info->rti_info[RTAX_DST]
+#define gateway	info->rti_info[RTAX_GATEWAY]
+#define netmask	info->rti_info[RTAX_NETMASK]
+#define ifaaddr	info->rti_info[RTAX_IFA]
+#define ifpaddr	info->rti_info[RTAX_IFP]
+#define flags	info->rti_flags
+
+int
+rt_getifa(info)
+	struct rt_addrinfo *info;
+{
+	struct ifaddr *ifa;
+	int error = 0;
+
+	/*
+	 * ifp may be specified by sockaddr_dl when protocol address
+	 * is ambiguous
+	 */
+	if (info->rti_ifp == NULL && ifpaddr != NULL
+	    && ifpaddr->sa_family == AF_LINK &&
+	    (ifa = ifa_ifwithnet((struct sockaddr *)ifpaddr)) != NULL)
+		info->rti_ifp = ifa->ifa_ifp;
+	if (info->rti_ifa == NULL && ifaaddr != NULL)
+		info->rti_ifa = ifa_ifwithaddr(ifaaddr);
+	if (info->rti_ifa == NULL) {
+		struct sockaddr *sa;
+
+		sa = ifaaddr != NULL ? ifaaddr :
+		    (gateway != NULL ? gateway : dst);
+		if (sa != NULL && info->rti_ifp != NULL)
+			info->rti_ifa = ifaof_ifpforaddr(sa, info->rti_ifp);
+		else if (dst != NULL && gateway != NULL)
+			info->rti_ifa = ifa_ifwithroute(flags, dst, gateway);
+		else if (sa != NULL)
+			info->rti_ifa = ifa_ifwithroute(flags, sa, sa);
+	}
+	if ((ifa = info->rti_ifa) != NULL) {
+		if (info->rti_ifp == NULL)
+			info->rti_ifp = ifa->ifa_ifp;
+	} else
+		error = ENETUNREACH;
+	return (error);
+}
+
+int
+rtrequest1(req, info, ret_nrt)
+	int req;
+	struct rt_addrinfo *info;
+	struct rtentry **ret_nrt;
+{
 	int s = splsoftnet(); int error = 0;
 	struct rtentry *rt;
 	struct radix_node *rn;
@@ -466,8 +549,9 @@
 		goto makeroute;
 
 	case RTM_ADD:
-		if ((ifa = ifa_ifwithroute(flags, dst, gateway)) == 0)
-			senderr(ENETUNREACH);
+		if (info->rti_ifa == 0 && (error = rt_getifa(info)))
+			senderr(error);
+		ifa = info->rti_ifa;
 	makeroute:
 		rt = pool_get(&rtentry_pool, PR_NOWAIT);
 		if (rt == 0)
@@ -519,6 +603,13 @@
 	return (error);
 }
 
+#undef dst
+#undef gateway
+#undef netmask
+#undef ifaaddr
+#undef ifpaddr
+#undef flags
+
 int
 rt_setgate(rt0, dst, gate)
 	struct rtentry *rt0;
@@ -599,6 +690,7 @@
 	struct sockaddr_storage deldst;
 	struct rtentry *nrt = 0;
 	int error;
+	struct rt_addrinfo info;
 
 	dst = flags & RTF_HOST ? ifa->ifa_dstaddr : ifa->ifa_addr;
 	if (cmd == RTM_DELETE) {
@@ -615,8 +707,19 @@
 							: ENETUNREACH);
 		}
 	}
-	error = rtrequest(cmd, dst, ifa->ifa_addr, ifa->ifa_netmask,
-			flags | ifa->ifa_flags, &nrt);
+	bzero(&info, sizeof(info));
+	info.rti_ifa = ifa;
+	info.rti_flags = flags | ifa->ifa_flags;
+	info.rti_info[RTAX_DST] = dst;
+	info.rti_info[RTAX_GATEWAY] = ifa->ifa_addr;
+	/*
+	 * XXX here, it seems that we are assuming that ifa_netmask is NULL
+	 * for RTF_HOST.  bsdi4 passes NULL explicitly (via intermediate
+	 * variable) when RTF_HOST is 1.  still not sure if i can safely
+	 * change it to meet bsdi4 behavior.
+	 */
+	info.rti_info[RTAX_NETMASK] = ifa->ifa_netmask;
+	error = rtrequest1(cmd, &info, &nrt);
 	if (cmd == RTM_DELETE && error == 0 && (rt = nrt)) {
 		rt_newaddrmsg(cmd, ifa, error, nrt);
 		if (rt->rt_refcnt <= 0) {
Index: route.h
===================================================================
RCS file: /cvsroot/kame/kame/netbsd/sys/net/route.h,v
retrieving revision 1.9
retrieving revision 1.11
diff -u -r1.9 -r1.11
--- route.h	2000/12/27 09:51:18	1.9
+++ route.h	2001/01/15 09:47:14	1.11
@@ -240,6 +240,10 @@
 struct rt_addrinfo {
 	int	rti_addrs;
 	struct	sockaddr *rti_info[RTAX_MAX];
+	int	rti_flags;
+	struct	ifaddr *rti_ifa;
+	struct	ifnet *rti_ifp;
+	struct	rt_msghdr *rti_rtm;
 };
 
 struct route_cb {
@@ -319,12 +323,14 @@
 struct rtentry *
 	 rtalloc1 __P((struct sockaddr *, int));
 void	 rtfree __P((struct rtentry *));
+int	 rt_getifa __P((struct rt_addrinfo *));
 int	 rtinit __P((struct ifaddr *, int, int));
 int	 rtioctl __P((u_long, caddr_t, struct proc *));
 void	 rtredirect __P((struct sockaddr *, struct sockaddr *,
 	    struct sockaddr *, int, struct sockaddr *, struct rtentry **));
 int	 rtrequest __P((int, struct sockaddr *,
 	    struct sockaddr *, struct sockaddr *, int, struct rtentry **));
+int	 rtrequest1 __P((int, struct rt_addrinfo *, struct rtentry **));
 
 #ifdef MIP6
 void	rt_mip6msg __P((int, struct ifnet *, struct rtentry *));
Index: rtsock.c
===================================================================
RCS file: /cvsroot/kame/kame/netbsd/sys/net/rtsock.c,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -r1.10 -r1.11
--- rtsock.c	2000/12/02 07:30:42	1.10
+++ rtsock.c	2001/01/15 09:47:14	1.11
@@ -221,7 +221,6 @@
 	so = va_arg(ap, struct socket *);
 	va_end(ap);
 
-	bzero(&info, sizeof(info));
 #define senderr(e) do { error = e; goto flush;} while (0)
 	if (m == 0 || ((m->m_len < sizeof(int32_t)) &&
 	   (m = m_pullup(m, sizeof(int32_t))) == 0))
@@ -245,8 +244,10 @@
 		senderr(EPROTONOSUPPORT);
 	}
 	rtm->rtm_pid = curproc->p_pid;
+	bzero(&info, sizeof(info));
 	info.rti_addrs = rtm->rtm_addrs;
 	rt_xaddrs((caddr_t)(rtm + 1), len + (caddr_t)rtm, &info);
+	info.rti_flags = rtm->rtm_flags;
 	if (dst == 0 || (dst->sa_family >= AF_MAX))
 		senderr(EINVAL);
 	if (gate != 0 && (gate->sa_family >= AF_MAX))
@@ -273,8 +274,7 @@
 	case RTM_ADD:
 		if (gate == 0)
 			senderr(EINVAL);
-		error = rtrequest(RTM_ADD, dst, gate, netmask,
-		    rtm->rtm_flags, &saved_nrt);
+		error = rtrequest1(rtm->rtm_type, &info, &saved_nrt);
 		if (error == 0 && saved_nrt) {
 			rt_setmetrics(rtm->rtm_inits,
 			    &rtm->rtm_rmx, &saved_nrt->rt_rmx);
@@ -284,8 +284,7 @@
 		break;
 
 	case RTM_DELETE:
-		error = rtrequest(RTM_DELETE, dst, gate, netmask,
-		    rtm->rtm_flags, &saved_nrt);
+		error = rtrequest1(rtm->rtm_type, &info, &saved_nrt);
 		if (error == 0) {
 			(rt = saved_nrt)->rt_refcnt++;
 			goto report;
@@ -345,6 +344,13 @@
 			break;
 
 		case RTM_CHANGE:
+			/*
+			 * new gateway could require new ifaddr, ifp;
+			 * flags may also be different; ifp may be specified
+			 * by ll sockaddr when protocol address is ambiguous
+			 */
+			if ((error = rt_getifa(&info)) != 0)
+				senderr(error);
 			if (gate && rt_setgate(rt, rt_key(rt), gate))
 				senderr(EDQUOT);
 			/* new gateway could require new ifaddr, ifp;