In your point 4, I think that all the $i++ are intentional, although a bad fit for the for loop.
If my refactoring is correct, then I recommend this equivalent code:
while (@options) {
my $option = hex shift @options;
last if $option == 255; # end of DHCP Options
my $length = hex shift @options;
push @{$opts{$option}}, splice( @options, 0, $length );
}