Commit a0657846 authored by John W. Linville's avatar John W. Linville

ath5k: improve pcal error handling for ENOMEM case

The ath5k driver does kmalloc allocations for pcal info in a loop.
But, if one fails it was simply returning -ENOMEM without freeing
already allocated memory.  This patch corrects that oversight.
Reported-by: default avatarEugene A. Shatokhin <dame_eugene@mail.ru>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
Reviewed-by: default avatarBob Copeland <me@bobcopeland.com>
parent ba30c4a5
...@@ -660,6 +660,53 @@ ath5k_get_pcdac_intercepts(struct ath5k_hw *ah, u8 min, u8 max, u8 *vp) ...@@ -660,6 +660,53 @@ ath5k_get_pcdac_intercepts(struct ath5k_hw *ah, u8 min, u8 max, u8 *vp)
vp[i] = (ip[i] * max + (100 - ip[i]) * min) / 100; vp[i] = (ip[i] * max + (100 - ip[i]) * min) / 100;
} }
static int
ath5k_eeprom_free_pcal_info(struct ath5k_hw *ah, int mode)
{
struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
struct ath5k_chan_pcal_info *chinfo;
u8 pier, pdg;
switch (mode) {
case AR5K_EEPROM_MODE_11A:
if (!AR5K_EEPROM_HDR_11A(ee->ee_header))
return 0;
chinfo = ee->ee_pwr_cal_a;
break;
case AR5K_EEPROM_MODE_11B:
if (!AR5K_EEPROM_HDR_11B(ee->ee_header))
return 0;
chinfo = ee->ee_pwr_cal_b;
break;
case AR5K_EEPROM_MODE_11G:
if (!AR5K_EEPROM_HDR_11G(ee->ee_header))
return 0;
chinfo = ee->ee_pwr_cal_g;
break;
default:
return -EINVAL;
}
for (pier = 0; pier < ee->ee_n_piers[mode]; pier++) {
if (!chinfo[pier].pd_curves)
continue;
for (pdg = 0; pdg < ee->ee_pd_gains[mode]; pdg++) {
struct ath5k_pdgain_info *pd =
&chinfo[pier].pd_curves[pdg];
if (pd != NULL) {
kfree(pd->pd_step);
kfree(pd->pd_pwr);
}
}
kfree(chinfo[pier].pd_curves);
}
return 0;
}
/* Convert RF5111 specific data to generic raw data /* Convert RF5111 specific data to generic raw data
* used by interpolation code */ * used by interpolation code */
static int static int
...@@ -684,7 +731,7 @@ ath5k_eeprom_convert_pcal_info_5111(struct ath5k_hw *ah, int mode, ...@@ -684,7 +731,7 @@ ath5k_eeprom_convert_pcal_info_5111(struct ath5k_hw *ah, int mode,
GFP_KERNEL); GFP_KERNEL);
if (!chinfo[pier].pd_curves) if (!chinfo[pier].pd_curves)
return -ENOMEM; goto err_out;
/* Only one curve for RF5111 /* Only one curve for RF5111
* find out which one and place * find out which one and place
...@@ -708,12 +755,12 @@ ath5k_eeprom_convert_pcal_info_5111(struct ath5k_hw *ah, int mode, ...@@ -708,12 +755,12 @@ ath5k_eeprom_convert_pcal_info_5111(struct ath5k_hw *ah, int mode,
pd->pd_step = kcalloc(AR5K_EEPROM_N_PWR_POINTS_5111, pd->pd_step = kcalloc(AR5K_EEPROM_N_PWR_POINTS_5111,
sizeof(u8), GFP_KERNEL); sizeof(u8), GFP_KERNEL);
if (!pd->pd_step) if (!pd->pd_step)
return -ENOMEM; goto err_out;
pd->pd_pwr = kcalloc(AR5K_EEPROM_N_PWR_POINTS_5111, pd->pd_pwr = kcalloc(AR5K_EEPROM_N_PWR_POINTS_5111,
sizeof(s16), GFP_KERNEL); sizeof(s16), GFP_KERNEL);
if (!pd->pd_pwr) if (!pd->pd_pwr)
return -ENOMEM; goto err_out;
/* Fill raw dataset /* Fill raw dataset
* (convert power to 0.25dB units * (convert power to 0.25dB units
...@@ -734,6 +781,10 @@ ath5k_eeprom_convert_pcal_info_5111(struct ath5k_hw *ah, int mode, ...@@ -734,6 +781,10 @@ ath5k_eeprom_convert_pcal_info_5111(struct ath5k_hw *ah, int mode,
} }
return 0; return 0;
err_out:
ath5k_eeprom_free_pcal_info(ah, mode);
return -ENOMEM;
} }
/* Parse EEPROM data */ /* Parse EEPROM data */
...@@ -867,7 +918,7 @@ ath5k_eeprom_convert_pcal_info_5112(struct ath5k_hw *ah, int mode, ...@@ -867,7 +918,7 @@ ath5k_eeprom_convert_pcal_info_5112(struct ath5k_hw *ah, int mode,
GFP_KERNEL); GFP_KERNEL);
if (!chinfo[pier].pd_curves) if (!chinfo[pier].pd_curves)
return -ENOMEM; goto err_out;
/* Fill pd_curves */ /* Fill pd_curves */
for (pdg = 0; pdg < ee->ee_pd_gains[mode]; pdg++) { for (pdg = 0; pdg < ee->ee_pd_gains[mode]; pdg++) {
...@@ -886,14 +937,13 @@ ath5k_eeprom_convert_pcal_info_5112(struct ath5k_hw *ah, int mode, ...@@ -886,14 +937,13 @@ ath5k_eeprom_convert_pcal_info_5112(struct ath5k_hw *ah, int mode,
sizeof(u8), GFP_KERNEL); sizeof(u8), GFP_KERNEL);
if (!pd->pd_step) if (!pd->pd_step)
return -ENOMEM; goto err_out;
pd->pd_pwr = kcalloc(pd->pd_points, pd->pd_pwr = kcalloc(pd->pd_points,
sizeof(s16), GFP_KERNEL); sizeof(s16), GFP_KERNEL);
if (!pd->pd_pwr) if (!pd->pd_pwr)
return -ENOMEM; goto err_out;
/* Fill raw dataset /* Fill raw dataset
* (all power levels are in 0.25dB units) */ * (all power levels are in 0.25dB units) */
...@@ -925,13 +975,13 @@ ath5k_eeprom_convert_pcal_info_5112(struct ath5k_hw *ah, int mode, ...@@ -925,13 +975,13 @@ ath5k_eeprom_convert_pcal_info_5112(struct ath5k_hw *ah, int mode,
sizeof(u8), GFP_KERNEL); sizeof(u8), GFP_KERNEL);
if (!pd->pd_step) if (!pd->pd_step)
return -ENOMEM; goto err_out;
pd->pd_pwr = kcalloc(pd->pd_points, pd->pd_pwr = kcalloc(pd->pd_points,
sizeof(s16), GFP_KERNEL); sizeof(s16), GFP_KERNEL);
if (!pd->pd_pwr) if (!pd->pd_pwr)
return -ENOMEM; goto err_out;
/* Fill raw dataset /* Fill raw dataset
* (all power levels are in 0.25dB units) */ * (all power levels are in 0.25dB units) */
...@@ -954,6 +1004,10 @@ ath5k_eeprom_convert_pcal_info_5112(struct ath5k_hw *ah, int mode, ...@@ -954,6 +1004,10 @@ ath5k_eeprom_convert_pcal_info_5112(struct ath5k_hw *ah, int mode,
} }
return 0; return 0;
err_out:
ath5k_eeprom_free_pcal_info(ah, mode);
return -ENOMEM;
} }
/* Parse EEPROM data */ /* Parse EEPROM data */
...@@ -1156,7 +1210,7 @@ ath5k_eeprom_convert_pcal_info_2413(struct ath5k_hw *ah, int mode, ...@@ -1156,7 +1210,7 @@ ath5k_eeprom_convert_pcal_info_2413(struct ath5k_hw *ah, int mode,
GFP_KERNEL); GFP_KERNEL);
if (!chinfo[pier].pd_curves) if (!chinfo[pier].pd_curves)
return -ENOMEM; goto err_out;
/* Fill pd_curves */ /* Fill pd_curves */
for (pdg = 0; pdg < ee->ee_pd_gains[mode]; pdg++) { for (pdg = 0; pdg < ee->ee_pd_gains[mode]; pdg++) {
...@@ -1177,13 +1231,13 @@ ath5k_eeprom_convert_pcal_info_2413(struct ath5k_hw *ah, int mode, ...@@ -1177,13 +1231,13 @@ ath5k_eeprom_convert_pcal_info_2413(struct ath5k_hw *ah, int mode,
sizeof(u8), GFP_KERNEL); sizeof(u8), GFP_KERNEL);
if (!pd->pd_step) if (!pd->pd_step)
return -ENOMEM; goto err_out;
pd->pd_pwr = kcalloc(pd->pd_points, pd->pd_pwr = kcalloc(pd->pd_points,
sizeof(s16), GFP_KERNEL); sizeof(s16), GFP_KERNEL);
if (!pd->pd_pwr) if (!pd->pd_pwr)
return -ENOMEM; goto err_out;
/* Fill raw dataset /* Fill raw dataset
* convert all pwr levels to * convert all pwr levels to
...@@ -1213,6 +1267,10 @@ ath5k_eeprom_convert_pcal_info_2413(struct ath5k_hw *ah, int mode, ...@@ -1213,6 +1267,10 @@ ath5k_eeprom_convert_pcal_info_2413(struct ath5k_hw *ah, int mode,
} }
return 0; return 0;
err_out:
ath5k_eeprom_free_pcal_info(ah, mode);
return -ENOMEM;
} }
/* Parse EEPROM data */ /* Parse EEPROM data */
...@@ -1534,53 +1592,6 @@ ath5k_eeprom_read_pcal_info(struct ath5k_hw *ah) ...@@ -1534,53 +1592,6 @@ ath5k_eeprom_read_pcal_info(struct ath5k_hw *ah)
return 0; return 0;
} }
static int
ath5k_eeprom_free_pcal_info(struct ath5k_hw *ah, int mode)
{
struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
struct ath5k_chan_pcal_info *chinfo;
u8 pier, pdg;
switch (mode) {
case AR5K_EEPROM_MODE_11A:
if (!AR5K_EEPROM_HDR_11A(ee->ee_header))
return 0;
chinfo = ee->ee_pwr_cal_a;
break;
case AR5K_EEPROM_MODE_11B:
if (!AR5K_EEPROM_HDR_11B(ee->ee_header))
return 0;
chinfo = ee->ee_pwr_cal_b;
break;
case AR5K_EEPROM_MODE_11G:
if (!AR5K_EEPROM_HDR_11G(ee->ee_header))
return 0;
chinfo = ee->ee_pwr_cal_g;
break;
default:
return -EINVAL;
}
for (pier = 0; pier < ee->ee_n_piers[mode]; pier++) {
if (!chinfo[pier].pd_curves)
continue;
for (pdg = 0; pdg < ee->ee_pd_gains[mode]; pdg++) {
struct ath5k_pdgain_info *pd =
&chinfo[pier].pd_curves[pdg];
if (pd != NULL) {
kfree(pd->pd_step);
kfree(pd->pd_pwr);
}
}
kfree(chinfo[pier].pd_curves);
}
return 0;
}
/* Read conformance test limits used for regulatory control */ /* Read conformance test limits used for regulatory control */
static int static int
ath5k_eeprom_read_ctl_info(struct ath5k_hw *ah) ath5k_eeprom_read_ctl_info(struct ath5k_hw *ah)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment