udhcpc: fix 6rd option formatting (was using 4 more bytes than there is)

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c
index d1e40ee..d9269f2 100644
--- a/networking/udhcp/dhcpc.c
+++ b/networking/udhcp/dhcpc.c
@@ -161,8 +161,8 @@
 	int len, type, optlen;
 	char *dest, *ret;
 
-	/* option points to OPT_DATA, need to go back and get OPT_LEN */
-	len = option[OPT_LEN - OPT_DATA];
+	/* option points to OPT_DATA, need to go back to get OPT_LEN */
+	len = option[-OPT_DATA + OPT_LEN];
 
 	type = optflag->flags & OPTION_TYPE_MASK;
 	optlen = dhcp_option_lengths[type];
@@ -252,39 +252,29 @@
 
 			return ret;
 		}
-		case OPTION_6RD: {
+		case OPTION_6RD:
 			/* Option binary format (see RFC 5969):
-			 * 0                   1                   2                   3
-			 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+			 *  0                   1                   2                   3
+			 *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
 			 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 			 * |  OPTION_6RD   | option-length |  IPv4MaskLen  |  6rdPrefixLen |
 			 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-			 * |                                                               |
 			 * |                           6rdPrefix                           |
-			 * |                          (16 octets)                          |
-			 * |                                                               |
-			 * |                                                               |
-			 * |                                                               |
+			 * ...                        (16 octets)                        ...
 			 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-			 * |                     6rdBRIPv4Address(es)                      |
-			 * .                                                               .
-			 * .                                                               .
-			 * .                                                               .
+			 * ...                   6rdBRIPv4Address(es)                    ...
 			 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-			 *
 			 * We convert it to a string
 			 * "IPv4MaskLen 6rdPrefixLen 6rdPrefix 6rdBRIPv4Address..."
-			 */
-
-			/* Sanity check: ensure that our length is at least 22 bytes, that
+			 *
+			 * Sanity check: ensure that our length is at least 22 bytes, that
 			 * IPv4MaskLen <= 32,
 			 * 6rdPrefixLen <= 128,
 			 * 6rdPrefixLen + (32 - IPv4MaskLen) <= 128
 			 * (2nd condition need no check - it follows from 1st and 3rd).
-			 * If any of these requirements is not fulfilled, return with empty
-			 * value.
+			 * Else, return envvar with empty value ("optname=")
 			 */
-			if (len >= 22
+			if (len >= (1 + 1 + 16 + 4)
 			 && option[0] <= 32
 			 && (option[1] + 32 - option[0]) <= 128
 			) {
@@ -295,19 +285,20 @@
 				/* 6rdPrefix */
 				dest += sprint_nip6(dest, /* "", */ option);
 				option += 16;
-				len -= 1 + 1 + 16;
-				/* 6rdBRIPv4Address(es) */
+				len -= 1 + 1 + 16 + 4;
+				/* "+ 4" above corresponds to the length of IPv4 addr
+				 * we consume in the loop below */
 				while (1) {
+					/* 6rdBRIPv4Address(es) */
 					dest += sprint_nip(dest, " ", option);
 					option += 4;
-					len -= 4;
+					len -= 4; /* do we have yet another 4+ bytes? */
 					if (len < 0)
-						break;
+						break; /* no */
 				}
 			}
 
 			return ret;
-		}
 #if ENABLE_FEATURE_UDHCP_RFC3397
 		case OPTION_DNS_STRING:
 			/* unpack option into dest; use ret for prefix (i.e., "optname=") */
@@ -347,6 +338,10 @@
 			return ret;
 #endif
 		} /* switch */
+
+		/* If we are here, try to format any remaining data
+		 * in the option as another, similarly-formatted option
+		 */
 		option += optlen;
 		len -= optlen;
 // TODO: it can be a list only if (optflag->flags & OPTION_LIST).
@@ -356,7 +351,8 @@
 			break;
 		*dest++ = ' ';
 		*dest = '\0';
-	}
+	} /* while */
+
 	return ret;
 }