generic: platform/mikrotik: fix LZOR support
31e99fe3dawhich introduced this code was unfortunately untested. This commit fixes a number of issues and works around the fact that in this particular scheme, the LZO payload may be padded at the end which will trigger a harmless lzo decompression error. This commit also disambiguates the debug printks. Tested-by: Robert Marko <robimarko@gmail.com> Signed-off-by: Thibaut VARÈNE <hacks@slashdirt.org> Fixes:31e99fe3da("generic: platform/mikrotik: support LZOR encoding") (cherry picked from commit2ea481193c)
This commit is contained in:
		 Thibaut VARÈNE
					Thibaut VARÈNE
				
			
				
					committed by
					
						 Hauke Mehrtens
						Hauke Mehrtens
					
				
			
			
				
	
			
			
			 Hauke Mehrtens
						Hauke Mehrtens
					
				
			
						parent
						
							4cd9ae41c5
						
					
				
				
					commit
					85e04e9f46
				
			| @@ -36,7 +36,7 @@ | |||||||
|  |  | ||||||
| #include "routerboot.h" | #include "routerboot.h" | ||||||
|  |  | ||||||
| #define RB_HARDCONFIG_VER		"0.02" | #define RB_HARDCONFIG_VER		"0.03" | ||||||
| #define RB_HC_PR_PFX			"[rb_hardconfig] " | #define RB_HC_PR_PFX			"[rb_hardconfig] " | ||||||
|  |  | ||||||
| /* ID values for hardware settings */ | /* ID values for hardware settings */ | ||||||
| @@ -483,16 +483,18 @@ static int hc_wlan_data_unpack_lzor(const u8 *inbuf, size_t inlen, | |||||||
| 				    void *outbuf, size_t *outlen) | 				    void *outbuf, size_t *outlen) | ||||||
| { | { | ||||||
| 	u16 rle_ofs, rle_len; | 	u16 rle_ofs, rle_len; | ||||||
| 	size_t templen; | 	const u32 *needle; | ||||||
| 	u8 *tempbuf; | 	u8 *tempbuf; | ||||||
|  | 	size_t templen, lzo_len; | ||||||
| 	int ret; | 	int ret; | ||||||
|  |  | ||||||
| 	templen = inlen + sizeof(hc_lzor_prefix); | 	lzo_len = inlen + sizeof(hc_lzor_prefix); | ||||||
| 	if (templen > *outlen) | 	if (lzo_len > *outlen) | ||||||
| 		return -EFBIG; | 		return -EFBIG; | ||||||
|  |  | ||||||
| 	/* Temporary buffer same size as the outbuf */ | 	/* Temporary buffer same size as the outbuf */ | ||||||
| 	tempbuf = kmalloc(*outlen, GFP_KERNEL); | 	templen = *outlen; | ||||||
|  | 	tempbuf = kmalloc(templen, GFP_KERNEL); | ||||||
| 	if (!outbuf) | 	if (!outbuf) | ||||||
| 		return -ENOMEM; | 		return -ENOMEM; | ||||||
|  |  | ||||||
| @@ -500,41 +502,54 @@ static int hc_wlan_data_unpack_lzor(const u8 *inbuf, size_t inlen, | |||||||
| 	memcpy(outbuf, hc_lzor_prefix, sizeof(hc_lzor_prefix)); | 	memcpy(outbuf, hc_lzor_prefix, sizeof(hc_lzor_prefix)); | ||||||
| 	memcpy(outbuf + sizeof(hc_lzor_prefix), inbuf, inlen); | 	memcpy(outbuf + sizeof(hc_lzor_prefix), inbuf, inlen); | ||||||
|  |  | ||||||
| 	/* LZO-decompress templen bytes of outbuf into the tempbuf */ | 	/* LZO-decompress lzo_len bytes of outbuf into the tempbuf */ | ||||||
| 	ret = lzo1x_decompress_safe(outbuf, templen, tempbuf, outlen); | 	ret = lzo1x_decompress_safe(outbuf, lzo_len, tempbuf, &templen); | ||||||
| 	if (ret) { | 	if (ret) { | ||||||
| 		pr_debug(RB_HC_PR_PFX "LZO decompression error (%d)\n", ret); | 		if (LZO_E_INPUT_NOT_CONSUMED == ret) { | ||||||
|  | 			/* | ||||||
|  | 			 * It is assumed that because the LZO payload is embedded | ||||||
|  | 			 * in a "root" RB_ID_WLAN_DATA tag, the tag length is aligned | ||||||
|  | 			 * and the payload is padded at the end, which triggers a | ||||||
|  | 			 * spurious error which we ignore here. | ||||||
|  | 			 */ | ||||||
|  | 			pr_debug(RB_HC_PR_PFX "LZOR: LZO EOF before buffer end - this may be harmless\n"); | ||||||
|  | 		} else { | ||||||
|  | 			pr_debug(RB_HC_PR_PFX "LZOR: LZO decompression error (%d)\n", ret); | ||||||
| 			goto fail; | 			goto fail; | ||||||
| 		} | 		} | ||||||
| 	templen = *outlen; | 	} | ||||||
|  |  | ||||||
| 	/* | 	/* | ||||||
| 	 * Post decompression we have a blob (possibly byproduct of the lzo | 	 * Post decompression we have a blob (possibly byproduct of the lzo | ||||||
| 	 * dictionary). We need to find RB_MAGIC_ERD. The magic number seems to | 	 * dictionary). We need to find RB_MAGIC_ERD. The magic number seems to | ||||||
| 	 * be 32bit-aligned in the decompression output. | 	 * be 32bit-aligned in the decompression output. | ||||||
| 	 */ | 	 */ | ||||||
|  | 	needle = (const u32 *)tempbuf; | ||||||
| 	while (RB_MAGIC_ERD != *(u32 *)tempbuf) { | 	while (RB_MAGIC_ERD != *needle++) { | ||||||
| 		tempbuf += 4; | 		if ((u8 *)needle >= tempbuf+templen) { | ||||||
| 		templen -= 4; | 			pr_debug(RB_HC_PR_PFX "LZOR: ERD magic not found\n"); | ||||||
|  | 			goto fail; | ||||||
| 		} | 		} | ||||||
|  | 	}; | ||||||
|  | 	templen -= (u8 *)needle - tempbuf; | ||||||
|  |  | ||||||
| 	/* Past magic. Look for tag node */ | 	/* Past magic. Look for tag node */ | ||||||
| 	ret = routerboot_tag_find(tempbuf, templen, 0x1, &rle_ofs, &rle_len); | 	ret = routerboot_tag_find((u8 *)needle, templen, 0x1, &rle_ofs, &rle_len); | ||||||
| 	if (ret) { | 	if (ret) { | ||||||
| 		pr_debug(RB_HC_PR_PFX "RLE data not found\n"); | 		pr_debug(RB_HC_PR_PFX "LZOR: RLE data not found\n"); | ||||||
| 		goto fail; | 		goto fail; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if (rle_len > templen) { | 	if (rle_len > templen) { | ||||||
| 		pr_debug(RB_HC_PR_PFX "Invalid RLE data length\n"); | 		pr_debug(RB_HC_PR_PFX "LZOR: Invalid RLE data length\n"); | ||||||
|  | 		ret = -EINVAL; | ||||||
| 		goto fail; | 		goto fail; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	/* RLE-decode tempbuf back into the outbuf */ | 	/* RLE-decode tempbuf from needle back into the outbuf */ | ||||||
| 	ret = routerboot_rle_decode(tempbuf+rle_ofs, rle_len, outbuf, outlen); | 	ret = routerboot_rle_decode((u8 *)needle+rle_ofs, rle_len, outbuf, outlen); | ||||||
| 	if (ret) | 	if (ret) | ||||||
| 		pr_debug(RB_HC_PR_PFX "RLE decoding error (%d)\n", ret); | 		pr_debug(RB_HC_PR_PFX "LZOR: RLE decoding error (%d)\n", ret); | ||||||
|  |  | ||||||
| fail: | fail: | ||||||
| 	kfree(tempbuf); | 	kfree(tempbuf); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user