patch-2.1.89 linux/net/ipv4/fib_semantics.c

Next file: linux/net/ipv4/icmp.c
Previous file: linux/net/ipv4/fib_rules.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.88/linux/net/ipv4/fib_semantics.c linux/net/ipv4/fib_semantics.c
@@ -178,11 +178,37 @@
 	return 0;
 }
 
+#ifndef CONFIG_RTNL_OLD_IFINFO
+static int
+fib_count_nexthops(struct rtattr *rta)
+{
+	int nhs = 0;
+	struct rtnexthop *nhp = RTA_DATA(rta);
+	int nhlen = RTA_PAYLOAD(rta);
+
+	while (nhlen >= sizeof(struct rtnexthop)) {
+		if ((nhlen -= nhp->rtnh_len) < 0)
+			return 0;
+		nhs++;
+		nhp = RTNH_NEXT(nhp);
+	};
+	return nhs;
+}
+#endif
+
+#ifdef CONFIG_RTNL_OLD_IFINFO
 static int
 fib_get_nhs(struct fib_info *fi, const struct nlmsghdr *nlh, const struct rtmsg *r)
 {
 	struct rtnexthop *nhp = RTM_RTNH(r);
 	int nhlen = RTM_NHLEN(nlh, r);
+#else
+static int
+fib_get_nhs(struct fib_info *fi, const struct rtattr *rta, const struct rtmsg *r)
+{
+	struct rtnexthop *nhp = RTA_DATA(rta);
+	int nhlen = RTA_PAYLOAD(rta);
+#endif
 
 	change_nexthops(fi) {
 		int attrlen = nhlen - sizeof(struct rtnexthop);
@@ -216,11 +242,18 @@
 	}
 
 #ifdef CONFIG_IP_ROUTE_MULTIPATH
+#ifdef CONFIG_RTNL_OLD_IFINFO
 	if (r->rtm_nhs == 0)
 		return 0;
 
 	nhp = RTM_RTNH(r);
 	nhlen = RTM_NHLEN(nlh, r);
+#else
+	if (rta->rta_mp == NULL)
+		return 0;
+	nhp = RTA_DATA(rta->rta_mp);
+	nhlen = RTA_PAYLOAD(rta->rta_mp);
+#endif
 	
 	for_nexthops(fi) {
 		int attrlen = nhlen - sizeof(struct rtnexthop);
@@ -352,16 +385,28 @@
 	struct fib_info *fi = NULL;
 	struct fib_info *ofi;
 #ifdef CONFIG_IP_ROUTE_MULTIPATH
+#ifdef CONFIG_RTNL_OLD_IFINFO
 	int nhs = r->rtm_nhs ? : 1;
 #else
+	int nhs = 1;
+#endif
+#else
 	const int nhs = 1;
 #endif
 
 	/* Fast check to catch the most weird cases */
-	if (fib_props[r->rtm_type].scope > r->rtm_scope) {
-		printk("Einval 1\n");
+	if (fib_props[r->rtm_type].scope > r->rtm_scope)
 		goto err_inval;
+
+#ifdef CONFIG_IP_ROUTE_MULTIPATH
+#ifndef CONFIG_RTNL_OLD_IFINFO
+	if (rta->rta_mp) {
+		nhs = fib_count_nexthops(rta->rta_mp);
+		if (nhs == 0)
+			goto err_inval;
 	}
+#endif
+#endif
 
 	fi = kmalloc(sizeof(*fi)+nhs*sizeof(struct fib_nh), GFP_KERNEL);
 	err = -ENOBUFS;
@@ -372,18 +417,43 @@
 	fi->fib_protocol = r->rtm_protocol;
 	fi->fib_nhs = nhs;
 	fi->fib_flags = r->rtm_flags;
+#ifdef CONFIG_RTNL_OLD_IFINFO
 	if (rta->rta_mtu)
 		fi->fib_mtu = *rta->rta_mtu;
 	if (rta->rta_rtt)
 		fi->fib_rtt = *rta->rta_rtt;
 	if (rta->rta_window)
 		fi->fib_window = *rta->rta_window;
+#else
+	if (rta->rta_mx) {
+		int attrlen = RTA_PAYLOAD(rta->rta_mx);
+		struct rtattr *attr = RTA_DATA(rta->rta_mx);
+
+		while (RTA_OK(attr, attrlen)) {
+			unsigned flavor = attr->rta_type;
+			if (flavor) {
+				if (flavor > FIB_MAX_METRICS)
+					goto failure;
+				fi->fib_metrics[flavor-1] = *(unsigned*)RTA_DATA(attr);
+			}
+			attr = RTA_NEXT(attr, attrlen);
+		}
+	}
+#endif
 	if (rta->rta_prefsrc)
 		memcpy(&fi->fib_prefsrc, rta->rta_prefsrc, 4);
 
+#ifndef CONFIG_RTNL_OLD_IFINFO
+	if (rta->rta_mp) {
+#else
 	if (r->rtm_nhs) {
+#endif
 #ifdef CONFIG_IP_ROUTE_MULTIPATH
+#ifdef CONFIG_RTNL_OLD_IFINFO
 		if ((err = fib_get_nhs(fi, nlh, r)) != 0)
+#else
+		if ((err = fib_get_nhs(fi, rta->rta_mp, r)) != 0)
+#endif
 			goto failure;
 		if (rta->rta_oif && fi->fib_nh->nh_oif != *rta->rta_oif)
 			goto err_inval;
@@ -414,7 +484,11 @@
 #endif
 
 	if (fib_props[r->rtm_type].error) {
+#ifndef CONFIG_RTNL_OLD_IFINFO
+		if (rta->rta_gw || rta->rta_oif || rta->rta_mp)
+#else
 		if (rta->rta_gw || rta->rta_oif || r->rtm_nhs)
+#endif
 			goto err_inval;
 		goto link_it;
 	}
@@ -550,7 +624,9 @@
 	struct rtmsg *rtm;
 	struct nlmsghdr  *nlh;
 	unsigned char	 *b = skb->tail;
+#ifdef CONFIG_RTNL_OLD_IFINFO
 	unsigned char 	 *o;
+#endif
 
 	nlh = NLMSG_PUT(skb, pid, seq, event, sizeof(*rtm));
 	rtm = NLMSG_DATA(nlh);
@@ -562,18 +638,33 @@
 	rtm->rtm_type = type;
 	rtm->rtm_flags = fi->fib_flags;
 	rtm->rtm_scope = scope;
+#ifdef CONFIG_RTNL_OLD_IFINFO
 	rtm->rtm_nhs = 0;
 
 	o = skb->tail;
+#endif
 	if (rtm->rtm_dst_len)
 		RTA_PUT(skb, RTA_DST, 4, dst);
 	rtm->rtm_protocol = fi->fib_protocol;
+#ifdef CONFIG_RTNL_OLD_IFINFO
 	if (fi->fib_mtu)
 		RTA_PUT(skb, RTA_MTU, sizeof(unsigned), &fi->fib_mtu);
 	if (fi->fib_window)
 		RTA_PUT(skb, RTA_WINDOW, sizeof(unsigned), &fi->fib_window);
 	if (fi->fib_rtt)
 		RTA_PUT(skb, RTA_RTT, sizeof(unsigned), &fi->fib_rtt);
+#else
+	if (fi->fib_mtu || fi->fib_window || fi->fib_rtt) {
+		int i;
+		struct rtattr *mx = (struct rtattr *)skb->tail;
+		RTA_PUT(skb, RTA_METRICS, 0, NULL);
+		for (i=0; i<FIB_MAX_METRICS; i++) {
+			if (fi->fib_metrics[i])
+				RTA_PUT(skb, i+1, sizeof(unsigned), fi->fib_metrics + i);
+		}
+		mx->rta_len = skb->tail - (u8*)mx;
+	}
+#endif
 	if (fi->fib_prefsrc)
 		RTA_PUT(skb, RTA_PREFSRC, 4, &fi->fib_prefsrc);
 	if (fi->fib_nhs == 1) {
@@ -582,10 +673,18 @@
 		if (fi->fib_nh->nh_oif)
 			RTA_PUT(skb, RTA_OIF, sizeof(int), &fi->fib_nh->nh_oif);
 	}
+#ifdef CONFIG_RTNL_OLD_IFINFO
 	rtm->rtm_optlen = skb->tail - o;
+#endif
 #ifdef CONFIG_IP_ROUTE_MULTIPATH
 	if (fi->fib_nhs > 1) {
 		struct rtnexthop *nhp;
+#ifndef CONFIG_RTNL_OLD_IFINFO
+		struct rtattr *mp_head;
+		if (skb_tailroom(skb) <= RTA_SPACE(0))
+			goto rtattr_failure;
+		mp_head = (struct rtattr*)skb_put(skb, RTA_SPACE(0));
+#endif
 		for_nexthops(fi) {
 			if (skb_tailroom(skb) < RTA_ALIGN(RTA_ALIGN(sizeof(*nhp)) + 4))
 				goto rtattr_failure;
@@ -596,8 +695,14 @@
 			if (nh->nh_gw)
 				RTA_PUT(skb, RTA_GATEWAY, 4, &nh->nh_gw);
 			nhp->rtnh_len = skb->tail - (unsigned char*)nhp;
+#ifdef CONFIG_RTNL_OLD_IFINFO
 			rtm->rtm_nhs++;
+#endif
 		} endfor_nexthops(fi);
+#ifndef CONFIG_RTNL_OLD_IFINFO
+		mp_head->rta_type = RTA_MULTIPATH;
+		mp_head->rta_len = skb->tail - (u8*)mp_head;
+#endif
 	}
 #endif
 	nlh->nlmsg_len = skb->tail - b;
@@ -605,7 +710,7 @@
 
 nlmsg_failure:
 rtattr_failure:
-	skb_put(skb, b - skb->tail);
+	skb_trim(skb, b - skb->data);
 	return -1;
 }
 
@@ -655,10 +760,8 @@
 		nl->nlmsg_flags = 0;
 	} else {
 		nl->nlmsg_type = RTM_NEWROUTE;
-		nl->nlmsg_flags = NLM_F_CREATE;
+		nl->nlmsg_flags = NLM_F_REQUEST|NLM_F_CREATE;
 		rtm->rtm_protocol = RTPROT_BOOT;
-		if (plen != 0)
-			nl->nlmsg_flags |= NLM_F_REPLACE;
 	}
 
 	rtm->rtm_dst_len = plen;
@@ -711,7 +814,7 @@
 	ptr = &((struct sockaddr_in*)&r->rt_gateway)->sin_addr.s_addr;
 	if (r->rt_gateway.sa_family == AF_INET && *ptr) {
 		rta->rta_gw = ptr;
-		if (r->rt_flags&RTF_GATEWAY)
+		if (r->rt_flags&RTF_GATEWAY && inet_addr_type(*ptr) == RTN_UNICAST)
 			rtm->rtm_scope = RT_SCOPE_UNIVERSE;
 	}
 
@@ -721,6 +824,7 @@
 	if (r->rt_flags&RTF_GATEWAY && rta->rta_gw == NULL)
 		return -EINVAL;
 
+#ifdef CONFIG_RTNL_OLD_IFINFO
 	/* Ugly conversion from rtentry types to unsigned */
 
 	if (r->rt_flags&RTF_IRTT) {
@@ -737,6 +841,10 @@
 		if (sizeof(*rta->rta_mtu) != sizeof(r->rt_mtu))
 			*rta->rta_mtu = r->rt_mtu;
 	}
+#else
+	if (r->rt_flags&(RTF_MTU|RTF_WINDOW|RTF_IRTT))
+	    printk(KERN_DEBUG "SIOCRT*: mtu/window/irtt are not implemnted.\n");
+#endif
 	return 0;
 }
 

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov