@@ -822,13 +822,15 @@ static void dhcpv6_send(enum dhcpv6_msg req_msg_type, uint8_t trid[3], uint32_t
822822 if (pd_entries [j ].iaid != iaid )
823823 continue ;
824824
825- uint8_t ex_len = 0 ;
826- if (pd_entries [j ].exclusion_length > 0 )
827- ex_len = ((pd_entries [j ].exclusion_length - pd_entries [j ].length - 1 ) / 8 ) + 6 ;
828-
825+ uint8_t excl_subnet_id_nbits , excl_subnet_id_nbytes , excl_opt_len = 0 ;
826+ if (pd_entries [j ].exclusion_length > 0 ) {
827+ excl_subnet_id_nbits = pd_entries [j ].exclusion_length - pd_entries [j ].length ;
828+ excl_subnet_id_nbytes = ((excl_subnet_id_nbits - 1 ) / 8 ) + 1 ;
829+ excl_opt_len = excl_subnet_id_nbytes + DHCPV6_OPT_HDR_SIZE + 1 ;
830+ }
829831 struct dhcpv6_ia_prefix p = {
830832 .type = htons (DHCPV6_OPT_IA_PREFIX ),
831- .len = htons (sizeof (p ) - DHCPV6_OPT_HDR_SIZE_U + ex_len ),
833+ .len = htons (sizeof (p ) - DHCPV6_OPT_HDR_SIZE_U + excl_opt_len ),
832834 .prefix = pd_entries [j ].length ,
833835 .addr = pd_entries [j ].target
834836 };
@@ -841,21 +843,22 @@ static void dhcpv6_send(enum dhcpv6_msg req_msg_type, uint8_t trid[3], uint32_t
841843 memcpy (ia_pd + ia_pd_len , & p , sizeof (p ));
842844 ia_pd_len += sizeof (p );
843845
844- if (ex_len ) {
846+ if (excl_opt_len ) {
845847 ia_pd [ia_pd_len ++ ] = 0 ;
846848 ia_pd [ia_pd_len ++ ] = DHCPV6_OPT_PD_EXCLUDE ;
847849 ia_pd [ia_pd_len ++ ] = 0 ;
848- ia_pd [ia_pd_len ++ ] = ex_len - DHCPV6_OPT_HDR_SIZE ;
850+ ia_pd [ia_pd_len ++ ] = excl_opt_len - DHCPV6_OPT_HDR_SIZE ;
849851 ia_pd [ia_pd_len ++ ] = pd_entries [j ].exclusion_length ;
850852
851- uint32_t excl = ntohl (pd_entries [j ].router .s6_addr32 [1 ]);
852- excl >>= (64 - pd_entries [j ].exclusion_length );
853- excl <<= 8 - (( pd_entries [ j ]. exclusion_length - pd_entries [ j ]. length ) % 8 );
853+ uint32_t excluded_bits = ntohl (pd_entries [j ].router .s6_addr32 [1 ]);
854+ excluded_bits >>= (64 - pd_entries [j ].exclusion_length ); /* Right align subnet ID bits */
855+ excluded_bits <<= ( 32 - excl_subnet_id_nbits ); /* Left align subnet ID bits */
854856
855- for (size_t k = ex_len - 5 ; k > 0 ; -- k , excl >>= 8 )
856- ia_pd [ia_pd_len + k ] = excl & 0xff ;
857-
858- ia_pd_len += ex_len - 5 ;
857+ /* Copy subnet ID bits into the option MSB first */
858+ for (size_t k = 0 ; k < excl_subnet_id_nbytes ; ++ k ) {
859+ ia_pd [ia_pd_len ++ ] = excluded_bits >> 24 ;
860+ excluded_bits <<= 8 ;
861+ }
859862 }
860863
861864 hdr -> len = htons (ntohs (hdr -> len ) + ntohs (p .len ) + 4U );
@@ -1826,9 +1829,10 @@ static unsigned int dhcpv6_parse_ia(void *opt, void *end, int *ret)
18261829
18271830 dhcpv6_log_status_code (code , "IA_PREFIX" , status_msg , msg_len );
18281831 if (ret ) * ret = 0 ; // renewal failed
1829- } else if (stype == DHCPV6_OPT_PD_EXCLUDE && slen > 2 ) {
1832+ } else if (stype == DHCPV6_OPT_PD_EXCLUDE && slen >= 2 ) {
18301833 /* RFC 6603 §4.2 Prefix Exclude option */
18311834 uint8_t exclude_length = sdata [0 ];
1835+ uint8_t * excl_subnet_id = & sdata [1 ];
18321836 if (exclude_length > 64 )
18331837 exclude_length = 64 ;
18341838
@@ -1837,21 +1841,19 @@ static unsigned int dhcpv6_parse_ia(void *opt, void *end, int *ret)
18371841 continue ;
18381842 }
18391843
1840- uint8_t bytes_needed = ((exclude_length - entry .length - 1 ) / 8 ) + 1 ;
1841- if (slen <= bytes_needed ) {
1844+ uint8_t excl_subnet_id_nbits = exclude_length - entry .length ;
1845+ uint8_t excl_subnet_id_nbytes = ((excl_subnet_id_nbits - 1 ) / 8 ) + 1 ;
1846+ if ((excl_subnet_id + excl_subnet_id_nbytes ) > (sdata + slen )) {
18421847 update_state = false;
18431848 continue ;
18441849 }
18451850
1846- // this decrements through the ipaddr bytes masking against
1847- // the address in the option until byte 0, the option length field.
18481851 uint32_t excluded_bits = 0 ;
1849- do {
1850- excluded_bits = excluded_bits << 8 | sdata [bytes_needed ];
1851- } while (-- bytes_needed );
1852-
1853- excluded_bits >>= 8 - ((exclude_length - entry .length ) % 8 );
1854- excluded_bits <<= 64 - exclude_length ;
1852+ /* Copy subnet ID bits out of the option MSB first */
1853+ for (size_t i = 0 ; i < excl_subnet_id_nbytes ; i ++ )
1854+ excluded_bits = (excluded_bits << 8 ) | excl_subnet_id [i ];
1855+ excluded_bits >>= (8 * excl_subnet_id_nbytes ) - excl_subnet_id_nbits ; /* Right align subnet ID bits */
1856+ excluded_bits <<= (64 - exclude_length ); /* Shift subnet ID bits into the low-order bits of the prefix */
18551857
18561858 // Re-using router field to hold the prefix
18571859 entry .router = entry .target ; // base prefix
@@ -1867,6 +1869,12 @@ static unsigned int dhcpv6_parse_ia(void *opt, void *end, int *ret)
18671869 info ("%s/%d preferred %d valid %d" ,
18681870 inet_ntop (AF_INET6 , & entry .target , buf , sizeof (buf )),
18691871 entry .length , entry .preferred , entry .valid );
1872+
1873+ if (entry .exclusion_length ) {
1874+ info ("PD_EXCLUDE %s/%d" ,
1875+ inet_ntop (AF_INET6 , & entry .router , buf , sizeof (buf )),
1876+ entry .exclusion_length );
1877+ }
18701878 }
18711879
18721880 entry .priority = 0 ;
0 commit comments