The problem here is that you are trying to compare something that is unsigned with something that is signed. This means that there's an implicit conversion involved before the actual conversion is done. In this case the signed is converted to unsigned (which is normally not what one would want - therefore many compilers have options to display warning when this is done).
To do it more correct in a sloppy way you would write:
if( (int)tmp > (int)len )
however this ignores the fact that size_t could have values that are too large for int. To be strict one would have to handle that the range of int combined with the range of size_t could be larger than any available type. This means that you would have to handle this in two cases, so you would use the fact that if tmp<0 then tmp<len (mathematically, since len>=0). So for example mathematically tmp<len would be written as tmp<0 || tmp<len. And the opposite would be tmp>=0 && tmp >= len. You should therefore write:
if( tmp >= 0 && tmp > len )
Note that then the conversion is not a problem, tmp could after the first check be converted to unsigned without change of value, different ranges of int and size_t are not a problem either as the smaller is converted to wider range before comparison.
The only problem left is that if you have enabled warnings about signed-unsigned comparison (to detect these kind of mistakes) it would still warn. To take care of that you would need to explicitely type cast it, but we know that conversion to unsigned doesn't change tmp once we checked that tmp>=0. So to avoid warnings you would write:
if( tmp >= 0 && (unsigned)tmp > len) )
the (unsigned) is because tmp is an int, you need to respect the type when converting to unsigned if tmp were of another type.