changeset 12915:2794a0c9cce1

6965774 bound the interface index in IP to [1,65535]
author Darren Reed <Darren.Reed@Oracle.COM>
date Fri, 23 Jul 2010 18:03:48 -0700
parents 3bb859a7330c
children aab2c5dd2abc
files usr/src/uts/common/inet/ip/ip_if.c usr/src/uts/common/net/if.h
diffstat 2 files changed, 32 insertions(+), 9 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/uts/common/inet/ip/ip_if.c	Fri Jul 23 17:34:02 2010 -0700
+++ b/usr/src/uts/common/inet/ip/ip_if.c	Fri Jul 23 18:03:48 2010 -0700
@@ -3538,34 +3538,51 @@
 	    &index, NULL) != NULL);
 }
 
-/* Pick a unique ifindex */
+/*
+ * Pick a unique ifindex.
+ * When the index counter passes IF_INDEX_MAX for the first time, the wrap
+ * flag is set so that next time time ip_assign_ifindex() is called, it
+ * falls through and resets the index counter back to 1, the minimum value
+ * for the interface index. The logic below assumes that ips_ill_index
+ * can hold a value of IF_INDEX_MAX+1 without there being any loss
+ * (i.e. reset back to 0.)
+ */
 boolean_t
 ip_assign_ifindex(uint_t *indexp, ip_stack_t *ipst)
 {
-	uint_t starting_index;
+	uint_t loops;
 
 	if (!ipst->ips_ill_index_wrap) {
 		*indexp = ipst->ips_ill_index++;
-		if (ipst->ips_ill_index == 0) {
-			/* Reached the uint_t limit Next time wrap  */
+		if (ipst->ips_ill_index > IF_INDEX_MAX) {
+			/*
+			 * Reached the maximum ifindex value, set the wrap
+			 * flag to indicate that it is no longer possible
+			 * to assume that a given index is unallocated.
+			 */
 			ipst->ips_ill_index_wrap = B_TRUE;
 		}
 		return (B_TRUE);
 	}
 
+	if (ipst->ips_ill_index > IF_INDEX_MAX)
+		ipst->ips_ill_index = 1;
+
 	/*
 	 * Start reusing unused indexes. Note that we hold the ill_g_lock
 	 * at this point and don't want to call any function that attempts
 	 * to get the lock again.
 	 */
-	starting_index = ipst->ips_ill_index++;
-	for (; ipst->ips_ill_index != starting_index; ipst->ips_ill_index++) {
-		if (ipst->ips_ill_index != 0 &&
-		    !phyint_exists(ipst->ips_ill_index, ipst)) {
+	for (loops = IF_INDEX_MAX; loops > 0; loops--) {
+		if (!phyint_exists(ipst->ips_ill_index, ipst)) {
 			/* found unused index - use it */
 			*indexp = ipst->ips_ill_index;
 			return (B_TRUE);
 		}
+
+		ipst->ips_ill_index++;
+		if (ipst->ips_ill_index > IF_INDEX_MAX)
+			ipst->ips_ill_index = 1;
 	}
 
 	/*
@@ -15957,7 +15974,7 @@
 	 */
 	ill = ipif->ipif_ill;
 	phyi = ill->ill_phyint;
-	if (ipif->ipif_id != 0 || index == 0) {
+	if (ipif->ipif_id != 0 || index == 0 || index > IF_INDEX_MAX) {
 		return (EINVAL);
 	}
 
--- a/usr/src/uts/common/net/if.h	Fri Jul 23 17:34:02 2010 -0700
+++ b/usr/src/uts/common/net/if.h	Fri Jul 23 18:03:48 2010 -0700
@@ -720,6 +720,12 @@
 extern	void			if_freenameindex(struct if_nameindex *);
 
 #define	IF_NAMESIZE	_LIFNAMSIZ
+/*
+ * If changing IF_MAX_INDEX to a value greater than UINT16_MAX, check if
+ * struct sockaddr_dl needs to be modified as the interface index is placed
+ * in this structure by the kernel.
+ */
+#define	IF_INDEX_MAX	UINT16_MAX
 
 #ifdef	__cplusplus
 }