--- busybox-1.11.2-orig/procps/sysctl.c	2008-06-25 20:51:31.000000000 +0800
+++ busybox-1.11.2/procps/sysctl.c	2011-03-24 18:15:23.486759333 +0800
@@ -20,6 +20,7 @@
 static int sysctl_write_setting(const char *setting);
 static int sysctl_display_all(const char *path);
 static int sysctl_preload_file_and_exit(const char *filename);
+static void sysctl_dots_to_slashes(char *name);
 
 static const char ETC_SYSCTL_CONF[] ALIGN1 = "/etc/sysctl.conf";
 static const char PROC_SYS[] ALIGN1 = "/proc/sys/";
@@ -169,8 +170,7 @@
 	tmpname = xasprintf("%s%.*s", PROC_SYS, (int)(equals - name), name);
 	outname = xstrdup(tmpname + strlen_PROC_SYS);
 
-	while ((cptr = strchr(tmpname, '.')) != NULL)
-		*cptr = '/';
+	sysctl_dots_to_slashes(tmpname);
 
 	while ((cptr = strchr(outname, '/')) != NULL)
 		*cptr = '.';
@@ -224,8 +224,8 @@
 	tmpname = concat_path_file(PROC_SYS, name);
 	outname = xstrdup(tmpname + strlen_PROC_SYS);
 
-	while ((cptr = strchr(tmpname, '.')) != NULL)
-		*cptr = '/';
+	sysctl_dots_to_slashes(tmpname);
+	
 	while ((cptr = strchr(outname, '/')) != NULL)
 		*cptr = '.';
 
@@ -292,3 +292,48 @@
 
 	return retval;
 } /* end sysctl_display_all() */
+
+static void sysctl_dots_to_slashes(char *name)
+{
+        char *cptr, *last_good, *end;
+
+        /* Convert minimum number of '.' to '/' so that
+         * we end up with existing file's name.
+         *
+         * Example from bug 3894:
+         * net.ipv4.conf.eth0.100.mc_forwarding ->
+         * net/ipv4/conf/eth0.100/mc_forwarding
+         * NB: net/ipv4/conf/eth0/mc_forwarding *also exists*,
+         * therefore we must start from the end, and if
+         * we replaced even one . -> /, start over again,
+         * but never replace dots before the position
+         * where last replacement occurred.
+         *
+         * Another bug we later had is that
+         * net.ipv4.conf.eth0.100
+         * (without .mc_forwarding) was mishandled.
+         *
+         * To set up testing: modprobe 8021q; vconfig add eth0 100
+         */
+        end = name + strlen(name);
+        last_good = name - 1;
+        *end = '.'; /* trick the loop into trying full name too */
+
+ again:
+        cptr = end;
+        while (cptr > last_good) {
+                if (*cptr == '.') {
+                        *cptr = '\0';
+                        //bb_error_msg("trying:'%s'", name);
+                        if (access(name, F_OK) == 0) {
+                                *cptr = '/';
+                                //bb_error_msg("replaced:'%s'", name);
+                                last_good = cptr;
+                                goto again;
+                        }
+                        *cptr = '.';
+                }
+                cptr--;
+        }
+        *end = '\0';
+}
+
