udhcpc: get rid of client_data.fqdn field

function                                             old     new   delta
attach_option                                        253     276     +23
udhcpc_main                                         2582    2588      +6
udhcpc6_main                                        2579    2571      -8
add_client_options                                   175     158     -17
udhcp_insert_new_option                              169     138     -31
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 2/3 up/down: 29/-56)            Total: -27 bytes

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
diff --git a/networking/udhcp/common.c b/networking/udhcp/common.c
index 7929950..b325c41 100644
--- a/networking/udhcp/common.c
+++ b/networking/udhcp/common.c
@@ -424,7 +424,6 @@
 void* FAST_FUNC udhcp_insert_new_option(
 		struct option_set **opt_list,
 		unsigned code,
-		const void *buffer,
 		unsigned length,
 		bool dhcpv6)
 {
@@ -434,17 +433,15 @@
 	log2("attaching option %02x to list", code);
 	new = xmalloc(sizeof(*new));
 	if (!dhcpv6) {
-		new->data = xmalloc(length + OPT_DATA);
+		new->data = xzalloc(length + OPT_DATA);
 		new->data[OPT_CODE] = code;
 		new->data[OPT_LEN] = length;
-		memcpy(new->data + OPT_DATA, buffer, length);
 	} else {
-		new->data = xmalloc(length + D6_OPT_DATA);
+		new->data = xzalloc(length + D6_OPT_DATA);
 		new->data[D6_OPT_CODE] = code >> 8;
 		new->data[D6_OPT_CODE + 1] = code & 0xff;
 		new->data[D6_OPT_LEN] = length >> 8;
 		new->data[D6_OPT_LEN + 1] = length & 0xff;
-		memcpy(new->data + D6_OPT_DATA, buffer,	length);
 	}
 
 	curr = opt_list;
@@ -498,7 +495,11 @@
 	existing = udhcp_find_option(*opt_list, optflag->code);
 	if (!existing) {
 		/* make a new option */
-		udhcp_insert_new_option(opt_list, optflag->code, buffer, length, dhcpv6);
+		uint8_t *p = udhcp_insert_new_option(opt_list, optflag->code, length, dhcpv6);
+		if (!dhcpv6)
+			memcpy(p + OPT_DATA, buffer, length);
+		else
+			memcpy(p + D6_OPT_DATA, buffer, length);
 		goto ret;
 	}
 
diff --git a/networking/udhcp/common.h b/networking/udhcp/common.h
index e5af628..48a2379 100644
--- a/networking/udhcp/common.h
+++ b/networking/udhcp/common.h
@@ -321,12 +321,11 @@
 int FAST_FUNC udhcp_str2nip(const char *str, void *arg);
 
 #if !ENABLE_UDHCPC6
-#define udhcp_insert_new_option(opt_list, code, buffer, length, dhcpv6) \
-	udhcp_insert_new_option(opt_list, code, buffer, length)
+#define udhcp_insert_new_option(opt_list, code, length, dhcpv6) \
+	udhcp_insert_new_option(opt_list, code, length)
 #endif
 void* FAST_FUNC udhcp_insert_new_option(struct option_set **opt_list,
 		unsigned code,
-		const void *buffer,
 		unsigned length,
 		bool dhcpv6);
 
diff --git a/networking/udhcp/d6_dhcpc.c b/networking/udhcp/d6_dhcpc.c
index 3fd1fa7..c68dc8c 100644
--- a/networking/udhcp/d6_dhcpc.c
+++ b/networking/udhcp/d6_dhcpc.c
@@ -1111,17 +1111,6 @@
 	client_data.state = RELEASED;
 }
 
-///static uint8_t* alloc_dhcp_option(int code, const char *str, int extra)
-///{
-///	uint8_t *storage;
-///	int len = strnlen(str, 255);
-///	storage = xzalloc(len + extra + OPT_DATA);
-///	storage[OPT_CODE] = code;
-///	storage[OPT_LEN] = len + extra;
-///	memcpy(storage + extra + OPT_DATA, str, len);
-///	return storage;
-///}
-
 #if BB_MMU
 static void client_background(void)
 {
@@ -1283,23 +1272,24 @@
 		free(optstr);
 	}
 
-	if (d6_read_interface(client_data.interface,
-			&client_data.ifindex,
-			&client6_data.ll_ip6,
-			client_data_client_mac)
-	) {
-		return 1;
-	}
-
 	clientid_mac_ptr = NULL;
 	if (!udhcp_find_option(client_data.options, D6_OPT_CLIENTID)) {
 		/* not set, set the default client ID */
-		client_data.clientid[1] = 3; /* DUID-LL */
-		client_data.clientid[3] = 1; /* ethernet */
 		clientid_mac_ptr = udhcp_insert_new_option(
 				&client_data.options, D6_OPT_CLIENTID,
-				client_data.clientid, 2+2 + 6, /*dhcp6:*/ 1);
-		clientid_mac_ptr += 2+2 + 2+2; /* skip option code, len, DUID-LL, ethernet */
+				2+2 + 6, /*dhcp6:*/ 1);
+		clientid_mac_ptr += 2+2; /* skip option code, len */
+		clientid_mac_ptr[1] = 3; /* DUID-LL */
+		clientid_mac_ptr[3] = 1; /* type: ethernet */
+		clientid_mac_ptr += 2+2; /* skip DUID-LL, ethernet */
+	}
+
+	if (d6_read_interface(client_data.interface,
+			&client_data.ifindex,
+			&client6_data.ll_ip6,
+			client_data.client_mac)
+	) {
+		return 1;
 	}
 
 #if !BB_MMU
@@ -1386,13 +1376,13 @@
 			if (d6_read_interface(client_data.interface,
 					&client_data.ifindex,
 					&client6_data.ll_ip6,
-					client_data_client_mac)
+					client_data.client_mac)
 			) {
 				goto ret0; /* iface is gone? */
 			}
 
 			if (clientid_mac_ptr)
-				memcpy(clientid_mac_ptr, client_data_client_mac, 6);
+				memcpy(clientid_mac_ptr, client_data.client_mac, 6);
 
 			switch (client_data.state) {
 			case INIT_SELECTING:
diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c
index 16228f0..ab669d2 100644
--- a/networking/udhcp/dhcpc.c
+++ b/networking/udhcp/dhcpc.c
@@ -609,7 +609,7 @@
 	secs = client_data.last_secs - client_data.first_secs;
 	packet->secs = (secs < 0xffff) ? htons(secs) : 0xffff;
 
-	memcpy(packet->chaddr, client_data_client_mac, 6);
+	memcpy(packet->chaddr, client_data.client_mac, 6);
 }
 
 static void add_client_options(struct dhcp_packet *packet)
@@ -635,9 +635,6 @@
 		packet->options[end + OPT_DATA + len] = DHCP_END;
 	}
 
-	if (client_data.fqdn)
-		udhcp_add_binary_option(packet, client_data.fqdn);
-
 	/* Request broadcast replies if we have no IP addr */
 	if ((option_mask32 & OPT_B) && packet->ciaddr == 0)
 		packet->flags |= htons(BROADCAST_FLAG);
@@ -715,7 +712,6 @@
 		udhcp_add_simple_option(&packet, DHCP_REQUESTED_IP, requested);
 
 	/* Add options: maxsize,
-	 * optionally: fqdn, client-id,
 	 * "param req" option according to -O, options specified with -x
 	 */
 	add_client_options(&packet);
@@ -759,7 +755,6 @@
 	udhcp_add_simple_option(&packet, DHCP_SERVER_ID, server);
 
 	/* Add options: maxsize,
-	 * optionally: fqdn, client-id,
 	 * "param req" option according to -O, and options specified with -x
 	 */
 	add_client_options(&packet);
@@ -804,7 +799,6 @@
 	packet.ciaddr = ciaddr;
 
 	/* Add options: maxsize,
-	 * optionally: fqdn, client-id,
 	 * "param req" option according to -O, and options specified with -x
 	 */
 	add_client_options(&packet);
@@ -1154,17 +1148,6 @@
 	client_data.state = RELEASED;
 }
 
-static uint8_t* alloc_dhcp_option(int code, const char *str, int extra)
-{
-	uint8_t *storage;
-	int len = strnlen(str, 255);
-	storage = xzalloc(len + extra + OPT_DATA);
-	storage[OPT_CODE] = code;
-	storage[OPT_LEN] = len + extra;
-	memcpy(storage + extra + OPT_DATA, str, len);
-	return storage;
-}
-
 #if BB_MMU
 static void client_background(void)
 {
@@ -1284,8 +1267,13 @@
 		IF_UDHCP_VERBOSE(, &dhcp_verbose)
 	);
 	if (opt & OPT_F) {
+		char *p;
+		unsigned len;
 		/* FQDN option format: [0x51][len][flags][0][0]<fqdn> */
-		client_data.fqdn = alloc_dhcp_option(DHCP_FQDN, str_F, 3);
+		len = strlen(str_F);
+		p = udhcp_insert_new_option(
+				&client_data.options, DHCP_FQDN,
+				len + 3, /*dhcp6:*/ 0);
 		/* Flag bits: 0000NEOS
 		 * S: 1 = Client requests server to update A RR in DNS as well as PTR
 		 * O: 1 = Server indicates to client that DNS has been updated regardless
@@ -1294,9 +1282,10 @@
 		 * N: 1 = Client requests server to not update DNS (S must be 0 then)
 		 * Two [0] bytes which follow are deprecated and must be 0.
 		 */
-		client_data.fqdn[OPT_DATA + 0] = 0x1;
-		/*client_data.fqdn[OPT_DATA + 1] = 0; - xzalloc did it */
-		/*client_data.fqdn[OPT_DATA + 2] = 0; */
+		p[OPT_DATA + 0] = 0x1;
+		/*p[OPT_DATA + 1] = 0; - xzalloc did it */
+		/*p[OPT_DATA + 2] = 0; */
+		memcpy(p + OPT_DATA + 3, str_F, len); /* do not store NUL byte */
 	}
 	if (opt & OPT_r)
 		requested_ip = inet_addr(str_r);
@@ -1333,31 +1322,35 @@
 		free(optstr);
 	}
 	if (str_V[0] != '\0') {
+		char *p;
+		unsigned len;
 		//msg added 2021-06
 		bb_error_msg("option -V VENDOR is deprecated, use -x vendor:VENDOR");
-		udhcp_insert_new_option(
+		len = strlen(str_V);
+		p = udhcp_insert_new_option(
 				&client_data.options, DHCP_VENDOR,
-				str_V, strlen(str_V), /*dhcp6:*/ 0);
+				len, /*dhcp6:*/ 0);
+		memcpy(p + OPT_DATA, str_V, len); /* do not store NUL byte */
+	}
+
+	clientid_mac_ptr = NULL;
+	if (!(opt & OPT_C) && !udhcp_find_option(client_data.options, DHCP_CLIENT_ID)) {
+		/* not suppressed and not set, create default client ID */
+		clientid_mac_ptr = udhcp_insert_new_option(
+				&client_data.options, DHCP_CLIENT_ID,
+				1 + 6, /*dhcp6:*/ 0);
+		clientid_mac_ptr[OPT_DATA] = 1; /* type: ethernet */
+		clientid_mac_ptr += OPT_DATA + 1; /* skip option code, len, ethernet */
 	}
 
 	if (udhcp_read_interface(client_data.interface,
 			&client_data.ifindex,
 			NULL,
-			client_data_client_mac)
+			client_data.client_mac)
 	) {
 		return 1;
 	}
 
-	clientid_mac_ptr = NULL;
-	if (!(opt & OPT_C) && !udhcp_find_option(client_data.options, DHCP_CLIENT_ID)) {
-		/* not suppressed and not set, set the default client ID */
-		client_data_client_mac[-1] = 1; /* type: ethernet */
-		clientid_mac_ptr = udhcp_insert_new_option(
-				&client_data.options, DHCP_CLIENT_ID,
-				client_data_client_mac - 1, 1 + 6, /*dhcp6:*/ 0);
-		clientid_mac_ptr += 3; /* skip option code, len, ethernet */
-	}
-
 #if !BB_MMU
 	/* on NOMMU reexec (i.e., background) early */
 	if (!(opt & OPT_f)) {
@@ -1443,12 +1436,12 @@
 			if (udhcp_read_interface(client_data.interface,
 					&client_data.ifindex,
 					NULL,
-					client_data_client_mac)
+					client_data.client_mac)
 			) {
 				goto ret0; /* iface is gone? */
 			}
 			if (clientid_mac_ptr)
-				memcpy(clientid_mac_ptr, client_data_client_mac, 6);
+				memcpy(clientid_mac_ptr, client_data.client_mac, 6);
 
 			switch (client_data.state) {
 			case INIT_SELECTING:
@@ -1643,7 +1636,7 @@
 
 		/* Ignore packets that aren't for us */
 		if (packet.hlen != 6
-		 || memcmp(packet.chaddr, client_data_client_mac, 6) != 0
+		 || memcmp(packet.chaddr, client_data.client_mac, 6) != 0
 		) {
 //FIXME: need to also check that last 10 bytes are zero
 			log1("chaddr does not match%s", ", ignoring packet"); // log2?
@@ -1755,7 +1748,7 @@
 					if (!arpping(requested_ip,
 							NULL,
 							(uint32_t) 0,
-							client_data_client_mac,
+							client_data.client_mac,
 							client_data.interface,
 							arpping_ms)
 					) {
diff --git a/networking/udhcp/dhcpc.h b/networking/udhcp/dhcpc.h
index 5c71096..cd9ead6 100644
--- a/networking/udhcp/dhcpc.h
+++ b/networking/udhcp/dhcpc.h
@@ -8,8 +8,7 @@
 PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN
 
 struct client_data_t {
-	uint8_t clientid[2+2 + 6];      /* Our mac address (prefixed by padding used for client-id) */
-#define client_data_client_mac (client_data.clientid + 2+2)
+	uint8_t client_mac[6];          /* Our mac address */
 	IF_FEATURE_UDHCP_PORT(uint16_t port;)
 	int ifindex;                    /* Index number of the interface to use */
 	uint8_t opt_mask[256 / 8];      /* Bitmask of options to send (-O option) */
@@ -18,7 +17,6 @@
 	char *pidfile;                  /* Optionally store the process ID */
 	const char *script;             /* User script to run at dhcp events */
 	struct option_set *options;     /* list of DHCP options to send to server */
-	uint8_t *fqdn;                  /* Optional fully qualified domain name to use */
 	llist_t *envp;                  /* list of DHCP options used for env vars */
 
 	unsigned first_secs;