zcip: allow our own class B range to be used for ZeroConf

169.254 may already be used by a local network. This patch allows
specifying your own IP range.

Our particular use case is a mesh network, in which the nodes partaking
were using an IP range specifically assigned for the meshing purpose.
As the LAN side of the mesh node could use 169.254, this default range
was not an option.

function                                             old     new   delta
zcip_main                                           1342    1426     +84
pick_nip                                               -      40     +40
packed_usage                                       29974   29969      -5
pick                                                  34       -     -34
------------------------------------------------------------------------------
(add/remove: 1/1 grow/shrink: 1/1 up/down: 124/-39)            Total: 85 bytes

Signed-off-by: Michel Stam <m.stam@fugro.nl>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
diff --git a/networking/zcip.c b/networking/zcip.c
index 45d1f7c..635d660 100644
--- a/networking/zcip.c
+++ b/networking/zcip.c
@@ -30,6 +30,7 @@
 //usage:     "\n	-f		Run in foreground"
 //usage:     "\n	-q		Quit after obtaining address"
 //usage:     "\n	-r 169.254.x.x	Request this address first"
+//usage:     "\n	-l x.x.0.0	Use this range instead of 169.254"
 //usage:     "\n	-v		Verbose"
 //usage:     "\n"
 //usage:     "\nWith no -q, runs continuously monitoring for ARP conflicts,"
@@ -87,6 +88,7 @@
 struct globals {
 	struct sockaddr saddr;
 	struct ether_addr eth_addr;
+	uint32_t localnet_ip;
 } FIX_ALIASING;
 #define G (*(struct globals*)&bb_common_bufsiz1)
 #define saddr    (G.saddr   )
@@ -98,14 +100,14 @@
  * Pick a random link local IP address on 169.254/16, except that
  * the first and last 256 addresses are reserved.
  */
-static uint32_t pick(void)
+static uint32_t pick_nip(void)
 {
 	unsigned tmp;
 
 	do {
 		tmp = rand() & IN_CLASSB_HOST;
 	} while (tmp > (IN_CLASSB_HOST - 0x0200));
-	return htonl((LINKLOCAL_ADDR + 0x0100) + tmp);
+	return htonl((G.localnet_ip + 0x0100) + tmp);
 }
 
 /**
@@ -197,6 +199,7 @@
 {
 	int state;
 	char *r_opt;
+	const char *l_opt = "169.254.0.0";
 	unsigned opts;
 
 	// ugly trick, but I want these zeroed in one go
@@ -231,7 +234,7 @@
 	// parse commandline: prog [options] ifname script
 	// exactly 2 args; -v accumulates and implies -f
 	opt_complementary = "=2:vv:vf";
-	opts = getopt32(argv, "fqr:v", &r_opt, &verbose);
+	opts = getopt32(argv, "fqr:l:v", &r_opt, &l_opt, &verbose);
 #if !BB_MMU
 	// on NOMMU reexec early (or else we will rerun things twice)
 	if (!FOREGROUND)
@@ -246,9 +249,18 @@
 		openlog(applet_name, 0, LOG_DAEMON);
 		logmode |= LOGMODE_SYSLOG;
 	}
+	{ // -l n.n.n.n
+		struct in_addr net;
+		if (inet_aton(l_opt, &net) == 0
+		 || (net.s_addr & htonl(IN_CLASSB_NET)) != net.s_addr
+		) {
+			bb_error_msg_and_die("invalid network address");
+		}
+		G.localnet_ip = ntohl(net.s_addr);
+	}
 	if (opts & 4) { // -r n.n.n.n
 		if (inet_aton(r_opt, &ip) == 0
-		 || (ntohl(ip.s_addr) & IN_CLASSB_NET) != LINKLOCAL_ADDR
+		 || (ntohl(ip.s_addr) & IN_CLASSB_NET) != G.localnet_ip
 		) {
 			bb_error_msg_and_die("invalid link address");
 		}
@@ -295,7 +307,7 @@
 		srand(t);
 	}
 	if (ip.s_addr == 0)
-		ip.s_addr = pick();
+		ip.s_addr = pick_nip();
 
 	// FIXME cases to handle:
 	//  - zcip already running!
@@ -433,7 +445,7 @@
 			default:
 				// Invalid, should never happen.  Restart the whole protocol.
 				state = PROBE;
-				ip.s_addr = pick();
+				ip.s_addr = pick_nip();
 				timeout_ms = 0;
 				nprobes = 0;
 				nclaims = 0;
@@ -535,7 +547,7 @@
 					}
 
 					// restart the whole protocol
-					ip.s_addr = pick();
+					ip.s_addr = pick_nip();
 					timeout_ms = 0;
 					nprobes = 0;
 					nclaims = 0;
@@ -561,7 +573,7 @@
 					run(argv, "deconfig", &ip);
 
 					// restart the whole protocol
-					ip.s_addr = pick();
+					ip.s_addr = pick_nip();
 					timeout_ms = 0;
 					nprobes = 0;
 					nclaims = 0;
@@ -571,7 +583,7 @@
 				// Invalid, should never happen.  Restart the whole protocol.
 				VDBG("invalid state -- starting over\n");
 				state = PROBE;
-				ip.s_addr = pick();
+				ip.s_addr = pick_nip();
 				timeout_ms = 0;
 				nprobes = 0;
 				nclaims = 0;