busybox-1.32.0/networking/udhcp/d6_dhcpc.c
static void option_to_env(const uint8_t *option, const uint8_t *option_end)
{
#if ENABLE_FEATURE_UDHCPC6_RFC3646
	int addrs, option_offset;
#endif
	/* "length minus 4" */
	int len_m4 = option_end - option - 4;

	while (len_m4 >= 0) {
		uint32_t v32;
		char ipv6str[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")];

		if (option[0] != 0 || option[2] != 0)
			break;

		/* Check if option-length exceeds size of option */
		if (option[3] > len_m4)
			break;

		switch (option[1]) {
		//case D6_OPT_CLIENTID:
		//case D6_OPT_SERVERID:
		case D6_OPT_IA_NA:
		case D6_OPT_IA_PD:
			option_to_env(option + 16, option + 4 + option[3]);
			break;
		//case D6_OPT_IA_TA:
		case D6_OPT_IAADDR:
/*  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_IAADDR        |          option-len           |
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 * |                                                               |
 * |                         IPv6 address                          |
 * |                                                               |
 * |                                                               |
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 * |                      preferred-lifetime                       |
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 * |                        valid-lifetime                         |
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 */
			/* Make sure payload contains an address */
			if (option[3] < 24)
				break;

			sprint_nip6(ipv6str, option + 4);
			*new_env() = xasprintf("ipv6=%s", ipv6str);

			move_from_unaligned32(v32, option + 4 + 16 + 4);
			*new_env() = xasprintf("lease=%u", (unsigned)v32);
			break;

		//case D6_OPT_ORO:
		//case D6_OPT_PREFERENCE:
		//case D6_OPT_ELAPSED_TIME:
		//case D6_OPT_RELAY_MSG:
		//case D6_OPT_AUTH:
		//case D6_OPT_UNICAST:
		//case D6_OPT_STATUS_CODE:
		//case D6_OPT_RAPID_COMMIT:
		//case D6_OPT_USER_CLASS:
		//case D6_OPT_VENDOR_CLASS:
		//case D6_OPT_VENDOR_OPTS:
		//case D6_OPT_INTERFACE_ID:
		//case D6_OPT_RECONF_MSG:
		//case D6_OPT_RECONF_ACCEPT:

		case D6_OPT_IAPREFIX:
/*  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_IAPREFIX        |         option-length         |
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 * |                      preferred-lifetime                       |
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 * |                        valid-lifetime                         |
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 * | prefix-length |                                               |
 * +-+-+-+-+-+-+-+-+          IPv6 prefix                          |
 * |                           (16 octets)                         |
 * |                                                               |
 * |               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 * |               |
 * +-+-+-+-+-+-+-+-+
 */
			move_from_unaligned32(v32, option + 4 + 4);
			*new_env() = xasprintf("ipv6prefix_lease=%u", (unsigned)v32);

			sprint_nip6(ipv6str, option + 4 + 4 + 4 + 1);
			*new_env() = xasprintf("ipv6prefix=%s/%u", ipv6str, (unsigned)(option[4 + 4 + 4]));
			break;
#if ENABLE_FEATURE_UDHCPC6_RFC3646
		case D6_OPT_DNS_SERVERS: {
			char *dlist;

			/* Make sure payload-size is a multiple of 16 */
			if ((option[3] & 0x0f) != 0)
				break;

			/* Get the number of addresses on the option */
			addrs = option[3] >> 4;

			/* Setup environment variable */
			*new_env() = dlist = xmalloc(4 + addrs * 40 - 1);
			dlist = stpcpy(dlist, "dns=");
			option_offset = 0;

			while (addrs--) {
				sprint_nip6(dlist, option + 4 + option_offset);
				dlist += 39;
				option_offset += 16;
				if (addrs)
					*dlist++ = ' ';
			}

			break;
		}
		case D6_OPT_DOMAIN_LIST: {
			char *dlist;

			dlist = dname_dec(option + 4, (option[2] << 8) | option[3], "search=");
			if (!dlist)
				break;
			*new_env() = dlist;
			break;
		}
#endif
#if ENABLE_FEATURE_UDHCPC6_RFC4704
		case D6_OPT_CLIENT_FQDN: {
			char *dlist;

			if (option[3] == 0)
				break;
			/* Work around broken ISC DHCPD6.
			 * ISC DHCPD6 does not implement RFC 4704 correctly: It says the first
			 * byte of option-payload should contain flags where the bits 7-3 are
			 * reserved for future use and MUST be zero. Instead ISC DHCPD6 just
			 * writes the entire FQDN as string to option-payload. We assume a
			 * broken server here if any of the reserved bits are set.
			 */
			if (option[4] & 0xf8) {
				*new_env() = xasprintf("fqdn=%.*s", (int)option[3], (char*)option + 4);
				break;
			}
			dlist = dname_dec(option + 5, (/*(option[2] << 8) |*/ option[3]) - 1, "fqdn=");
			if (!dlist)
				break;
			*new_env() = dlist;
			break;
		}
#endif
#if ENABLE_FEATURE_UDHCPC6_RFC4833
		/* RFC 4833 Timezones */
		case D6_OPT_TZ_POSIX:
			*new_env() = xasprintf("tz=%.*s", (int)option[3], (char*)option + 4);
			break;
		case D6_OPT_TZ_NAME:
			*new_env() = xasprintf("tz_name=%.*s", (int)option[3], (char*)option + 4);
			break;
#endif
		case D6_OPT_BOOT_URL:
		case D6_OPT_BOOT_PARAM:
		case 0xd1: /* DHCP_PXE_CONF_FILE */
		case 0xd2: /* DHCP_PXE_PATH_PREFIX */
			{
			char *tmp = string_option_to_env(option, option_end);
			if (tmp)
				*new_env() = tmp;
			break;
			}
		}
		len_m4 -= 4 + option[3];
		option += 4 + option[3];
	}
}
/* put all the parameters into the environment */
put all the parameters into the environment
put all the parameters into the environment
static void option_to_env(const uint8_t *option, const uint8_t *option_end)
{
#if ENABLE_FEATURE_UDHCPC6_RFC3646
	int addrs, option_offset;
#endif
	int len_m4 = option_end - option - 4;
	while (len_m4 >= 0) {
		uint32_t v32;
		char ipv6str[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")];
		if (option[0] != 0 || option[2] != 0)
			break;
		if (option[3] > len_m4)
			break;
		switch (option[1]) {
		case D6_OPT_IA_NA:
		case D6_OPT_IA_PD:
			option_to_env(option + 16, option + 4 + option[3]);
			break;
		case D6_OPT_IAADDR:
			if (option[3] < 24)
				break;
			sprint_nip6(ipv6str, option + 4);
			*new_env() = xasprintf("ipv6=%s", ipv6str);
			move_from_unaligned32(v32, option + 4 + 16 + 4);
			*new_env() = xasprintf("lease=%u", (unsigned)v32);
			break;
		case D6_OPT_IAPREFIX:
			move_from_unaligned32(v32, option + 4 + 4);
			*new_env() = xasprintf("ipv6prefix_lease=%u", (unsigned)v32);
			sprint_nip6(ipv6str, option + 4 + 4 + 4 + 1);
			*new_env() = xasprintf("ipv6prefix=%s/%u", ipv6str, (unsigned)(option[4 + 4 + 4]));
			break;
#if ENABLE_FEATURE_UDHCPC6_RFC3646
		case D6_OPT_DNS_SERVERS: {
			char *dlist;
			if ((option[3] & 0x0f) != 0)
				break;
			addrs = option[3] >> 4;
			*new_env() = dlist = xmalloc(4 + addrs * 40 - 1);
			dlist = stpcpy(dlist, "dns=");
			option_offset = 0;
			while (addrs--) {
				sprint_nip6(dlist, option + 4 + option_offset);
				dlist += 39;
				option_offset += 16;
				if (addrs)
					*dlist++ = ' ';
			}
			break;
		}
		case D6_OPT_DOMAIN_LIST: {
			char *dlist;
			dlist = dname_dec(option + 4, (option[2] << 8) | option[3], "search=");
			if (!dlist)
				break;
			*new_env() = dlist;
			break;
		}
#endif
#if ENABLE_FEATURE_UDHCPC6_RFC4704
		case D6_OPT_CLIENT_FQDN: {
			char *dlist;
			if (option[3] == 0)
				break;
			if (option[4] & 0xf8) {
				*new_env() = xasprintf("fqdn=%.*s", (int)option[3], (char*)option + 4);
				break;
			}
			dlist = dname_dec(option + 5, ( option[3]) - 1, "fqdn=");
			if (!dlist)
				break;
			*new_env() = dlist;
			break;
		}
#endif
#if ENABLE_FEATURE_UDHCPC6_RFC4833
		case D6_OPT_TZ_POSIX:
			*new_env() = xasprintf("tz=%.*s", (int)option[3], (char*)option + 4);
			break;
		case D6_OPT_TZ_NAME:
			*new_env() = xasprintf("tz_name=%.*s", (int)option[3], (char*)option + 4);
			break;
#endif
		case D6_OPT_BOOT_URL:
		case D6_OPT_BOOT_PARAM:
		case 0xd1: 
		case 0xd2: 
			{
			char *tmp = string_option_to_env(option, option_end);
			if (tmp)
				*new_env() = tmp;
			break;
			}
		}
		len_m4 -= 4 + option[3];
		option += 4 + option[3];
	}
}
static void option_to_env ( const uint8_t * option , const uint8_t * option_end ) { #if ENABLE_FEATURE_UDHCPC6_RFC3646 int addrs , option_offset ; #endif int len_m4 = option_end - option - 4 ; while ( len_m4 >= 0 ) { uint32_t v32 ; char ipv6str [ sizeof ( " " ) ] ; if ( option [ 0 ] != 0 || option [ 2 ] != 0 ) break ; if ( option [ 3 ] > len_m4 ) break ; switch ( option [ 1 ] ) { case D6_OPT_IA_NA : case D6_OPT_IA_PD : option_to_env ( option + 16 , option + 4 + option [ 3 ] ) ; break ; case D6_OPT_IAADDR : if ( option [ 3 ] < 24 ) break ; sprint_nip6 ( ipv6str , option + 4 ) ; * new_env ( ) = xasprintf ( " " , ipv6str ) ; move_from_unaligned32 ( v32 , option + 4 + 16 + 4 ) ; * new_env ( ) = xasprintf ( " " , ( unsigned ) v32 ) ; break ; case D6_OPT_IAPREFIX : move_from_unaligned32 ( v32 , option + 4 + 4 ) ; * new_env ( ) = xasprintf ( " " , ( unsigned ) v32 ) ; sprint_nip6 ( ipv6str , option + 4 + 4 + 4 + 1 ) ; * new_env ( ) = xasprintf ( " " , ipv6str , ( unsigned ) ( option [ 4 + 4 + 4 ] ) ) ; break ; #if ENABLE_FEATURE_UDHCPC6_RFC3646 case D6_OPT_DNS_SERVERS : { char * dlist ; if ( ( option [ 3 ] & 0x0f ) != 0 ) break ; addrs = option [ 3 ] >> 4 ; * new_env ( ) = dlist = xmalloc ( 4 + addrs * 40 - 1 ) ; dlist = stpcpy ( dlist , " " ) ; option_offset = 0 ; while ( addrs -- ) { sprint_nip6 ( dlist , option + 4 + option_offset ) ; dlist += 39 ; option_offset += 16 ; if ( addrs ) * dlist ++ = ' ' ; } break ; } case D6_OPT_DOMAIN_LIST : { char * dlist ; dlist = dname_dec ( option + 4 , ( option [ 2 ] << 8 ) | option [ 3 ] , " " ) ; if ( ! dlist ) break ; * new_env ( ) = dlist ; break ; } #endif #if ENABLE_FEATURE_UDHCPC6_RFC4704 case D6_OPT_CLIENT_FQDN : { char * dlist ; if ( option [ 3 ] == 0 ) break ; if ( option [ 4 ] & 0xf8 ) { * new_env ( ) = xasprintf ( " " , ( int ) option [ 3 ] , ( char * ) option + 4 ) ; break ; } dlist = dname_dec ( option + 5 , ( option [ 3 ] ) - 1 , " " ) ; if ( ! dlist ) break ; * new_env ( ) = dlist ; break ; } #endif #if ENABLE_FEATURE_UDHCPC6_RFC4833 case D6_OPT_TZ_POSIX : * new_env ( ) = xasprintf ( " " , ( int ) option [ 3 ] , ( char * ) option + 4 ) ; break ; case D6_OPT_TZ_NAME : * new_env ( ) = xasprintf ( " " , ( int ) option [ 3 ] , ( char * ) option + 4 ) ; break ; #endif case D6_OPT_BOOT_URL : case D6_OPT_BOOT_PARAM : case 0xd1 : case 0xd2 : { char * tmp = string_option_to_env ( option , option_end ) ; if ( tmp ) * new_env ( ) = tmp ; break ; } } len_m4 -= 4 + option [ 3 ] ; option += 4 + option [ 3 ] ; } }
put all the parameters into the environment
put all the parameters into the environment
/* "length minus 4" */ /* Check if option-length exceeds size of option */ //case D6_OPT_CLIENTID: //case D6_OPT_SERVERID: //case D6_OPT_IA_TA: /*  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_IAADDR        |          option-len           |
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 * |                                                               |
 * |                         IPv6 address                          |
 * |                                                               |
 * |                                                               |
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 * |                      preferred-lifetime                       |
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 * |                        valid-lifetime                         |
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 */ /* Make sure payload contains an address */ //case D6_OPT_ORO: //case D6_OPT_PREFERENCE: //case D6_OPT_ELAPSED_TIME: //case D6_OPT_RELAY_MSG: //case D6_OPT_AUTH: //case D6_OPT_UNICAST: //case D6_OPT_STATUS_CODE: //case D6_OPT_RAPID_COMMIT: //case D6_OPT_USER_CLASS: //case D6_OPT_VENDOR_CLASS: //case D6_OPT_VENDOR_OPTS: //case D6_OPT_INTERFACE_ID: //case D6_OPT_RECONF_MSG: //case D6_OPT_RECONF_ACCEPT: /*  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_IAPREFIX        |         option-length         |
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 * |                      preferred-lifetime                       |
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 * |                        valid-lifetime                         |
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 * | prefix-length |                                               |
 * +-+-+-+-+-+-+-+-+          IPv6 prefix                          |
 * |                           (16 octets)                         |
 * |                                                               |
 * |               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 * |               |
 * +-+-+-+-+-+-+-+-+
 */ /* Make sure payload-size is a multiple of 16 */ /* Get the number of addresses on the option */ /* Setup environment variable */ /* Work around broken ISC DHCPD6.
			 * ISC DHCPD6 does not implement RFC 4704 correctly: It says the first
			 * byte of option-payload should contain flags where the bits 7-3 are
			 * reserved for future use and MUST be zero. Instead ISC DHCPD6 just
			 * writes the entire FQDN as string to option-payload. We assume a
			 * broken server here if any of the reserved bits are set.
			 */ /*(option[2] << 8) |*/ /* RFC 4833 Timezones */ /* DHCP_PXE_CONF_FILE */ /* DHCP_PXE_PATH_PREFIX */