diff --git a/arch/arm64/configs/vendor/lineage-a52q_defconfig b/arch/arm64/configs/vendor/lineage-a52q_defconfig index 1532ef6b1e68..b664e1cdfca2 100755 --- a/arch/arm64/configs/vendor/lineage-a52q_defconfig +++ b/arch/arm64/configs/vendor/lineage-a52q_defconfig @@ -410,6 +410,8 @@ CONFIG_RWSEM_PRIO_AWARE=y CONFIG_FREEZER=y # CONFIG_OLAF_SUPPORT is not set CONFIG_SEC_A52Q_PROJECT=y +# CONFIG_SEC_A72Q_PROJECT is not set +# CONFIG_SEC_M42Q_PROJECT is not set CONFIG_SEC_A52Q_EUR_OPEN=y # CONFIG_SEC_A52Q_LTN_OPEN is not set @@ -5656,6 +5658,7 @@ CONFIG_SEC_LOG_STORE_LPM_KMSG=y # CONFIG_SEC_STORE_POWER_ONOFF_HISTORY is not set CONFIG_SEC_DEBUG_SCHED_LOG=y # CONFIG_SEC_DEBUG_SCHED_LOG_PER_CPU is not set +# CONFIG_SEC_DEBUG_SCHED_LOG_IRQ_V2 is not set # CONFIG_SEC_DEBUG_MSG_LOG is not set # CONFIG_SEC_DEBUG_DCVS_LOG is not set # CONFIG_SEC_DEBUG_POWER_LOG is not set diff --git a/drivers/adsp_factory/flip_cover_detector.c b/drivers/adsp_factory/flip_cover_detector.c index 9a1143cbdf9b..9a136159b231 100755 --- a/drivers/adsp_factory/flip_cover_detector.c +++ b/drivers/adsp_factory/flip_cover_detector.c @@ -494,6 +494,8 @@ static int __init flip_cover_detector_factory_init(void) fcd_data->poll_delay = ns_to_ktime(MAG_DELAY_MS * NSEC_PER_MSEC); + snprintf(sysfs_cover_status, 10, "OPEN"); + pr_info("[FACTORY] %s\n", __func__); return 0; diff --git a/drivers/battery/charger/sm5440_charger.c b/drivers/battery/charger/sm5440_charger.c index e72dbd3660fc..c81b4b05a52b 100755 --- a/drivers/battery/charger/sm5440_charger.c +++ b/drivers/battery/charger/sm5440_charger.c @@ -12,7 +12,7 @@ #include #include #include -#if defined (CONFIG_OF) +#if defined(CONFIG_OF) #include #include #include @@ -29,6 +29,8 @@ static bool wireless_4x_charger = 1; static int offset_4x; #endif +#define SM5440_DC_VERSION "UF2" + static int sm5440_read_reg(struct sm5440_charger *sm5440, u8 reg, u8 *dest) { int i, cnt, ret; @@ -94,7 +96,7 @@ static int sm5440_write_reg(struct sm5440_charger *sm5440, u8 reg, u8 value) return ret; } -static int sm5440_update_reg(struct sm5440_charger *sm5440, u8 reg, +static int sm5440_update_reg(struct sm5440_charger *sm5440, u8 reg, u8 val, u8 mask, u8 pos) { int ret; @@ -105,7 +107,9 @@ static int sm5440_update_reg(struct sm5440_charger *sm5440, u8 reg, ret = sm5440_read_reg(sm5440, reg, &old_val); if (ret == 0) { - u8 new_val = (val & mask) << pos | (old_val & ~(mask << pos)); + u8 new_val; + + new_val = (val & mask) << pos | (old_val & ~(mask << pos)); ret = sm5440_write_reg(sm5440, reg, new_val); } @@ -185,14 +189,16 @@ static struct sm_dc_info *select_sm_dc_info(struct sm5440_charger *sm5440) static int sm5440_convert_adc(struct sm5440_charger *sm5440, u8 index) { - struct sm_dc_info *sm_dc = select_sm_dc_info(sm5440); u8 reg1, reg2; int adc; +#if !defined(CONFIG_SEC_FACTORY) + struct sm_dc_info *sm_dc = select_sm_dc_info(sm5440); if (sm_dc_get_current_state(sm_dc) < SM_DC_CHECK_VBAT) { /* Didn't worked ADC block during on CHG-OFF status */ - return 0; + return -1; } +#endif switch (index) { case SM5440_ADC_THEM: @@ -239,7 +245,7 @@ static void sm5440_print_regmap(struct sm5440_charger *sm5440) int i; sm5440_bulk_read(sm5440, SM5440_REG_MSK1, 0x1F, regs); - sm5440_bulk_read(sm5440, SM5440_REG_MSK1 + 0x1F, + sm5440_bulk_read(sm5440, SM5440_REG_MSK1 + 0x1F, print_reg_num - 0x1F, regs + 0x1F); for (i = 0; i < print_reg_num; ++i) { @@ -304,14 +310,16 @@ static int sm5440_sw_reset(struct sm5440_charger *sm5440) sm5440_write_reg(sm5440, SM5440_REG_CNTL1, 0x1); /* Do SW RESET */ for (i = 0; i < 0xff; ++i) { - msleep(20); + usleep_range(1000, 2000); sm5440_read_reg(sm5440, SM5440_REG_CNTL1, ®); if (!(reg & 0x1)) break; } - if (i == 0xff) + if (i == 0xff) { + dev_err(sm5440->dev, "%s: didn't clear reset bit\n", __func__); return -EBUSY; + } return 0; } @@ -346,7 +354,7 @@ static int sm5440_reverse_boost_enable(struct sm5440_charger *sm5440, bool enabl } static int sm5440_set_ENHIZ(struct sm5440_charger *sm5440, bool vbus, bool chg_en) -{ +{ u8 enhiz = 0; /* case : chg_on or chg_off & vbus_uvlo */ if (vbus && !(chg_en)) @@ -374,6 +382,7 @@ static bool sm5440_check_charging_enable(struct sm5440_charger *sm5440) static void set_divide4_mode(struct sm5440_charger *sm5440, int mode) { union power_supply_propval value; + pr_info("%s: %d\n", __func__, mode); value.intval = 1; @@ -459,10 +468,28 @@ static int get_apdo_max_power(struct sm5440_charger *sm5440, struct sm_dc_power_ return ret; } +static void sm5440_init_reg_param(struct sm5440_charger *sm5440) +{ + sm5440_set_wdt_timer(sm5440, WDT_TIMER_S_30); + sm5440_set_freq(sm5440, sm5440->pdata->freq); + + sm5440_write_reg(sm5440, SM5440_REG_CNTL2, 0xF2); /* disable IBUSOCP,IBATOCP,THEM */ + sm5440_write_reg(sm5440, SM5440_REG_CNTL3, 0xB8); /* disable CHGTMR */ + sm5440_write_reg(sm5440, SM5440_REG_CNTL4, 0xFF); /* used DEB:8ms */ + sm5440_write_reg(sm5440, SM5440_REG_CNTL6, 0x09); /* forced PWM mode, disable ENHIZ */ + sm5440_update_reg(sm5440, SM5440_REG_VBUSCNTL, 0x7, 0x7, 0); /* VBUS_OVP_TH=11V */ + sm5440_write_reg(sm5440, SM5440_REG_VOUTCNTL, 0x3F); /* VOUT=max */ + sm5440_write_reg(sm5440, SM5440_REG_PRTNCNTL, 0xFE); /* OCP,OVP setting */ + sm5440_update_reg(sm5440, SM5440_REG_ADCCNTL1, 1, 0x1, 3); /* ADC average sample = 32 */ + sm5440_write_reg(sm5440, SM5440_REG_ADCCNTL2, 0xDF); /* ADC channel setting */ + sm5440_write_reg(sm5440, SM5440_REG_THEMCNTL1, 0x0C); /* Thermal Regulation threshold = 120'C */ +} + static int sm5440_start_charging(struct sm5440_charger *sm5440) { struct sm_dc_info *sm_dc = select_sm_dc_info(sm5440); struct sm_dc_power_source_info ta; + int state = sm_dc_get_current_state(sm_dc); int ret; if (sm5440->cable_online < 1) { @@ -470,6 +497,17 @@ static int sm5440_start_charging(struct sm5440_charger *sm5440) __func__, sm5440->cable_online); return -ENODEV; } + + if (state < SM_DC_CHECK_VBAT) { + dev_info(sm5440->dev, "%s: charging off state (state=%d)\n", __func__, state); + ret = sm5440_sw_reset(sm5440); + if (ret < 0) { + dev_err(sm5440->dev, "%s: fail to sw reset(ret=%d)\n", __func__, ret); + return ret; + } + sm5440_init_reg_param(sm5440); + } + #if defined(MULTIPLE_4X) ret = get_wpc_mfd_max_power(sm5440, &ta); if (ret < 0) { @@ -478,9 +516,9 @@ static int sm5440_start_charging(struct sm5440_charger *sm5440) } /* 0 : DA935X_STATE_OFF - * 1 : DA935X_STATE_ONLINE_BYPASS - * 2 : DA935X_STATE_ONLINE_CONVERT - */ + * 1 : DA935X_STATE_ONLINE_BYPASS + * 2 : DA935X_STATE_ONLINE_CONVERT + */ set_divide4_mode(sm5440, 2); { @@ -666,7 +704,7 @@ static const char *sm5440_dc_state_str[] = { "NO_CHARGING", "DC_ERR", "CHARGING_DONE", "CHECK_VBAT", "PRESET_DC", "ADJUST_CC", "UPDATE_BAT", "CC_MODE", "CV_MODE" }; -static int psy_chg_get_ext_direct_charger_chg_status(struct sm5440_charger *sm5440, +static int psy_chg_get_ext_direct_charger_chg_status(struct sm5440_charger *sm5440, union power_supply_propval *val) { struct sm_dc_info *sm_dc = select_sm_dc_info(sm5440); @@ -683,7 +721,7 @@ static int sm5440_chg_get_property(struct power_supply *psy, union power_supply_propval *val) { struct sm5440_charger *sm5440 = power_supply_get_drvdata(psy); - enum power_supply_ext_property ext_psp = + enum power_supply_ext_property ext_psp = (enum power_supply_ext_property) psp; dev_info(sm5440->dev, "%s: psp=%d\n", __func__, psp); @@ -724,6 +762,7 @@ static int sm5440_chg_get_property(struct power_supply *psy, #if defined(MULTIPLE_4X) { union power_supply_propval value; + dev_err(sm5440->dev, "%s: %d\n", __func__, ext_psp); psy_do_property("da935x-usb", get, (enum power_supply_property)ext_psp, value); @@ -758,6 +797,8 @@ static int psy_chg_set_online(struct sm5440_charger *sm5440, int online) { struct sm_dc_info *sm_dc = select_sm_dc_info(sm5440); int ret = 0; + u8 vbus_pok = 0x0; + u8 reg = 0x0; dev_info(sm5440->dev, "%s: online=%d\n", __func__, online); @@ -768,7 +809,11 @@ static int psy_chg_set_online(struct sm5440_charger *sm5440, int online) } sm5440->cable_online = online; - sm5440->vbus_in = sm5440->cable_online > 1 ? true : false; + sm5440_read_reg(sm5440, SM5440_REG_STATUS3, ®); + dev_info(sm5440->dev, "%s: STATUS3=0x%x\n", __func__, reg); + vbus_pok = (reg >> 5) & 0x1; + + sm5440->vbus_in = vbus_pok; sm5440_set_ENHIZ(sm5440, sm5440->vbus_in, sm5440_check_charging_enable(sm5440)); if (sm5440->wpc_dc) { @@ -828,10 +873,13 @@ static int psy_chg_set_input_curr(struct sm5440_charger *sm5440, int ibus) static int psy_chg_ext_direct_float_max(struct sm5440_charger *sm5440, int max_vbat) { + struct sm_dc_info *sm_dc = select_sm_dc_info(sm5440); + dev_info(sm5440->dev, "%s: max_vbat [%dmA] to [%dmA]\n", __func__, sm5440->max_vbat, max_vbat); sm5440->max_vbat = max_vbat; + sm_dc->config.chg_float_voltage = max_vbat; return 0; @@ -849,20 +897,21 @@ static int psy_chg_ext_wdt_control(struct sm5440_charger *sm5440, int wdt_contro return 0; } +static int sm5440_set_adc_mode(struct i2c_client *i2c, u8 mode); static int sm5440_chg_set_property(struct power_supply *psy, enum power_supply_property psp, const union power_supply_propval *val) { struct sm5440_charger *sm5440 = power_supply_get_drvdata(psy); - enum power_supply_ext_property ext_psp = + enum power_supply_ext_property ext_psp = (enum power_supply_ext_property) psp; - int ret; + int ret = 0; dev_info(sm5440->dev, "%s: psp=%d, val-intval=%d\n", __func__, psp, val->intval); - switch (psp) { + switch (psp) { case POWER_SUPPLY_PROP_ONLINE: psy_chg_set_online(sm5440, val->intval); break; @@ -899,10 +948,10 @@ static int sm5440_chg_set_property(struct power_supply *psy, ret = psy_chg_ext_direct_float_max(sm5440, val->intval); break; case POWER_SUPPLY_EXT_PROP_DIRECT_ADC_CTRL: - /** - * Need to check operation details.. by SEC. - */ - dev_err(sm5440->dev, "%s: need to works\n", __func__); + if (val->intval) + sm5440_set_adc_mode(sm5440->i2c, SM_DC_ADC_MODE_ONESHOT); + else + sm5440_set_adc_mode(sm5440->i2c, SM_DC_ADC_MODE_OFF); break; #if defined(MULTIPLE_4X) case POWER_SUPPLY_EXT_PROP_CHARGE_BOOST: @@ -947,7 +996,7 @@ static const struct power_supply_desc sm5440_charger_power_supply_desc = { .name = "sm5440-charger", .type = POWER_SUPPLY_TYPE_UNKNOWN, .get_property = sm5440_chg_get_property, - .set_property = sm5440_chg_set_property, + .set_property = sm5440_chg_set_property, .properties = sm5440_charger_props, .num_properties = ARRAY_SIZE(sm5440_charger_props), }; @@ -1207,6 +1256,7 @@ static int sm5440_send_wpc_msg(struct i2c_client *i2c, struct sm_dc_power_source if (is_hv_wireless_type(sm5440->cable_online)) { union power_supply_propval value; + value.intval = pps_v; ret = psy_do_property("mfc-charger", set, POWER_SUPPLY_EXT_PROP_WIRELESS_SET_VOUT, value); } else { @@ -1247,13 +1297,13 @@ static void sm5440_adc_work(struct work_struct *work) static void sm5440_ocp_check_work(struct work_struct *work) { - struct sm5440_charger *sm5440 = container_of(work, struct sm5440_charger, + struct sm5440_charger *sm5440 = container_of(work, struct sm5440_charger, ocp_check_work.work); struct sm_dc_info *sm_dc = select_sm_dc_info(sm5440); int i; u8 reg; - for (i=0; i < 3; ++i) { + for (i = 0; i < 3; ++i) { sm5440_read_reg(sm5440, SM5440_REG_STATUS2, ®); if (reg & (0x1 << 7)) { /* activate IBUSLIM */ dev_err(sm5440->dev, "%s: detect IBUSLIM (i=%d)\n", __func__, i); @@ -1332,7 +1382,7 @@ static irqreturn_t sm5440_irq_thread(int irq, void *data) dev_info(sm5440->dev, "%s: VBUS UVLO detected\n", __func__); psy_do_property("da935x-wireless", get, POWER_SUPPLY_PROP_ONLINE, value); - pr_info("%s: DC Error Occured. Check da9352 wireless online : %d\n", + pr_info("%s: DC Error Occurred. Check da9352 wireless online : %d\n", __func__, value.intval); if (value.intval == 2) sm5440_irq_vbus_uvlo(sm5440); @@ -1371,7 +1421,7 @@ static int sm5440_irq_init(struct sm5440_charger *sm5440) sm5440_write_reg(sm5440, SM5440_REG_MSK3, 0x18); sm5440_write_reg(sm5440, SM5440_REG_MSK4, 0xF8); - ret = request_threaded_irq(sm5440->irq, NULL, sm5440_irq_thread, + ret = request_threaded_irq(sm5440->irq, NULL, sm5440_irq_thread, IRQF_TRIGGER_LOW | IRQF_ONESHOT, "sm5440-irq", sm5440); if (ret) { @@ -1397,19 +1447,7 @@ static int sm5440_hw_init_config(struct sm5440_charger *sm5440) } sm5440->pdata->rev_id = (reg >> 4) & 0xf; - sm5440_set_wdt_timer(sm5440, WDT_TIMER_S_30); - sm5440_set_freq(sm5440, sm5440->pdata->freq); - - sm5440_write_reg(sm5440, SM5440_REG_CNTL2, 0xF2); /* disable IBUSOCP,IBATOCP,THEM */ - sm5440_write_reg(sm5440, SM5440_REG_CNTL3, 0xB8); /* disable CHGTMR */ - sm5440_write_reg(sm5440, SM5440_REG_CNTL4, 0xFF); /* used DEB:8ms */ - sm5440_write_reg(sm5440, SM5440_REG_CNTL6, 0x09); /* forced PWM mode, disable ENHIZ */ - sm5440_update_reg(sm5440, SM5440_REG_VBUSCNTL, 0x7, 0x7, 0); /* VBUS_OVP_TH=11V */ - sm5440_write_reg(sm5440, SM5440_REG_VOUTCNTL, 0x3F); /* VOUT=max */ - sm5440_write_reg(sm5440, SM5440_REG_PRTNCNTL, 0xFE); /* OCP,OVP setting */ - sm5440_update_reg(sm5440, SM5440_REG_ADCCNTL1, 1, 0x1, 3); /* ADC average sample = 32 */ - sm5440_write_reg(sm5440, SM5440_REG_ADCCNTL2, 0xDF); /* ADC channel setting */ - sm5440_write_reg(sm5440, SM5440_REG_THEMCNTL1, 0x0C); /* Thermal Regulation threshold = 120'C */ + sm5440_init_reg_param(sm5440); #if defined(CONFIG_BATTERY_SAMSUNG) psy_chg_set_const_chg_voltage(sm5440, sm5440->pdata->battery.chg_float_voltage); @@ -1419,7 +1457,7 @@ static int sm5440_hw_init_config(struct sm5440_charger *sm5440) } #if defined(CONFIG_OF) -static int sm5440_charger_parse_dt(struct device *dev, +static int sm5440_charger_parse_dt(struct device *dev, struct sm5440_platform_data *pdata) { struct device_node *np_sm5440 = dev->of_node; @@ -1427,7 +1465,7 @@ static int sm5440_charger_parse_dt(struct device *dev, int ret; /* Parse: sm5440 node */ - if(!np_sm5440) { + if (!np_sm5440) { dev_err(dev, "%s: empty of_node for sm5440_dev\n", __func__); return -EINVAL; } @@ -1442,7 +1480,7 @@ static int sm5440_charger_parse_dt(struct device *dev, /* Parse: battery node */ np_battery = of_find_node_by_name(NULL, "battery"); - if(!np_battery) { + if (!np_battery) { dev_err(dev, "%s: empty of_node for battery\n", __func__); return -EINVAL; } @@ -1667,7 +1705,7 @@ static int sm5440_dbg_write_reg(void *data, u64 val) return 0; } -DEFINE_SIMPLE_ATTRIBUTE(register_debug_ops, sm5440_dbg_read_reg, +DEFINE_SIMPLE_ATTRIBUTE(register_debug_ops, sm5440_dbg_read_reg, sm5440_dbg_write_reg, "0x%02llx\n"); static int sm5440_create_debugfs_entries(struct sm5440_charger *sm5440) @@ -1859,7 +1897,6 @@ static int sm5440_charger_remove(struct i2c_client *i2c) struct sm5440_charger *sm5440 = i2c_get_clientdata(i2c); sm5440_stop_charging(sm5440); - sm5440_sw_reset(sm5440); power_supply_unregister(sm5440->psy_chg); mutex_destroy(&sm5440->i2c_lock); @@ -1938,7 +1975,7 @@ static struct i2c_driver sm5440_charger_driver = { #endif /* CONFIG_OF */ #if defined(CONFIG_PM) .pm = &sm5440_pm_ops, -#endif /* CONFIG_PM */ +#endif /* CONFIG_PM */ }, .probe = sm5440_charger_probe, .remove = sm5440_charger_remove, diff --git a/drivers/battery/charger/sm_direct_charger.c b/drivers/battery/charger/sm_direct_charger.c index d584274a43cd..cb6dd19e1afa 100755 --- a/drivers/battery/charger/sm_direct_charger.c +++ b/drivers/battery/charger/sm_direct_charger.c @@ -30,7 +30,7 @@ static u32 pps_v(u32 vol) } static u32 pps_c(u32 cur) -{ +{ if ((cur % PPS_C_STEP) >= (PPS_C_STEP / 2)) cur += PPS_C_STEP; @@ -144,13 +144,13 @@ static int update_work_state(struct sm_dc_info *sm_dc, u8 state) pr_info("%s %s: changed chg param, request: update_bat\n", sm_dc->name, __func__); request_state_work(sm_dc, SM_DC_UPDAT_BAT, DELAY_NONE); ret = -EINVAL; - } else { - if (sm_dc->state != state) { - mutex_lock(&sm_dc->st_lock); - sm_dc->state = state; - mutex_unlock(&sm_dc->st_lock); - report_dc_state(sm_dc); - } + } + + if (sm_dc->state != state) { + mutex_lock(&sm_dc->st_lock); + sm_dc->state = state; + mutex_unlock(&sm_dc->st_lock); + report_dc_state(sm_dc); } return ret; @@ -165,7 +165,7 @@ static int send_power_source_msg(struct sm_dc_info *sm_dc) if (sm_dc->ta.v > sm_dc->ta.v_max || sm_dc->ta.c > sm_dc->ta.c_max) { pr_err("%s %s: ERROR: out of bounce v=%dmV(max=%dmV) c=%dmA(max=%dmA)\n", - sm_dc->name, __func__, sm_dc->ta.v, sm_dc->ta.v_max, + sm_dc->name, __func__, sm_dc->ta.v, sm_dc->ta.v_max, sm_dc->ta.c, sm_dc->ta.c_max); sm_dc->err = SM_DC_ERR_SEND_PD_MSG; @@ -243,7 +243,7 @@ static int check_error_state(struct sm_dc_info *sm_dc, u8 retry_state) return 0; } -static int get_adc_values(struct sm_dc_info *sm_dc, const char *str, int *vbus, int *ibus, int *vout, +static int get_adc_values(struct sm_dc_info *sm_dc, const char *str, int *vbus, int *ibus, int *vout, int *vbat, int *ibat, int *them, int *dietemp) { int adc_vbus, adc_ibus, adc_vout, adc_vbat, adc_ibat, adc_them, adc_dietemp; @@ -311,7 +311,19 @@ static inline u32 _calc_pps_v_init_offset(struct sm_dc_info *sm_dc) offset = (sm_dc->ta.c * (sm_dc->config.pps_lr + sm_dc->config.rpara + (sm_dc->config.rsns * 2) + (sm_dc->config.rpcm * 2))) / 1000000; offset += 200; /* add to extra initial offset */ - pr_info("%s %s: pps_c=%dmA, v_init_offset=%d\n", sm_dc->name, __func__, sm_dc->ta.c, offset); + pr_info("%s %s: pps_c=%dmA, v_init_offset=%dmV\n", sm_dc->name, __func__, sm_dc->ta.c, offset); + + return offset; +} + +static inline u32 _calc_ibus_voffset(struct sm_dc_info *sm_dc, int adc_ibus) +{ + u32 offset; + + offset = ((sm_dc->ta.c - adc_ibus) * (sm_dc->config.pps_lr + sm_dc->config.rpara + + (sm_dc->config.rsns * 2) + (sm_dc->config.rpcm * 2))) / 1000000; + offset = pps_v((offset > PPS_V_STEP * 10) ? (PPS_V_STEP * 10) : offset); + pr_info("%s %s: offset=%dmV\n", sm_dc->name, __func__, offset); return offset; } @@ -362,8 +374,8 @@ static inline int _pd_pre_cc_check_limitation(struct sm_dc_info *sm_dc, int adc_ } if ((adc_ibus > sm_dc->ta.c - PRE_CC_ST_IBUS_OFFSET) && - (adc_vbus < sm_dc->wq.prev_adc_vbus + (PPS_V_STEP/2)) && - (adc_ibus < sm_dc->wq.prev_adc_ibus + (PPS_C_STEP)) && + (adc_vbus < sm_dc->wq.prev_adc_vbus + (PPS_V_STEP * 2)) && + (adc_ibus < sm_dc->wq.prev_adc_ibus + (PPS_C_STEP * 2)) && (sm_dc->wq.c_down == 0 && sm_dc->wq.pps_cl == 0)) { ret = 1; } else if (sm_dc->wq.ci_gl == sm_dc->config.ta_min_current) { /* Case: didn't reduce PPS_C than TA_MIN_C */ @@ -385,7 +397,7 @@ static inline int _pd_pre_cc_check_limitation(struct sm_dc_info *sm_dc, int adc_ return ret; } -static inline int _try_to_adjust_cc(struct sm_dc_info *sm_dc) +static inline int _try_to_adjust_cc_up(struct sm_dc_info *sm_dc) { sm_dc->wq.cc_cnt += 1; @@ -396,15 +408,19 @@ static inline int _try_to_adjust_cc(struct sm_dc_info *sm_dc) sm_dc->ta.v = sm_dc->ta.v_max; } else { sm_dc->ta.c += PPS_C_STEP; + if (sm_dc->ta.c > sm_dc->ta.c_max) + sm_dc->ta.c = sm_dc->ta.c_max; } } else { - if (sm_dc->ta.c + PPS_C_STEP <= sm_dc->target_ibus) + if (sm_dc->ta.c + PPS_C_STEP <= sm_dc->target_ibus) { sm_dc->ta.c += PPS_C_STEP; + if (sm_dc->ta.c > sm_dc->ta.c_max) + sm_dc->ta.c = sm_dc->ta.c_max; + } } - if ((sm_dc->ta.v * sm_dc->ta.c >= sm_dc->ta.p_max) || (sm_dc->ta.v == sm_dc->ta.v_max) || (sm_dc->ta.c == sm_dc->ta.c_max)) { - pr_info("%s %s: PPS-TA has been reached limitation(v=%dmV, c=%dmA)\n", + pr_info("%s %s: PPS-TA has been reached limitation(v=%dmV, c=%dmA)\n", sm_dc->name, __func__, sm_dc->ta.v, sm_dc->ta.c); sm_dc->wq.cc_limit = 1; @@ -414,6 +430,17 @@ static inline int _try_to_adjust_cc(struct sm_dc_info *sm_dc) return 0; } +static inline void _try_to_adjust_cc_down(struct sm_dc_info *sm_dc) +{ + sm_dc->wq.cc_cnt += 1; + + if (sm_dc->wq.cc_cnt % 2) + sm_dc->ta.c -= PPS_C_STEP; + else + sm_dc->ta.v -= PPS_V_STEP; + + return; +} static void pd_check_vbat_work(struct work_struct *work) { @@ -542,6 +569,18 @@ static void pd_pre_cc_work(struct work_struct *work) return; } sm_dc->ta.c -= PPS_C_STEP; + if(sm_dc->ta.c < sm_dc->config.ta_min_current) { + sm_dc->ta.c = sm_dc->config.ta_min_current; + pr_info("%s %s: can't used less then ta_min_current\n", + sm_dc->name, __func__); + sm_dc->ta.v -= PPS_V_STEP; + if(sm_dc->ta.v < sm_dc->config.ta_min_voltage) { + pr_err("%s %s: SM_DC_ERR_FAIL_ADJUST\n", sm_dc->name, __func__); + sm_dc->err = SM_DC_ERR_FAIL_ADJUST; + request_state_work(sm_dc, SM_DC_ERR, DELAY_NONE); + return; + } + } ret = send_power_source_msg(sm_dc); if (ret < 0) return; @@ -581,7 +620,9 @@ static void pd_pre_cc_work(struct work_struct *work) return; } - if ((sm_dc->wq.pps_cl) && (sm_dc->ta.v * (sm_dc->ta.c + PPS_C_STEP) >= sm_dc->ta.p_max)) { + if ((sm_dc->wq.pps_cl) && + ((sm_dc->ta.v * (sm_dc->ta.c + PPS_C_STEP) >= sm_dc->ta.p_max) || + ((sm_dc->ta.c + PPS_C_STEP) >= sm_dc->ta.c_max))) { sm_dc->wq.c_offset = 0; sm_dc->wq.cc_limit = 0; sm_dc->wq.cc_cnt = 0; @@ -590,22 +631,48 @@ static void pd_pre_cc_work(struct work_struct *work) request_state_work(sm_dc, SM_DC_CC, DELAY_ADC_UPDATE); return; } +#if defined(CONFIG_SEC_FACTORY) + if (sm_dc->wq.pps_cl) { + if ((adc_ibus < sm_dc->wq.ci_gl - (PPS_C_STEP * 12)) && + (sm_dc->ta.c < sm_dc->wq.ci_gl - (PPS_C_STEP * 12))) + sm_dc->ta.c += (PPS_C_STEP * 10); + else if ((adc_ibus < sm_dc->wq.ci_gl - (PPS_C_STEP * 7)) && + (sm_dc->ta.c < sm_dc->wq.ci_gl - (PPS_C_STEP * 7))) + sm_dc->ta.c += (PPS_C_STEP * 5); + else if ((adc_ibus < sm_dc->wq.ci_gl - (PPS_C_STEP * 4)) && + (sm_dc->ta.c < sm_dc->wq.ci_gl - (PPS_C_STEP * 4))) + sm_dc->ta.c += (PPS_C_STEP * 2); + else + sm_dc->ta.c += PPS_C_STEP; + ret = send_power_source_msg(sm_dc); + if (ret < 0) + return; + sm_dc->wq.c_up = 1; + sm_dc->wq.c_down = 0; + } else { + if (((adc_ibus < sm_dc->ta.c - (PPS_C_STEP * 4)) && (sm_dc->wq.v_up != 1)) || + (adc_ibus < sm_dc->wq.prev_adc_ibus - PPS_C_STEP)) + sm_dc->ta.v += _calc_ibus_voffset(sm_dc, adc_ibus); + else + sm_dc->ta.v += PPS_V_STEP * 2; + ret = send_power_source_msg(sm_dc); + if (ret < 0) + return; + sm_dc->wq.v_up = 1; + sm_dc->wq.v_down = 0; + } +#else if (sm_dc->wq.pps_cl) { if ((adc_ibus < sm_dc->wq.ci_gl - (PPS_C_STEP * 6)) && (sm_dc->ta.c < ((sm_dc->wq.ci_gl * 90)/100))) -#if defined(CONFIG_SEC_FACTORY) - sm_dc->ta.c += (PPS_C_STEP * 5); -#else sm_dc->ta.c += (PPS_C_STEP * 3); -#endif else sm_dc->ta.c += PPS_C_STEP; ret = send_power_source_msg(sm_dc); if (ret < 0) return; - sm_dc->wq.c_up = 1; sm_dc->wq.c_down = 0; } else { @@ -613,10 +680,10 @@ static void pd_pre_cc_work(struct work_struct *work) ret = send_power_source_msg(sm_dc); if (ret < 0) return; - sm_dc->wq.v_up = 1; sm_dc->wq.v_down = 0; } +#endif sm_dc->wq.prev_adc_vbus = adc_vbus; sm_dc->wq.prev_adc_ibus = adc_ibus; @@ -659,6 +726,18 @@ static void pd_cc_work(struct work_struct *work) break; } + /* CC_STEP_DOWN */ + if (sm_dc->wq.ci_gl + CC_ST_IBUS_OFFSET < adc_ibus && (sm_dc->wq.cc_limit == 0)) { + _try_to_adjust_cc_down(sm_dc); + if (sm_dc->config.support_pd_remain) { + ret = send_power_source_msg(sm_dc); + if (ret < 0) + return; + } + request_state_work(sm_dc, SM_DC_CC, DELAY_ADC_UPDATE); + return; + } + if (adc_ibus >= sm_dc->wq.ci_gl - CC_ST_IBUS_OFFSET || sm_dc->wq.cc_limit) { if (sm_dc->config.support_pd_remain) { ret = send_power_source_msg(sm_dc); @@ -669,7 +748,8 @@ static void pd_cc_work(struct work_struct *work) return; } - ret = _try_to_adjust_cc(sm_dc); + /* CC_STEP_UP */ + ret = _try_to_adjust_cc_up(sm_dc); if (ret < 0) { if (sm_dc->config.support_pd_remain) { ret = send_power_source_msg(sm_dc); @@ -724,6 +804,13 @@ static void pd_cv_work(struct work_struct *work) return; delay = DELAY_PPS_UPDATE; + } else if (loop_status & LOOP_THEMREG) { + if (sm_dc->config.support_pd_remain) { + ret = send_power_source_msg(sm_dc); + if (ret < 0) + return; + } + delay = DELAY_PPS_UPDATE; } /* occurred abnormal CV status */ @@ -1070,7 +1157,7 @@ static void wpc_pre_cc_work(struct work_struct *work) } if ((sm_dc->ta.v + WPC_V_STEP) >= sm_dc->ta.v_max) { - pr_info("%s %s: can't increase voltage(v:%d v_max:%d)\n", sm_dc->name, + pr_info("%s %s: can't increase voltage(v:%d v_max:%d)\n", sm_dc->name, __func__, sm_dc->ta.v, sm_dc->ta.v_max); pr_info("%s %s: [request] pre_cc -> cc\n", sm_dc->name, __func__); sm_dc->ops->set_adc_mode(sm_dc->i2c, SM_DC_ADC_MODE_CONTINUOUS); @@ -1154,7 +1241,8 @@ static void wpc_cc_work(struct work_struct *work) pr_info("%s %s: Changed WPC Msg\n", sm_dc->name, __func__); sm_dc->ta.v = _wpc_calc_voltage(sm_dc, sm_dc->ta.v, dir); if (sm_dc->ta.v >= sm_dc->ta.v_max) { - pr_info("%s %s: can't increase wpc_v(v:%d, v_max:%d)\n", sm_dc->name, __func__, sm_dc->ta.v, sm_dc->ta.v_max); + pr_info("%s %s: can't increase wpc_v(v:%d, v_max:%d)\n", + sm_dc->name, __func__, sm_dc->ta.v, sm_dc->ta.v_max); sm_dc->ta.v = sm_dc->ta.v_max; ret = send_power_source_msg(sm_dc); if (ret < 0) @@ -1308,7 +1396,7 @@ static void wpc_error_work(struct work_struct *work) /** * SM Direct-charging module management APIs */ -struct sm_dc_info *sm_dc_create_pd_instance(const char* name, struct i2c_client *i2c) +struct sm_dc_info *sm_dc_create_pd_instance(const char *name, struct i2c_client *i2c) { struct sm_dc_info *sm_dc; int ret; @@ -1350,7 +1438,7 @@ err_kmem: } EXPORT_SYMBOL(sm_dc_create_pd_instance); -struct sm_dc_info *sm_dc_create_wpc_instance(const char* name, struct i2c_client *i2c) +struct sm_dc_info *sm_dc_create_wpc_instance(const char *name, struct i2c_client *i2c) { struct sm_dc_info *sm_dc; int ret; diff --git a/drivers/battery_v2/include/sec_battery.h b/drivers/battery_v2/include/sec_battery.h index 627f73a181cb..4f20b73e3ad6 100755 --- a/drivers/battery_v2/include/sec_battery.h +++ b/drivers/battery_v2/include/sec_battery.h @@ -183,8 +183,9 @@ struct sec_bat_pdic_info { #endif }; +#define MAX_PDO_NUM 8 struct sec_bat_pdic_list { - struct sec_bat_pdic_info pd_info[8]; /* 5V ~ 12V */ + struct sec_bat_pdic_info pd_info[MAX_PDO_NUM]; /* 5V ~ 12V */ unsigned int now_pd_index; unsigned int max_pd_count; #if defined(CONFIG_PDIC_PD30) diff --git a/drivers/battery_v2/sec_battery.c b/drivers/battery_v2/sec_battery.c index 05c6133cbc28..27c932e805a4 100755 --- a/drivers/battery_v2/sec_battery.c +++ b/drivers/battery_v2/sec_battery.c @@ -482,7 +482,7 @@ static void sec_bat_get_charging_current_by_siop(struct sec_battery_info *batter static void sec_bat_change_pdo(struct sec_battery_info *battery, int vol) { - unsigned int target_pd_index = 0; + int target_pd_index = 0; if (is_pd_wire_type(battery->wire_status)) { @@ -497,6 +497,12 @@ static void sec_bat_change_pdo(struct sec_battery_info *battery, int vol) /* select 5V PDO */ target_pd_index = 0; } + + if (target_pd_index < 0 || target_pd_index >= MAX_PDO_NUM) { + pr_info("%s: target_pd_index is wrong %d\n", __func__, target_pd_index); + return; + } + pr_info("%s: target_pd_index: %d, now_pd_index: %d\n", __func__, target_pd_index, battery->pd_list.now_pd_index); @@ -520,7 +526,8 @@ static void sec_bat_change_pdo(struct sec_battery_info *battery, int vol) POWER_SUPPLY_PROP_CURRENT_MAX, value); } battery->pdic_ps_rdy = false; - select_pdo(battery->pd_list.pd_info[target_pd_index].pdo_index); + if (target_pd_index >= 0 && target_pd_index < MAX_PDO_NUM) + select_pdo(battery->pd_list.pd_info[target_pd_index].pdo_index); } } } @@ -926,7 +933,7 @@ extern void select_pdo(int num); static bool sec_bat_change_vbus_pd(struct sec_battery_info *battery, int *input_current) { #if defined(CONFIG_SUPPORT_HV_CTRL) - unsigned int target_pd_index = 0; + int target_pd_index = 0; if (battery->pdata->chg_temp_check_type == SEC_BATTERY_TEMP_CHECK_NONE) return false; @@ -948,6 +955,12 @@ static bool sec_bat_change_vbus_pd(struct sec_battery_info *battery, int *input_ /* select 5V PDO */ target_pd_index = 0; } + + if (target_pd_index < 0 || target_pd_index >= MAX_PDO_NUM) { + pr_info("%s: target_pd_index is wrong %d\n", __func__, target_pd_index); + return; + } + pr_info("%s: target_pd_index: %d, now_pd_index: %d\n", __func__, target_pd_index, battery->pd_list.now_pd_index); @@ -975,7 +988,9 @@ static bool sec_bat_change_vbus_pd(struct sec_battery_info *battery, int *input_ battery->pdic_ps_rdy = false; sec_bat_set_current_event(battery, SEC_BAT_CURRENT_EVENT_SELECT_PDO, SEC_BAT_CURRENT_EVENT_SELECT_PDO); - select_pdo(battery->pd_list.pd_info[target_pd_index].pdo_index); + if (target_pd_index >= 0 && target_pd_index < MAX_PDO_NUM) + select_pdo(battery->pd_list.pd_info[target_pd_index].pdo_index); + return true; } } @@ -1285,6 +1300,12 @@ int sec_bat_set_charging_current(struct sec_battery_info *battery) (battery->charging_current != charging_current)) { /* update charge power */ battery->charge_power = battery->input_voltage * input_current; + + if (battery->current_event & SEC_BAT_CURRENT_EVENT_HV_DISABLE) { + if (battery->charge_power > battery->pdata->nv_charge_power) + battery->charge_power = battery->pdata->nv_charge_power; + } + if (battery->charge_power > battery->max_charge_power) battery->max_charge_power = battery->charge_power; @@ -5621,6 +5642,7 @@ static int sec_bat_set_property(struct power_supply *psy, int full_check_type = SEC_BATTERY_FULLCHARGED_NONE; union power_supply_propval value = {0, }; enum power_supply_ext_property ext_psp = (enum power_supply_ext_property) psp; + int target_pd_index = 0; dev_dbg(battery->dev, "%s: (%d,%d)\n", __func__, psp, val->intval); @@ -5847,14 +5869,20 @@ static int sec_bat_set_property(struct power_supply *psy, sec_bat_set_current_event(battery, 0, SEC_BAT_CURRENT_EVENT_HV_DISABLE); - if (is_pd_wire_type(battery->cable_type)) { - battery->update_pd_list = true; - pr_info("%s: update pd list\n", __func__); #if defined(CONFIG_PDIC_PD30) - select_pdo(battery->pd_list.pd_info[battery->pd_list.num_fpdo - 1].pdo_index); + target_pd_index = battery->pd_list.num_fpdo - 1; #else - select_pdo(battery->pd_list.pd_info[battery->pd_list.max_pd_count - 1].pdo_index); + target_pd_index = battery->pd_list.max_pd_count - 1; #endif + if (target_pd_index < 0 || target_pd_index >= MAX_PDO_NUM) { + pr_info("%s: target_pd_index is wrong %d\n", __func__, target_pd_index); + return 0; + } + if (is_pd_wire_type(battery->cable_type)) { + battery->update_pd_list = true; + pr_info("%s: update pd list\n", __func__); + + select_pdo(battery->pd_list.pd_info[target_pd_index].pdo_index); } } break; @@ -7087,7 +7115,7 @@ static int make_pd_list(struct sec_battery_info *battery) { pPower_list = &battery->pdic_info.sink_status.power_list[i]; - if (pPower_list->apdo) { + if (pPower_list->apdo && pd_list_index >= 0 && pd_list_index < MAX_PDO_NUM) { battery->pd_list.pd_info[pd_list_index].pdo_index = i; battery->pd_list.pd_info[pd_list_index].apdo = true; battery->pd_list.pd_info[pd_list_index].max_voltage = pPower_list->max_voltage; @@ -7106,8 +7134,8 @@ static int make_pd_list(struct sec_battery_info *battery) num_pd_list = pd_list_index; - if (num_pd_list <= 0) { - pr_info("%s : PDO list is empty!!\n", __func__); + if (num_pd_list <= 0 || num_pd_list > MAX_PDO_NUM) { + pr_info("%s : PDO list is wrong: %d\n", __func__, num_pd_list); return 0; } else { #if defined(CONFIG_PDIC_PD30) @@ -7133,6 +7161,10 @@ static int make_pd_list(struct sec_battery_info *battery) #else pd_list_select = num_pd_list - 1; #endif + if (pd_list_select < 0 || pd_list_select >= MAX_PDO_NUM) { + pr_info("%s : pd_list_select is wrong: %d\n", __func__, pd_list_select); + return 0; + } for (i = 0; i < num_pd_list; i++) { #if defined(CONFIG_PDIC_PD30) @@ -7199,7 +7231,8 @@ static int make_pd_list(struct sec_battery_info *battery) battery->pdic_ps_rdy = false; sec_bat_set_current_event(battery, SEC_BAT_CURRENT_EVENT_SELECT_PDO, SEC_BAT_CURRENT_EVENT_SELECT_PDO); - select_pdo(battery->pd_list.pd_info[pd_list_select].pdo_index); + if (pd_list_select >= 0 && pd_list_select < MAX_PDO_NUM) + select_pdo(battery->pd_list.pd_info[pd_list_select].pdo_index); } battery->pd_list.now_pd_index = sec_bat_get_pd_list_index(&battery->pdic_info.sink_status, diff --git a/drivers/battery_v2/sec_battery_sysfs.c b/drivers/battery_v2/sec_battery_sysfs.c index e48b0d30c289..782f5418f24b 100755 --- a/drivers/battery_v2/sec_battery_sysfs.c +++ b/drivers/battery_v2/sec_battery_sysfs.c @@ -690,6 +690,8 @@ ssize_t sec_bat_show_attrs(struct device *dev, battery->max_charge_power >= HV_CHARGER_STATUS_STANDARD1) /* 12000mW */ check_val = AFC_9V_OR_15W; } + pr_info("%s : HV_CHARGER_STATUS(%d) pd max charge power(%d), max_charge_power(%d)\n", + __func__, check_val, battery->pd_max_charge_power, battery->max_charge_power); i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", check_val); } break; diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c index a8461a5c8c44..344e62ac45ef 100755 --- a/drivers/block/zram/zram_drv.c +++ b/drivers/block/zram/zram_drv.c @@ -38,6 +38,12 @@ #include #include #include +#include +#include +#include +#include +#include +#include #include #include "zram_drv.h" @@ -351,10 +357,61 @@ static struct zram *g_zram; static struct notifier_block zram_app_launch_nb; static bool is_app_launch; +#define F2FS_IOCTL_MAGIC 0xf5 +#define F2FS_IOC_SET_PIN_FILE _IOW(F2FS_IOCTL_MAGIC, 13, __u32) +#define F2FS_SET_PIN_FILE 1 +static int zram_pin_backing_file(struct zram *zram) +{ + struct loop_device *lo = zram->bdev->bd_disk->private_data; + struct file *file = lo->lo_backing_file; + unsigned int cmd = F2FS_IOC_SET_PIN_FILE; + int __user *buf; + int set = F2FS_SET_PIN_FILE; + int ret; + + buf = compat_alloc_user_space(sizeof(*buf)); + if (!buf) { + pr_info("%s failed to compat_alloc_user_space\n", __func__); + return -ENOMEM; + } + copy_to_user(buf, &set, sizeof(int)); + ret = file->f_op->unlocked_ioctl(file, cmd, (unsigned long)buf); + pr_info("%s ioctl to pin file returned %d\n", __func__, ret); + + return ret; +} + +static void fallocate_block(struct zram *zram, unsigned long blk_idx) +{ + struct block_device *bdev = zram->bdev; + + if (!bdev) + return; + + mutex_lock(&zram->blk_bitmap_lock); + /* check 2MB block bitmap. if unset, fallocate 2MB block at once */ + if (!test_and_set_bit(blk_idx / NR_FALLOC_PAGES, zram->blk_bitmap)) { + struct loop_device *lo = bdev->bd_disk->private_data; + struct file *file = lo->lo_backing_file; + loff_t pos = (blk_idx & FALLOC_ALIGN_MASK) << PAGE_SHIFT; + loff_t len = NR_FALLOC_PAGES << PAGE_SHIFT; + int mode = FALLOC_FL_KEEP_SIZE; + int ret; + + file_start_write(file); + ret = file->f_op->fallocate(file, mode, pos, len); + if (ret) + pr_err("%s pos %lx failed %d\n", __func__, pos, ret); + file_end_write(file); + } + mutex_unlock(&zram->blk_bitmap_lock); +} + static int init_lru_writeback(struct zram *zram) { struct sched_param param = { .sched_priority = 0 }; int ret = 0; + int bitmap_sz; init_waitqueue_head(&zram->wbd_wait); zram->wb_table = kvzalloc(sizeof(u8) * zram->nr_pages, GFP_KERNEL); @@ -362,6 +419,27 @@ static int init_lru_writeback(struct zram *zram) ret = -ENOMEM; return ret; } + /* bitmap for 2MB block */ + bitmap_sz = (BITS_TO_LONGS(zram->nr_pages) * sizeof(long)) / NR_FALLOC_PAGES; + zram->blk_bitmap = kvzalloc(bitmap_sz, GFP_KERNEL); + if (!zram->blk_bitmap) { + ret = -ENOMEM; + goto out; + } + if (zram_pin_backing_file(zram)) { + ret = -EINVAL; + goto out; + } + + bitmap_sz = BITS_TO_LONGS(zram->nr_pages) * sizeof(long) / NR_ZWBS; + /* backing dev should be large enough for chunk writeback */ + if (!bitmap_sz) + return -EINVAL; + zram->chunk_bitmap = kvzalloc(bitmap_sz, GFP_KERNEL); + if (!zram->chunk_bitmap) { + ret = -ENOMEM; + goto out; + } zram->wbd = kthread_run(zram_wbd, zram, "%s_wbd", zram->disk->disk_name); if (IS_ERR(zram->wbd)) { @@ -375,6 +453,14 @@ static int init_lru_writeback(struct zram *zram) return ret; out: + if (zram->chunk_bitmap) { + kvfree(zram->chunk_bitmap); + zram->chunk_bitmap = NULL; + } + if (zram->blk_bitmap) { + kvfree(zram->blk_bitmap); + zram->blk_bitmap = NULL; + } kvfree(zram->wb_table); zram->wb_table = NULL; return ret; @@ -391,11 +477,22 @@ static void stop_lru_writeback(struct zram *zram) static void deinit_lru_writeback(struct zram *zram) { + unsigned long flags; + u8 *wb_table_tmp = zram->wb_table; + stop_lru_writeback(zram); - if (zram->wb_table) { - kvfree(zram->wb_table); - zram->wb_table = NULL; + if (zram->chunk_bitmap) { + kvfree(zram->chunk_bitmap); + zram->chunk_bitmap = NULL; } + if (zram->blk_bitmap) { + kvfree(zram->blk_bitmap); + zram->blk_bitmap = NULL; + } + spin_lock_irqsave(&zram->wb_table_lock, flags); + zram->wb_table = NULL; + spin_unlock_irqrestore(&zram->wb_table_lock, flags); + kvfree(wb_table_tmp); } #endif @@ -646,52 +743,150 @@ out: return err; } +#ifdef CONFIG_ZRAM_LRU_WRITEBACK +static unsigned long chunk_to_blk_idx(unsigned long idx) +{ + return idx * NR_ZWBS; +} +static unsigned long blk_to_chunk_idx(unsigned long idx) +{ + return idx / NR_ZWBS; +} + +static unsigned long alloc_chunk_bdev(struct zram *zram) +{ + unsigned long chunk_idx = 1; + unsigned long max_idx = zram->nr_pages / NR_ZWBS; + unsigned long blk_idx; + unsigned long flags; + int i; +retry: + /* skip 0 bit to confuse zram.handle = 0 */ + chunk_idx = find_next_zero_bit(zram->chunk_bitmap, max_idx, chunk_idx); + if (chunk_idx == max_idx) + return 0; + + spin_lock_irqsave(&zram->bitmap_lock, flags); + if (test_and_set_bit(chunk_idx, zram->chunk_bitmap)) { + spin_unlock_irqrestore(&zram->bitmap_lock, flags); + goto retry; + } + blk_idx = chunk_to_blk_idx(chunk_idx); + for (i = 0; i < NR_ZWBS; i++) + BUG_ON(test_and_set_bit(blk_idx + i, zram->bitmap)); + spin_unlock_irqrestore(&zram->bitmap_lock, flags); + atomic64_add(NR_ZWBS, &zram->stats.bd_count); + count_vm_events(SQZR_COUNT, NR_ZWBS); + return blk_idx; +} + static unsigned long alloc_block_bdev(struct zram *zram) { unsigned long blk_idx = 1; + unsigned long flags; retry: /* skip 0 bit to confuse zram.handle = 0 */ blk_idx = find_next_zero_bit(zram->bitmap, zram->nr_pages, blk_idx); if (blk_idx == zram->nr_pages) return 0; - if (test_and_set_bit(blk_idx, zram->bitmap)) + spin_lock_irqsave(&zram->bitmap_lock, flags); + if (test_and_set_bit(blk_idx, zram->bitmap)) { + spin_unlock_irqrestore(&zram->bitmap_lock, flags); goto retry; - + } + set_bit(blk_to_chunk_idx(blk_idx), zram->chunk_bitmap); + spin_unlock_irqrestore(&zram->bitmap_lock, flags); atomic64_inc(&zram->stats.bd_count); -#ifdef CONFIG_ZRAM_LRU_WRITEBACK count_vm_events(SQZR_COUNT, 1); -#endif return blk_idx; } -static void free_block_bdev(struct zram *zram, unsigned long blk_idx) +static unsigned long try_alloc_block_bdev(struct zram *zram, int *nr_pages) +{ + unsigned long blk_idx; + + /* found free chunk, return blk_idx */ + if (*nr_pages == NR_ZWBS) { + blk_idx = alloc_chunk_bdev(zram); + if (blk_idx) + return blk_idx; + } + *nr_pages = 1; + return alloc_block_bdev(zram); +} + +static void free_chunk_bdev(struct zram *zram, unsigned long chunk_idx) +{ + unsigned long blk_idx; + unsigned long flags; + int i; + + blk_idx = chunk_to_blk_idx(chunk_idx); + spin_lock_irqsave(&zram->bitmap_lock, flags); + for (i = 0; i < NR_ZWBS; i++) { + if (test_bit(blk_idx + i, zram->bitmap)) { + spin_unlock_irqrestore(&zram->bitmap_lock, flags); + return; + } + } + clear_bit(chunk_idx, zram->chunk_bitmap); + spin_unlock_irqrestore(&zram->bitmap_lock, flags); +} + +static void free_block_bdev(struct zram *zram, unsigned long blk_idx, bool ppr) { int was_set; -#ifdef CONFIG_ZRAM_LRU_WRITEBACK unsigned long flags; spin_lock_irqsave(&zram->wb_table_lock, flags); - if (zram->wb_table[blk_idx] == 0) { - count_vm_events(SQZR_COUNT, -1); - atomic64_dec(&zram->stats.bd_count); - spin_unlock_irqrestore(&zram->wb_table_lock, flags); - return; - } + if (!zram->wb_table || zram->wb_table[blk_idx] == 0) + goto out; zram->wb_table[blk_idx]--; atomic64_dec(&zram->stats.bd_objcnt); count_vm_events(SQZR_OBJCNT, -1); + if (ppr) + atomic64_dec(&zram->stats.bd_ppr_objcnt); if (zram->wb_table[blk_idx] > 0) { spin_unlock_irqrestore(&zram->wb_table_lock, flags); return; } +out: spin_unlock_irqrestore(&zram->wb_table_lock, flags); + was_set = test_and_clear_bit(blk_idx, zram->bitmap); + WARN_ON_ONCE(!was_set); + atomic64_dec(&zram->stats.bd_count); count_vm_events(SQZR_COUNT, -1); -#endif + if (ppr) + atomic64_dec(&zram->stats.bd_ppr_count); + free_chunk_bdev(zram, blk_to_chunk_idx(blk_idx)); +} +#else +static unsigned long alloc_block_bdev(struct zram *zram) +{ + unsigned long blk_idx = 1; +retry: + /* skip 0 bit to confuse zram.handle = 0 */ + blk_idx = find_next_zero_bit(zram->bitmap, zram->nr_pages, blk_idx); + if (blk_idx == zram->nr_pages) + return 0; + + if (test_and_set_bit(blk_idx, zram->bitmap)) + goto retry; + + atomic64_inc(&zram->stats.bd_count); + return blk_idx; +} + +static void free_block_bdev(struct zram *zram, unsigned long blk_idx) +{ + int was_set; + was_set = test_and_clear_bit(blk_idx, zram->bitmap); WARN_ON_ONCE(!was_set); atomic64_dec(&zram->stats.bd_count); } +#endif static void zram_page_end_io(struct bio *bio) { @@ -734,7 +929,7 @@ static int read_from_bdev_async(struct zram *zram, struct bio_vec *bvec, } #ifdef CONFIG_ZRAM_LRU_WRITEBACK -static int zram_balance_threshold = 5; /* min swap-used threshold */ +static int zram_balance_threshold = 25; /* min swap-used threshold */ static int zram_balance_ratio = 25; /* nand writeback ratio */ module_param(zram_balance_threshold, int, 0644); module_param(zram_balance_ratio, int, 0644); @@ -800,15 +995,18 @@ static u32 entry_to_index(struct zram *zram, struct zram_table_entry *entry) #define ABORT 2 static int zram_try_mark_page(struct zram *zram, u32 index) { + /* invalid index */ + if (index >= (zram->disksize >> PAGE_SHIFT)) + return ABORT; + if (!zram_slot_trylock(zram, index)) return SKIP; - if (!zram_allocated(zram, index)) { + if (!zram_allocated(zram, index) || + zram_test_flag(zram, index, ZRAM_UNDER_PPR)) { zram_slot_unlock(zram, index); return ABORT; - } - if (zram_test_flag(zram, index, ZRAM_SAME) || - zram_test_flag(zram, index, ZRAM_UNDER_WB)) { + } else if (zram_test_flag(zram, index, ZRAM_UNDER_WB)) { zram_slot_unlock(zram, index); return SKIP; } @@ -817,6 +1015,42 @@ static int zram_try_mark_page(struct zram *zram, u32 index) return 0; } +void free_zwbs(struct zwbs **zwbs) +{ + int i; + + for (i = 0; i < NR_ZWBS; i++) { + if (!zwbs[i]) + return; + if (zwbs[i]->page) + __free_page(zwbs[i]->page); + kfree(zwbs[i]); + } +} + +int alloc_zwbs(struct zwbs **zwbs) +{ + int i; + + for (i = 0; i < NR_ZWBS; i++) { + zwbs[i] = kzalloc(sizeof(struct zwbs), GFP_KERNEL); + if (!zwbs[i]) + goto out; + zwbs[i]->page = alloc_page(GFP_KERNEL); + if (!zwbs[i]->page) + goto out; + } + return 0; +out: + free_zwbs(zwbs); + return -ENOMEM; +} + +bool zram_is_app_launch(void) +{ + return is_app_launch; +} + #define ZRAM_WBD_INTERVAL 10 * HZ static bool zram_should_writeback(struct zram *zram, unsigned long pages, bool trigger) @@ -824,6 +1058,7 @@ static bool zram_should_writeback(struct zram *zram, unsigned long total = zram->disksize >> PAGE_SHIFT; unsigned long stored = atomic64_read(&zram->stats.pages_stored); unsigned long writtenback = atomic64_read(&zram->stats.bd_objcnt) - + atomic64_read(&zram->stats.bd_ppr_objcnt) - atomic64_read(&zram->stats.bd_expire); unsigned long min_stored = total * zram_balance_threshold / 100; int writtenback_ratio = stored ? (writtenback * 100) / stored : 0; @@ -861,10 +1096,17 @@ static bool zram_should_writeback(struct zram *zram, static void try_wakeup_zram_wbd(struct zram *zram) { + unsigned long bd_count; + if (zram->backing_dev && !zram->wbd_running && zram_wb_available(zram) && zram_should_writeback(zram, 0, true) && is_bdev_avail(zram)) { + bd_count = atomic64_read(&zram->stats.bd_count); + /* wakeup zram_wbd with enough free blocks */ + if (zram->nr_pages - bd_count < NR_ZWBS) + return; + zram->wbd_running = true; wake_up(&zram->wbd_wait); } @@ -885,9 +1127,11 @@ static struct notifier_block zram_app_launch_nb = { .notifier_call = zram_app_launch_notifier, }; -static void mark_end_of_page(struct page *page, int offset) +static void mark_end_of_page(struct zwbs *zwbs) { struct zram_wb_header *zhdr; + struct page *page = zwbs->page; + int offset = zwbs->off; void *mem; if (offset + sizeof(struct zram_wb_header) < PAGE_SIZE) { @@ -900,9 +1144,11 @@ static void mark_end_of_page(struct page *page, int offset) } static int zram_writeback_fill_page(struct zram *zram, u32 index, - struct page *page, int offset) + struct zwbs *zwbs) { struct zram_wb_header *zhdr; + struct page *page = zwbs->page; + int offset = zwbs->off; unsigned long handle; void *src, *dst; int ret, size; @@ -957,9 +1203,10 @@ static int zram_writeback_fill_page(struct zram *zram, u32 index, return ret; } -static void zram_writeback_clear_flag(struct zram *zram, - struct zram_wb_entry *entry, unsigned int count) +static void zram_writeback_clear_flag(struct zram *zram, struct zwbs *zwbs) { + struct zram_wb_entry *entry = zwbs->entry; + unsigned int count = zwbs->cnt; unsigned long index; int i; @@ -968,24 +1215,59 @@ static void zram_writeback_clear_flag(struct zram *zram, zram_slot_lock(zram, index); zram_clear_flag(zram, index, ZRAM_UNDER_WB); zram_clear_flag(zram, index, ZRAM_IDLE); + zram_clear_flag(zram, index, ZRAM_UNDER_PPR); zram_slot_unlock(zram, index); } } -static void zram_writeback_done(struct zram *zram, unsigned long blk_idx, - struct zram_wb_entry *entry, unsigned int count) +static void zram_update_max_stats(struct zram *zram) +{ + unsigned long bd_count, bd_size, bd_ppr_count, bd_ppr_size; + + bd_count = atomic64_read(&zram->stats.bd_count); + if (bd_count <= atomic64_read(&zram->stats.bd_max_count)) + return; + + bd_size = atomic64_read(&zram->stats.bd_size); + bd_ppr_count = atomic64_read(&zram->stats.bd_ppr_count); + bd_ppr_size = atomic64_read(&zram->stats.bd_ppr_size); + atomic64_set(&zram->stats.bd_max_count, bd_count); + atomic64_set(&zram->stats.bd_max_size, bd_size); + atomic64_set(&zram->stats.bd_ppr_max_count, bd_ppr_count); + atomic64_set(&zram->stats.bd_ppr_max_size, bd_ppr_size); +} + +static void zram_reset_stats(struct zram *zram) +{ + atomic64_set(&zram->stats.bd_max_count, 0); + atomic64_set(&zram->stats.bd_max_size, 0); + atomic64_set(&zram->stats.bd_ppr_max_count, 0); + atomic64_set(&zram->stats.bd_ppr_max_size, 0); +} + +static void zram_writeback_done(struct zram *zram, + struct zwbs *zwbs, unsigned long blk_idx, bool ppr) { unsigned long index; unsigned int offset; unsigned int size; + unsigned int count = zwbs->cnt; + struct zram_wb_entry *entry = zwbs->entry; int i; unsigned long flags; spin_lock_irqsave(&zram->wb_table_lock, flags); + if (!zram->wb_table) { + spin_unlock_irqrestore(&zram->wb_table_lock, flags); + return; + } zram->wb_table[blk_idx] = count; spin_unlock_irqrestore(&zram->wb_table_lock, flags); + atomic64_add(count, &zram->stats.bd_objwrites); atomic64_add(count, &zram->stats.bd_objcnt); count_vm_events(SQZR_OBJCNT, count); + if (ppr) + atomic64_add(count, &zram->stats.bd_ppr_objcnt); for (i = 0; i < count; i++) { index = entry[i].index; @@ -1005,14 +1287,20 @@ static void zram_writeback_done(struct zram *zram, unsigned long blk_idx, !zram_test_flag(zram, index, ZRAM_IDLE)) { zram_clear_flag(zram, index, ZRAM_UNDER_WB); zram_clear_flag(zram, index, ZRAM_IDLE); - free_block_bdev(zram, blk_idx); + zram_clear_flag(zram, index, ZRAM_UNDER_PPR); + free_block_bdev(zram, blk_idx, ppr); zram_slot_unlock(zram, index); - continue;; + continue; } zram_free_page(zram, index); zram_clear_flag(zram, index, ZRAM_UNDER_WB); zram_set_flag(zram, index, ZRAM_WB); + atomic64_add(size, &zram->stats.bd_size); + if (ppr) { + zram_set_flag(zram, index, ZRAM_PPR); + atomic64_add(size, &zram->stats.bd_ppr_size); + } /* record element as "blk_idx|offset|size" */ if (size == PAGE_SIZE) size = 0; @@ -1025,32 +1313,44 @@ static void zram_writeback_done(struct zram *zram, unsigned long blk_idx, static void zram_writeback_end_io(struct bio *bio) { - struct page *page = bio->bi_io_vec[0].bv_page; - struct zram *zram = (struct zram *)page_private(page); - - zram->io_complete = true; - wake_up(&zram->wbd_wait); + if (g_zram && !g_zram->io_complete) { + g_zram->io_complete = true; + wake_up(&g_zram->wbd_wait); + } } -static int zram_writeback_page(struct zram *zram, struct page *page, - struct zram_wb_entry *entry, int count, bool sync) +static int zram_writeback_page(struct zram *zram, struct zwbs **zwbs, + int nr_to_write, bool sync, bool ppr) { struct bio bio; - struct bio_vec bio_vec; + struct bio_vec *bio_vec; unsigned long blk_idx; int ret = 0; - - blk_idx = alloc_block_bdev(zram); + int i, idx = 0; + int nr_pages = nr_to_write; +retry: + blk_idx = try_alloc_block_bdev(zram, &nr_pages); if (!blk_idx) { ret = -ENOSPC; goto out; } + /* fallocate 2MB block if not allocated yet */ + fallocate_block(zram, blk_idx); + if (ppr) + atomic64_add(nr_pages, &zram->stats.bd_ppr_count); + + bio_vec = kmalloc_array(nr_pages, sizeof(struct bio_vec), GFP_KERNEL); + if (!bio_vec) { + ret = -ENOSPC; + goto out; + } - bio_init(&bio, &bio_vec, 1); + bio_init(&bio, bio_vec, nr_pages); bio_set_dev(&bio, zram->bdev); bio.bi_iter.bi_sector = blk_idx * (PAGE_SIZE >> 9); bio.bi_opf = REQ_OP_WRITE; - bio_add_page(&bio, page, PAGE_SIZE, 0); + for (i = 0; i < nr_pages; i++) + bio_add_page(&bio, zwbs[idx + i]->page, PAGE_SIZE, 0); if (sync) { ret = submit_bio_wait(&bio); } else { @@ -1060,99 +1360,112 @@ static int zram_writeback_page(struct zram *zram, struct page *page, wait_event(zram->wbd_wait, zram->io_complete); ret = blk_status_to_errno(bio.bi_status); } - if (ret) { - ret = -EIO; - free_block_bdev(zram, blk_idx); - pr_err("%s failed %lu", __func__, blk_idx); - goto out; - } - atomic64_inc(&zram->stats.bd_writes); -#ifdef CONFIG_ZRAM_LRU_WRITEBACK - count_vm_event(SQZR_WRITE); -#endif - spin_lock(&zram->wb_limit_lock); - if (zram->wb_limit_enable && zram->bd_wb_limit > 0) - zram->bd_wb_limit -= 1UL << (PAGE_SHIFT - 12); - spin_unlock(&zram->wb_limit_lock); + kfree(bio_vec); out: - if (ret) - zram_writeback_clear_flag(zram, entry, count); - else - zram_writeback_done(zram, blk_idx, entry, count); + if (!ret) { + for (i = 0; i < nr_pages; i++) + zram_writeback_done(zram, zwbs[idx + i], blk_idx + i, ppr); + + zram_update_max_stats(zram); + atomic64_add(nr_pages, &zram->stats.bd_writes); + count_vm_events(SQZR_WRITE, nr_pages); + if (ppr) + atomic64_add(nr_pages, &zram->stats.bd_ppr_writes); + spin_lock(&zram->wb_limit_lock); + if (zram->wb_limit_enable) { + if (zram->bd_wb_limit > nr_pages) + zram->bd_wb_limit -= nr_pages; + else + zram->bd_wb_limit = 0; + } + spin_unlock(&zram->wb_limit_lock); + + idx += nr_pages; + if (idx < nr_to_write) + goto retry; + } else { + if (blk_idx) + for (i = 0; i < nr_pages; i++) + free_block_bdev(zram, blk_idx + i, ppr); + /* free all remaining entries when error */ + for (i = idx; i < nr_to_write; i++) + zram_writeback_clear_flag(zram, zwbs[i]); + } return ret; } -#define ZRAM_WB_THRESHOLD 32 static int zram_comp_writeback_index(struct zram *zram, u32 index, - struct zram_wb_entry *entry, int *count, - struct page *page, int *offset, bool sync) + struct zwbs **zwbs, int *idx, bool sync, bool ppr) { int size, ret = 0; - int cnt = *count; - int off = *offset; + int i = *idx, j; retry: - size = zram_writeback_fill_page(zram, index, page, off); + size = zram_writeback_fill_page(zram, index, zwbs[i]); if (size > 0) { - entry[cnt].index = index; - entry[cnt].offset = off; - entry[cnt].size = size; - off += size; + struct zram_wb_entry *entry = zwbs[i]->entry; + entry[zwbs[i]->cnt].index = index; + entry[zwbs[i]->cnt].offset = zwbs[i]->off; + entry[zwbs[i]->cnt].size = size; + zwbs[i]->off += size; if (size < PAGE_SIZE) - off += sizeof(struct zram_wb_header); - cnt++; + zwbs[i]->off += sizeof(struct zram_wb_header); + zwbs[i]->cnt++; } /* writeback if page is full/entry is full */ - if (size == -ENOSPC || off == PAGE_SIZE || cnt == ZRAM_WB_THRESHOLD) { - mark_end_of_page(page, off); - ret = zram_writeback_page(zram, page, entry, cnt, sync); - cnt = off = 0; - if (ret) - goto out; - if (size == -ENOSPC) + if (size == -ENOSPC || zwbs[i]->cnt == ZRAM_WB_THRESHOLD) { + mark_end_of_page(zwbs[i]); + i = (i + 1) % NR_ZWBS; + if (i > 0) + goto retry; + ret = zram_writeback_page(zram, zwbs, NR_ZWBS, sync, ppr); + for (j = 0; j < NR_ZWBS; j++) { + zwbs[j]->cnt = 0; + zwbs[j]->off = 0; + } + if (ret == 0 && size == -ENOSPC) goto retry; } -out: - *count = cnt; - *offset = off; + *idx = i; return ret; } -static void zram_comp_writeback(struct zram *zram, struct page *page) +static void zram_comp_writeback(struct zram *zram) { - struct zram_wb_entry entry[ZRAM_WB_THRESHOLD]; + struct zwbs *zwbs[NR_ZWBS]; unsigned long nr_pages = zram->disksize >> PAGE_SHIFT; unsigned long index; - u32 offset = 0; - int count = 0; + int idx = 0; - set_page_private(page, (unsigned long)zram); + if (alloc_zwbs(zwbs)) { + pr_info("%s alloc_zwbs failed", __func__); + return; + } for (index = 0; index < nr_pages; index++) { if (!zram_wb_available(zram)) break; - if (zram_comp_writeback_index(zram, index, - entry, &count, page, &offset, true)) + if (zram_comp_writeback_index(zram, index, zwbs, &idx, true, false)) break; } + free_zwbs(zwbs); pr_info("%s done", __func__); } static int zram_wbd(void *p) { - struct zram_wb_entry entry[ZRAM_WB_THRESHOLD]; struct zram *zram = (struct zram *)p; struct zram_table_entry *zram_entry, *n; - struct page *page; - u32 index, offset = 0; - int count = 0; + struct zwbs *zwbs[NR_ZWBS]; + u32 index; + int idx = 0; int ret; set_freezable(); - page = alloc_page(GFP_KERNEL); - if (!page) + if (alloc_zwbs(zwbs)) { + pr_info("%s alloc_zwbs failed", __func__); return 0; - set_page_private(page, (unsigned long)zram); + } while (!kthread_should_stop()) { unsigned long nr_pages = 0; @@ -1165,23 +1478,124 @@ static int zram_wbd(void *p) break; index = entry_to_index(zram, zram_entry); ret = zram_try_mark_page(zram, index); - if (ret == SKIP) - continue; - else if (ret == ABORT) - break; - if (zram_comp_writeback_index(zram, index, - entry, &count, page, &offset, false)) - break; + if (!ret) { + if (zram_comp_writeback_index(zram, index, + zwbs, &idx, false, false)) + break; + } else if (ret == ABORT) { + n = list_first_entry(&zram->list, + struct zram_table_entry, lru_list); + } if (!zram_should_writeback(zram, ++nr_pages, false)) break; } zram->wbd_running = false; pr_info("%s done", __func__); } - __free_page(page); + free_zwbs(zwbs); return 0; } + +int is_writeback_entry(swp_entry_t entry) +{ + struct zram *zram; + struct swap_info_struct *sis = swap_info[swp_type(entry)]; + unsigned long index = swp_offset(entry); + int ret = 0; + + if (!(sis->flags & SWP_BLKDEV)) + return 0; + + zram = sis->bdev->bd_disk->private_data; + zram_slot_lock(zram, index); + if (zram_allocated(zram, index) && + zram_test_flag(zram, index, ZRAM_WB)) + ret = 1; + zram_slot_unlock(zram, index); + + return ret; +} + +void swap_add_to_list(struct list_head *list, swp_entry_t entry) +{ + struct zram *zram; + struct swap_info_struct *sis = swap_info[swp_type(entry)]; + unsigned long index = swp_offset(entry); + unsigned long flags; + + if (!(sis->flags & SWP_BLKDEV)) + return; + + zram = sis->bdev->bd_disk->private_data; + if (zram != g_zram) + return; + + if (!is_bdev_avail(zram)) + return; + + if (!zram_wb_available(zram)) + return; + + if (!zram_slot_trylock(zram, index)) + return; + + if (zram_allocated(zram, index) && + !zram_test_flag(zram, index, ZRAM_IDLE) && + !zram_test_flag(zram, index, ZRAM_WB) && + !zram_test_flag(zram, index, ZRAM_SAME) && + !zram_test_flag(zram, index, ZRAM_UNDER_WB) && + !zram_test_flag(zram, index, ZRAM_UNDER_PPR)) { + zram_set_flag(zram, index, ZRAM_IDLE); + zram_set_flag(zram, index, ZRAM_UNDER_PPR); + spin_lock_irqsave(&zram->list_lock, flags); + if (!list_empty(&zram->table[index].lru_list)) + list_move(&zram->table[index].lru_list, list); + spin_unlock_irqrestore(&zram->list_lock, flags); + } + zram_slot_unlock(zram, index); +} + +void swap_writeback_list(struct zwbs **zwbs, struct list_head *list) +{ + struct zram *zram = g_zram; + struct zram_table_entry *zram_entry; + u32 index; + static int idx = 0; + unsigned long flags; + bool skip = false; + + if (list == NULL) { + if (idx > 0 || zwbs[idx]->cnt > 0) { + mark_end_of_page(zwbs[idx]); + if (zwbs[idx]->cnt > 0) + idx++; + zram_writeback_page(zram, zwbs, idx, true, true); + } + idx = 0; + return; + } + + while (!list_empty(list)) { + zram_entry = list_first_entry(list, + typeof(struct zram_table_entry), lru_list); + index = entry_to_index(zram, zram_entry); + if (!skip) { + if (!zram_wb_available(zram)) + skip = true; + else if (zram_comp_writeback_index(zram, index, + zwbs, &idx, true, true)) + skip = true; + } + zram_slot_lock(zram, index); + zram_clear_flag(zram, index, ZRAM_UNDER_PPR); + spin_lock_irqsave(&zram->list_lock, flags); + if (!list_empty(&zram->table[index].lru_list)) + list_del_init(&zram->table[index].lru_list); + spin_unlock_irqrestore(&zram->list_lock, flags); + zram_slot_unlock(zram, index); + } +} #endif #define HUGE_WRITEBACK 1 @@ -1237,7 +1651,7 @@ static ssize_t writeback_store(struct device *dev, #ifdef CONFIG_ZRAM_LRU_WRITEBACK if (mode == IDLE_WRITEBACK) { if (is_bdev_avail(zram)) - zram_comp_writeback(zram, page); + zram_comp_writeback(zram); ret = len; __free_page(page); goto release_init_lock; @@ -1357,7 +1771,7 @@ next: } if (blk_idx) - free_block_bdev(zram, blk_idx); + free_block_bdev(zram, blk_idx, false); ret = len; __free_page(page); release_init_lock: @@ -1467,6 +1881,7 @@ static void zram_handle_remain(struct zram *zram, struct page *page, zram_slot_unlock(zram, index); goto next; } + atomic64_inc(&zram->stats.bd_objreads); handle = zs_malloc(zram->mem_pool, size, __GFP_KSWAPD_RECLAIM | @@ -1495,7 +1910,7 @@ next: offset += (size + sizeof(struct zram_wb_header)); } kunmap_atomic(mem); - free_block_bdev(zram, blk_idx); + free_block_bdev(zram, blk_idx, false); atomic64_inc(&zram->stats.bd_objcnt); count_vm_event(SQZR_OBJCNT); } @@ -1543,7 +1958,8 @@ static void zram_handle_comp_page(struct work_struct *work) /* increment refcount to prevent freeing block */ spin_lock_irqsave(&zram->wb_table_lock, flags); - zram->wb_table[blk_idx]++; + if (zram->wb_table) + zram->wb_table[blk_idx]++; spin_unlock_irqrestore(&zram->wb_table_lock, flags); page_endio(dst_page, op_is_write(bio_op(bio)), @@ -1573,9 +1989,7 @@ static int read_comp_from_bdev(struct zram *zram, struct bio_vec *bvec, unsigned long blk_idx = handle >> (PAGE_SHIFT * 2); atomic64_inc(&zram->stats.bd_reads); -#ifdef CONFIG_ZRAM_LRU_WRITEBACK count_vm_event(SQZR_READ); -#endif bio = bio_alloc(GFP_ATOMIC, 1); if (!bio) @@ -1920,12 +2334,25 @@ static ssize_t bd_stat_show(struct device *dev, down_read(&zram->init_lock); #ifdef CONFIG_ZRAM_LRU_WRITEBACK ret = scnprintf(buf, PAGE_SIZE, - "%8llu %8llu %8llu %8llu %8llu\n", + "%8llu %8llu %8llu %8llu %8llu %8llu %8llu %8llu %8llu " + "%8llu %8llu %8llu %8llu %8llu %8llu %8llu %8llu\n", FOUR_K((u64)atomic64_read(&zram->stats.bd_expire)), FOUR_K((u64)atomic64_read(&zram->stats.bd_count)), FOUR_K((u64)atomic64_read(&zram->stats.bd_reads)), FOUR_K((u64)atomic64_read(&zram->stats.bd_writes)), - FOUR_K((u64)atomic64_read(&zram->stats.bd_objcnt))); + FOUR_K((u64)atomic64_read(&zram->stats.bd_objcnt)), + (u64)(atomic64_read(&zram->stats.bd_size) >> PAGE_SHIFT), + FOUR_K((u64)atomic64_read(&zram->stats.bd_max_count)), + (u64)(atomic64_read(&zram->stats.bd_max_size) >> PAGE_SHIFT), + FOUR_K((u64)atomic64_read(&zram->stats.bd_ppr_count)), + FOUR_K((u64)atomic64_read(&zram->stats.bd_ppr_reads)), + FOUR_K((u64)atomic64_read(&zram->stats.bd_ppr_writes)), + FOUR_K((u64)atomic64_read(&zram->stats.bd_ppr_objcnt)), + (u64)(atomic64_read(&zram->stats.bd_ppr_size) >> PAGE_SHIFT), + FOUR_K((u64)atomic64_read(&zram->stats.bd_ppr_max_count)), + (u64)(atomic64_read(&zram->stats.bd_ppr_max_size) >> PAGE_SHIFT), + FOUR_K((u64)atomic64_read(&zram->stats.bd_objreads)), + FOUR_K((u64)atomic64_read(&zram->stats.bd_objwrites))); #else ret = scnprintf(buf, PAGE_SIZE, "%8llu %8llu %8llu\n", @@ -1937,6 +2364,16 @@ static ssize_t bd_stat_show(struct device *dev, return ret; } + +#ifdef CONFIG_ZRAM_LRU_WRITEBACK +static ssize_t bd_stat_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t len) +{ + struct zram *zram = dev_to_zram(dev); + zram_reset_stats(zram); + return len; +} +#endif #endif static ssize_t debug_stat_show(struct device *dev, @@ -1960,7 +2397,7 @@ static ssize_t debug_stat_show(struct device *dev, static DEVICE_ATTR_RO(io_stat); static DEVICE_ATTR_RO(mm_stat); #ifdef CONFIG_ZRAM_WRITEBACK -static DEVICE_ATTR_RO(bd_stat); +static DEVICE_ATTR_RW(bd_stat); #endif static DEVICE_ATTR_RO(debug_stat); @@ -2087,13 +2524,28 @@ static void zram_free_page(struct zram *zram, size_t index) if (zram_test_flag(zram, index, ZRAM_WB)) { #ifdef CONFIG_ZRAM_LRU_WRITEBACK + unsigned long handle; + int size; + bool ppr = zram_test_flag(zram, index, ZRAM_PPR); + handle = zram_get_element(zram, index); + size = handle & (PAGE_SIZE - 1); + if (size == 0) + size = PAGE_SIZE; + atomic64_sub(size, &zram->stats.bd_size); + if (ppr) { + zram_clear_flag(zram, index, ZRAM_PPR); + atomic64_sub(size, &zram->stats.bd_ppr_size); + } if (zram_test_flag(zram, index, ZRAM_EXPIRE)) { zram_clear_flag(zram, index, ZRAM_EXPIRE); atomic64_dec(&zram->stats.bd_expire); } -#endif zram_clear_flag(zram, index, ZRAM_WB); - free_block_bdev(zram, zram_get_element(zram, index) >> (PAGE_SHIFT * 2)); + free_block_bdev(zram, handle >> (PAGE_SHIFT * 2), ppr); +#else + zram_clear_flag(zram, index, ZRAM_WB); + free_block_bdev(zram, zram_get_element(zram, index) >> (PAGE_SHIFT * 2)); +#endif goto out; } @@ -2119,14 +2571,16 @@ out: atomic64_dec(&zram->stats.pages_stored); zram_set_entry(zram, index, NULL); zram_set_obj_size(zram, index, 0); - WARN_ON_ONCE(zram->table[index].flags & - ~(1UL << ZRAM_LOCK | 1UL << ZRAM_UNDER_WB)); #ifdef CONFIG_ZRAM_LRU_WRITEBACK + if (zram_test_flag(zram, index, ZRAM_UNDER_PPR)) + zram_clear_flag(zram, index, ZRAM_UNDER_PPR); spin_lock_irqsave(&zram->list_lock, flags); if (!list_empty(&zram->table[index].lru_list)) list_del_init(&zram->table[index].lru_list); spin_unlock_irqrestore(&zram->list_lock, flags); #endif + WARN_ON_ONCE(zram->table[index].flags & + ~(1UL << ZRAM_LOCK | 1UL << ZRAM_UNDER_WB)); } static int __zram_bvec_read(struct zram *zram, struct page *page, u32 index, @@ -2148,8 +2602,13 @@ static int __zram_bvec_read(struct zram *zram, struct page *page, u32 index, bvec.bv_len = PAGE_SIZE; bvec.bv_offset = 0; #ifdef CONFIG_ZRAM_LRU_WRITEBACK - zram_set_flag(zram, index, ZRAM_EXPIRE); - atomic64_inc(&zram->stats.bd_expire); + atomic64_inc(&zram->stats.bd_objreads); + if (zram_test_flag(zram, index, ZRAM_PPR)) + atomic64_inc(&zram->stats.bd_ppr_reads); + if (!zram_test_flag(zram, index, ZRAM_EXPIRE)) { + zram_set_flag(zram, index, ZRAM_EXPIRE); + atomic64_inc(&zram->stats.bd_expire); + } if ((zram_get_element(zram, index) & (PAGE_SIZE - 1)) != 0) { zram_set_flag(zram, index, ZRAM_READ_BDEV); zram_slot_unlock(zram, index); @@ -2202,6 +2661,8 @@ static int __zram_bvec_read(struct zram *zram, struct page *page, u32 index, zs_unmap_object(zram->mem_pool, zram_entry_handle(zram, entry)); #ifdef CONFIG_ZRAM_LRU_WRITEBACK + if (zram_test_flag(zram, index, ZRAM_UNDER_PPR)) + zram_clear_flag(zram, index, ZRAM_UNDER_PPR); spin_lock_irqsave(&zram->list_lock, flags); if (!list_empty(&zram->table[index].lru_list)) list_del_init(&zram->table[index].lru_list); @@ -2869,6 +3330,8 @@ static int zram_add(void) INIT_LIST_HEAD(&zram->list); spin_lock_init(&zram->list_lock); spin_lock_init(&zram->wb_table_lock); + spin_lock_init(&zram->bitmap_lock); + mutex_init(&zram->blk_bitmap_lock); #endif queue = blk_alloc_queue(GFP_KERNEL); if (!queue) { @@ -3121,10 +3584,10 @@ static int __init zram_init(void) num_devices--; } + show_mem_extra_notifier_register(&zram_size_nb); #ifdef CONFIG_ZRAM_LRU_WRITEBACK am_app_launch_notifier_register(&zram_app_launch_nb); #endif - show_mem_extra_notifier_register(&zram_size_nb); return 0; out_error: diff --git a/drivers/block/zram/zram_drv.h b/drivers/block/zram/zram_drv.h index b20427564cd0..b45d38dcf7d5 100755 --- a/drivers/block/zram/zram_drv.h +++ b/drivers/block/zram/zram_drv.h @@ -18,6 +18,7 @@ #include #include #include +#include #include #include "zcomp.h" @@ -55,6 +56,8 @@ enum zram_pageflags { ZRAM_IDLE, /* not accessed page since last idle marking */ ZRAM_EXPIRE, ZRAM_READ_BDEV, + ZRAM_PPR, + ZRAM_UNDER_PPR, __NR_ZRAM_PAGEFLAGS, }; @@ -111,10 +114,26 @@ struct zram_stats { #ifdef CONFIG_ZRAM_LRU_WRITEBACK atomic64_t bd_expire; atomic64_t bd_objcnt; + atomic64_t bd_size; + atomic64_t bd_max_count; + atomic64_t bd_max_size; + atomic64_t bd_ppr_count; + atomic64_t bd_ppr_reads; + atomic64_t bd_ppr_writes; + atomic64_t bd_ppr_objcnt; + atomic64_t bd_ppr_size; + atomic64_t bd_ppr_max_count; + atomic64_t bd_ppr_max_size; + atomic64_t bd_objreads; + atomic64_t bd_objwrites; #endif }; #ifdef CONFIG_ZRAM_LRU_WRITEBACK +#define ZRAM_WB_THRESHOLD 32 +#define NR_ZWBS 16 +#define NR_FALLOC_PAGES 512 +#define FALLOC_ALIGN_MASK (~(NR_FALLOC_PAGES - 1)) struct zram_wb_header { u32 index; u32 size; @@ -134,6 +153,20 @@ struct zram_wb_entry { unsigned int offset; unsigned int size; }; + +struct zwbs { + struct zram_wb_entry entry[ZRAM_WB_THRESHOLD]; + struct page *page; + u32 cnt; + u32 off; +}; + +void free_zwbs(struct zwbs **); +int alloc_zwbs(struct zwbs **); +bool zram_is_app_launch(void); +int is_writeback_entry(swp_entry_t); +void swap_add_to_list(struct list_head *, swp_entry_t); +void swap_writeback_list(struct zwbs **, struct list_head *); #endif struct zram_hash { @@ -184,11 +217,15 @@ struct zram { struct task_struct *wbd; wait_queue_head_t wbd_wait; u8 *wb_table; + unsigned long *chunk_bitmap; bool wbd_running; bool io_complete; struct list_head list; spinlock_t list_lock; spinlock_t wb_table_lock; + spinlock_t bitmap_lock; + unsigned long *blk_bitmap; + struct mutex blk_bitmap_lock; #endif }; diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c index 841476d7343d..4eb76019bd87 100755 --- a/drivers/char/adsprpc.c +++ b/drivers/char/adsprpc.c @@ -3427,11 +3427,14 @@ static int fastrpc_set_process_info(struct fastrpc_file *fl) { int err = 0, buf_size = 0; char strpid[PID_SIZE]; + char cur_comm[TASK_COMM_LEN]; + memcpy(cur_comm, current->comm, TASK_COMM_LEN); + cur_comm[TASK_COMM_LEN-1] = '\0'; fl->tgid = current->tgid; snprintf(strpid, PID_SIZE, "%d", current->pid); if (debugfs_root) { - buf_size = strlen(current->comm) + strlen("_") + buf_size = strlen(cur_comm) + strlen("_") + strlen(strpid) + 1; spin_lock(&fl->hlock); @@ -3447,13 +3450,13 @@ static int fastrpc_set_process_info(struct fastrpc_file *fl) err = -ENOMEM; return err; } - snprintf(fl->debug_buf, UL_SIZE, "%.10s%s%d", - current->comm, "_", current->pid); + snprintf(fl->debug_buf, buf_size, "%.10s%s%d", + cur_comm, "_", current->pid); fl->debugfs_file = debugfs_create_file(fl->debug_buf, 0644, debugfs_root, fl, &debugfs_fops); if (IS_ERR_OR_NULL(fl->debugfs_file)) { pr_warn("Error: %s: %s: failed to create debugfs file %s\n", - current->comm, __func__, fl->debug_buf); + cur_comm, __func__, fl->debug_buf); fl->debugfs_file = NULL; kfree(fl->debug_buf); fl->debug_buf = NULL; diff --git a/drivers/char/diag/diag_dci.c b/drivers/char/diag/diag_dci.c index 25a1706b6508..6150a293573d 100755 --- a/drivers/char/diag/diag_dci.c +++ b/drivers/char/diag/diag_dci.c @@ -1061,6 +1061,11 @@ void extract_dci_pkt_rsp(unsigned char *buf, int len, int data_source, return; } + if (token != entry->client_info.token) { + mutex_unlock(&driver->dci_mutex); + return; + } + mutex_lock(&entry->buffers[data_source].buf_mutex); rsp_buf = entry->buffers[data_source].buf_cmd; @@ -1732,7 +1737,16 @@ static int diag_send_dci_pkt_remote(unsigned char *data, int len, int tag, write_len += dci_header_size; *(int *)(buf + write_len) = tag; write_len += sizeof(int); - memcpy(buf + write_len, data, len); + if ((write_len + len) < DIAG_MDM_BUF_SIZE) { + memcpy(buf + write_len, data, len); + } else { + pr_err("diag: skip writing invalid length packet, token: %d, pkt_len: %d\n", + token, (write_len + len)); + spin_lock_irqsave(&driver->dci_mempool_lock, flags); + diagmem_free(driver, buf, dci_ops_tbl[token].mempool); + spin_unlock_irqrestore(&driver->dci_mempool_lock, flags); + return -EAGAIN; + } write_len += len; *(buf + write_len) = CONTROL_CHAR; /* End Terminator */ write_len += sizeof(uint8_t); diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c index 9b6c95eb9859..3ec8788908d4 100755 --- a/drivers/char/diag/diagchar_core.c +++ b/drivers/char/diag/diagchar_core.c @@ -1996,13 +1996,15 @@ static int diag_switch_logging(struct diag_logging_mode_param_t *param) driver->pcie_switch_pid = current->tgid; } if (new_mode == DIAG_PCIE_MODE) { - driver->transport_set = DIAG_ROUTE_TO_PCIE; + driver->transport_set = + DIAG_ROUTE_TO_PCIE; diagmem_setsize(POOL_TYPE_MUX_APPS, itemsize_pcie_apps, (poolsize_pcie_apps + 1 + (NUM_PERIPHERALS * 6))); } else if (new_mode == DIAG_USB_MODE) { - driver->transport_set = DIAG_ROUTE_TO_USB; + driver->transport_set = + DIAG_ROUTE_TO_USB; diagmem_setsize(POOL_TYPE_MUX_APPS, itemsize_usb_apps, (poolsize_usb_apps + 1 + @@ -4400,7 +4402,7 @@ static void diag_init_transport(void) * The number of buffers encompasses Diag data generated on * the Apss processor + 1 for the responses generated * exclusively on the Apps processor + data from data channels - *(4 channels periperipheral) + data from command channels (2) + *(4 channels per peripheral) + data from command channels (2) */ diagmem_setsize(POOL_TYPE_MUX_APPS, itemsize_pcie_apps, poolsize_pcie_apps + 1 + (NUM_PERIPHERALS * 6)); @@ -4419,7 +4421,7 @@ static void diag_init_transport(void) * The number of buffers encompasses Diag data generated on * the Apss processor + 1 for the responses generated * exclusively on the Apps processor + data from data channels - *(4 channels periperipheral) + data from command channels (2) + *(4 channels per peripheral) + data from command channels (2) */ diagmem_setsize(POOL_TYPE_MUX_APPS, itemsize_usb_apps, poolsize_usb_apps + 1 + (NUM_PERIPHERALS * 6)); diff --git a/drivers/char/diag/diagmem.c b/drivers/char/diag/diagmem.c index f526eddcb6e5..666d69ea1764 100755 --- a/drivers/char/diag/diagmem.c +++ b/drivers/char/diag/diagmem.c @@ -152,6 +152,9 @@ void diagmem_setsize(int pool_idx, int itemsize, int poolsize) } diag_mempools[pool_idx].itemsize = itemsize; + if (diag_mempools[pool_idx].pool) + diag_mempools[pool_idx].pool->pool_data = + (void *)(uintptr_t)itemsize; diag_mempools[pool_idx].poolsize = poolsize; pr_debug("diag: Mempool %s sizes: itemsize %d poolsize %d\n", diag_mempools[pool_idx].name, diag_mempools[pool_idx].itemsize, @@ -177,7 +180,8 @@ void *diagmem_alloc(struct diagchar_dev *driver, int size, int pool_type) mempool->name); break; } - if (size == 0 || size > mempool->itemsize) { + if (size == 0 || size > mempool->itemsize || + size > (int)mempool->pool->pool_data) { pr_err_ratelimited("diag: cannot alloc from mempool %s, invalid size: %d\n", mempool->name, size); break; diff --git a/drivers/gpu/drm/msm/samsung_lego/S6E3FC3_AMS646YD04/ss_dsi_panel_S6E3FC3_AMS646YD04.c b/drivers/gpu/drm/msm/samsung_lego/S6E3FC3_AMS646YD04/ss_dsi_panel_S6E3FC3_AMS646YD04.c index a6866a691e3f..a22083f7823c 100755 --- a/drivers/gpu/drm/msm/samsung_lego/S6E3FC3_AMS646YD04/ss_dsi_panel_S6E3FC3_AMS646YD04.c +++ b/drivers/gpu/drm/msm/samsung_lego/S6E3FC3_AMS646YD04/ss_dsi_panel_S6E3FC3_AMS646YD04.c @@ -239,6 +239,7 @@ static struct dsi_panel_cmd_set *ss_vrr_hbm(struct samsung_display_driver_data * #define HBM_NORMAL_DELAY_60FPS (9) #define HBM_NORMAL_DELAY_90FPS (12) #define HBM_NORMAL_DELAY_120FPS (3) +static bool last_br_hbm; #define get_bit(value, shift, width) ((value >> shift) & (GENMASK(width - 1, 0))) static struct dsi_panel_cmd_set *ss_brightness_gamma_mode2_normal @@ -330,6 +331,7 @@ static struct dsi_panel_cmd_set *ss_brightness_gamma_mode2_normal } *level_key = LEVEL_KEY_NONE; + last_br_hbm = false; return pcmds; } @@ -363,13 +365,15 @@ static struct dsi_panel_cmd_set *ss_brightness_gamma_mode2_hbm vdd->br_info.temperature : (char)(BIT(7) | (-1 * vdd->br_info.temperature)); if (vdd->finger_mask_updated) { - /* Smooth Dimming Off First */ - if (vdd->vrr.cur_refresh_rate > 60) - pcmds_smooth_off->cmds[3].post_wait_ms = FRAME_WAIT_90FPS; - else - pcmds_smooth_off->cmds[3].post_wait_ms = FRAME_WAIT_60FPS; + if (last_br_hbm == false) { /* Normal -> HBM Case Only */ + /* Smooth Dimming Off First */ + if (vdd->vrr.cur_refresh_rate > 60) + pcmds_smooth_off->cmds[3].post_wait_ms = FRAME_WAIT_90FPS; + else + pcmds_smooth_off->cmds[3].post_wait_ms = FRAME_WAIT_60FPS; - ss_send_cmd(vdd, TX_SMOOTH_DIMMING_OFF); + ss_send_cmd(vdd, TX_SMOOTH_DIMMING_OFF); + } /* There is panel limitation for HBM & AOR setting. @@ -414,6 +418,7 @@ static struct dsi_panel_cmd_set *ss_brightness_gamma_mode2_hbm } *level_key = LEVEL_KEY_NONE; + last_br_hbm = true; return pcmds; } diff --git a/drivers/gpu/drm/msm/samsung_lego/S6E3FC3_AMS667YM01/ss_dsi_panel_S6E3FC3_AMS667YM01.c b/drivers/gpu/drm/msm/samsung_lego/S6E3FC3_AMS667YM01/ss_dsi_panel_S6E3FC3_AMS667YM01.c index c45d511265e3..4ef312e47356 100755 --- a/drivers/gpu/drm/msm/samsung_lego/S6E3FC3_AMS667YM01/ss_dsi_panel_S6E3FC3_AMS667YM01.c +++ b/drivers/gpu/drm/msm/samsung_lego/S6E3FC3_AMS667YM01/ss_dsi_panel_S6E3FC3_AMS667YM01.c @@ -233,6 +233,7 @@ static struct dsi_panel_cmd_set *ss_vrr_hbm(struct samsung_display_driver_data * #define FRAME_WAIT_90FPS (12) #define HBM_NORMAL_DELAY_60FPS (12) #define HBM_NORMAL_DELAY_90FPS (12) +static bool last_br_hbm; #define get_bit(value, shift, width) ((value >> shift) & (GENMASK(width - 1, 0))) static struct dsi_panel_cmd_set *ss_brightness_gamma_mode2_normal @@ -325,6 +326,7 @@ static struct dsi_panel_cmd_set *ss_brightness_gamma_mode2_normal } *level_key = LEVEL_KEY_NONE; + last_br_hbm = false; return pcmds; } @@ -358,13 +360,15 @@ static struct dsi_panel_cmd_set *ss_brightness_gamma_mode2_hbm vdd->br_info.temperature : (char)(BIT(7) | (-1 * vdd->br_info.temperature)); if (vdd->finger_mask_updated) { - /* Smooth Dimming Off First */ - if (vdd->vrr.cur_refresh_rate > 60) - pcmds_smooth_off->cmds[3].post_wait_ms = FRAME_WAIT_90FPS; - else - pcmds_smooth_off->cmds[3].post_wait_ms = FRAME_WAIT_60FPS; + if (last_br_hbm == false) { /* Normal -> HBM Case Only */ + /* Smooth Dimming Off First */ + if (vdd->vrr.cur_refresh_rate > 60) + pcmds_smooth_off->cmds[3].post_wait_ms = FRAME_WAIT_90FPS; + else + pcmds_smooth_off->cmds[3].post_wait_ms = FRAME_WAIT_60FPS; - ss_send_cmd(vdd, TX_SMOOTH_DIMMING_OFF); + ss_send_cmd(vdd, TX_SMOOTH_DIMMING_OFF); + } /* There is panel limitation for HBM & AOR setting. @@ -409,6 +413,7 @@ static struct dsi_panel_cmd_set *ss_brightness_gamma_mode2_hbm } *level_key = LEVEL_KEY_NONE; + last_br_hbm = true; return pcmds; } diff --git a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.c b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.c index a68e20745b1a..552476c292a2 100755 --- a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.c +++ b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.c @@ -526,7 +526,6 @@ static int cam_cpas_hw_reg_read(struct cam_hw_info *cpas_hw, if (!CAM_CPAS_CLIENT_VALID(client_indx)) return -EINVAL; - mutex_lock(&cpas_core->client_mutex[client_indx]); cpas_client = cpas_core->cpas_client[client_indx]; if (!CAM_CPAS_CLIENT_STARTED(cpas_core, client_indx)) { @@ -534,7 +533,7 @@ static int cam_cpas_hw_reg_read(struct cam_hw_info *cpas_hw, client_indx, cpas_client->data.identifier, cpas_client->data.cell_index); rc = -EPERM; - goto unlock_client; + return rc; } if (mb) @@ -546,8 +545,6 @@ static int cam_cpas_hw_reg_read(struct cam_hw_info *cpas_hw, *value = reg_value; -unlock_client: - mutex_unlock(&cpas_core->client_mutex[client_indx]); return rc; } diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c index e3b5bb3d8902..93081302aea6 100755 --- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c +++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c @@ -1461,7 +1461,8 @@ static int cam_icp_hw_mgr_create_debugfs_entry(void) rc = -ENOMEM; goto err; } - + /* Set default hang dump lvl */ + icp_hw_mgr.a5_fw_dump_lvl = HFI_FW_DUMP_ON_FAILURE; return rc; err: debugfs_remove_recursive(icp_hw_mgr.dentry); diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index 21ad9b730b89..bb3b78d651e0 100755 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -5084,8 +5084,7 @@ static int cam_ife_hw_mgr_get_err_type( core_idx = evt_payload->core_index; evt_payload->evt_id = CAM_ISP_HW_EVENT_ERROR; - evt_payload->enable_reg_dump = - g_ife_hw_mgr.debug_cfg.enable_reg_dump; + evt_payload->enable_reg_dump = true; list_for_each_entry(isp_ife_camif_res, &ife_hwr_mgr_ctx->res_list_ife_src, list) { diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c index 52de7b10cbe6..7c4303aab686 100755 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c @@ -1393,7 +1393,7 @@ static int cam_vfe_bus_err_bottom_half(void *ctx_priv, evt_payload = evt_payload_priv; common_data = evt_payload->ctx; - enable_dmi_dump = evt_payload->enable_dump; + enable_dmi_dump = 0x3; stats_cfg = common_data->stats_data->stats_cfg_offset; dmi_cfg = common_data->stats_data->dmi_offset_info; val = evt_payload->debug_status_0; diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_core.c index c16890a1a146..e032a11e8795 100755 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_core.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_core.c @@ -54,6 +54,11 @@ static int cam_flash_prepare(struct cam_flash_ctrl *flash_ctrl, (struct cam_flash_private_soc *) flash_ctrl->soc_info.soc_private; + // Set the PMIC voltage to 5V for Flash operation +#if defined(CONFIG_LEDS_SM5714) + sm5714_fled_mode_ctrl(SM5714_FLED_MODE_PREPARE_FLASH, 0); +#endif + #if !defined(CONFIG_LEDS_S2MU107_FLASH) && !defined(CONFIG_LEDS_S2MU106_FLASH) && !defined(CONFIG_LEDS_SM5714) if (!(flash_ctrl->switch_trigger)) { CAM_ERR(CAM_FLASH, "Invalid argument"); @@ -1947,6 +1952,11 @@ int cam_flash_release_dev(struct cam_flash_ctrl *fctrl) { int rc = 0; + // Re-Set the PMIC voltage 5V -> 9V +#if defined(CONFIG_LEDS_SM5714) + sm5714_fled_mode_ctrl(SM5714_FLED_MODE_CLOSE_FLASH, 0); +#endif + if (fctrl->bridge_intf.device_hdl != 1) { rc = cam_destroy_device_hdl(fctrl->bridge_intf.device_hdl); if (rc) diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c index 8470e805f719..6f45760c0d80 100755 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c @@ -19,10 +19,6 @@ #include "cam_common_util.h" #include "cam_packet_util.h" -#if defined(CONFIG_LEDS_SM5714) -#include -#endif - #if defined(CONFIG_GC5035_MACRO_OTP_DD_AUTOLOAD) #include "gc5035_macro_otp.h" #endif @@ -1561,14 +1557,6 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, goto release_mutex; } - // Set the PMIC voltage to 5V for Flash operation on Rear Sensor -#if defined(CONFIG_LEDS_SM5714) - if(s_ctrl->soc_info.index == 0 || s_ctrl->soc_info.index == 4) - { - sm5714_fled_mode_ctrl(SM5714_FLED_MODE_PREPARE_FLASH, 0); - } -#endif - rc = cam_sensor_power_up(s_ctrl); if (rc < 0) { CAM_ERR(CAM_SENSOR, "Sensor Power up failed"); @@ -1602,14 +1590,6 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, goto release_mutex; } - // Re-Set the PMIC voltage 5V -> 9V -#if defined(CONFIG_LEDS_SM5714) - if(s_ctrl->soc_info.index == 0 || s_ctrl->soc_info.index == 4) - { - sm5714_fled_mode_ctrl(SM5714_FLED_MODE_CLOSE_FLASH, 0); - } -#endif - rc = cam_sensor_power_down(s_ctrl); if (rc < 0) { CAM_ERR(CAM_SENSOR, "Sensor Power Down failed"); diff --git a/drivers/media/platform/msm/camera/cam_smmu/cam_smmu_api.c b/drivers/media/platform/msm/camera/cam_smmu/cam_smmu_api.c index a3a906e2f038..b8d3c779deb6 100755 --- a/drivers/media/platform/msm/camera/cam_smmu/cam_smmu_api.c +++ b/drivers/media/platform/msm/camera/cam_smmu/cam_smmu_api.c @@ -3197,6 +3197,7 @@ static int cam_smmu_setup_cb(struct cam_context_bank_info *cb, struct device *dev) { int rc = 0; + int32_t stall_disable = 1; if (!cb || !dev) { CAM_ERR(CAM_SMMU, "Error: invalid input params"); @@ -3263,6 +3264,12 @@ static int cam_smmu_setup_cb(struct cam_context_bank_info *cb, CAM_ERR(CAM_SMMU, "Error: failed to set non fatal fault attribute"); } + if (iommu_domain_set_attr(cb->mapping->domain, + DOMAIN_ATTR_CB_STALL_DISABLE, + &stall_disable) < 0) { + CAM_ERR(CAM_SMMU, + "Error: failed to set cb stall disable"); + } } else { CAM_ERR(CAM_SMMU, "Context bank does not have IO region"); diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c index b4ce603616cc..ef086f03abb2 100755 --- a/drivers/misc/qseecom.c +++ b/drivers/misc/qseecom.c @@ -3048,6 +3048,11 @@ static int qseecom_unload_app(struct qseecom_dev_handle *data, goto unload_exit; } + if (!memcmp(data->client.app_name, "tz_hdm", strlen("tz_hdm"))) { + pr_debug("Do not unload tz_hdm app from tz\n"); + goto unload_exit; + } + __qseecom_cleanup_app(data); __qseecom_reentrancy_check_if_no_app_blocked(TZ_OS_APP_SHUTDOWN_ID); @@ -3823,54 +3828,60 @@ static int qseecom_send_cmd(struct qseecom_dev_handle *data, void __user *argp) int __boundary_checks_offset(struct qseecom_send_modfd_cmd_req *req, struct qseecom_send_modfd_listener_resp *lstnr_resp, - struct qseecom_dev_handle *data, int i) + struct qseecom_dev_handle *data, int i, size_t size) { + char *curr_field = NULL; + char *temp_field = NULL; + int j = 0; if ((data->type != QSEECOM_LISTENER_SERVICE) && (req->ifd_data[i].fd > 0)) { - if ((req->cmd_req_len < sizeof(uint32_t)) || + if ((req->cmd_req_len < size) || (req->ifd_data[i].cmd_buf_offset > - req->cmd_req_len - sizeof(uint32_t))) { + req->cmd_req_len - size)) { pr_err("Invalid offset (req len) 0x%x\n", req->ifd_data[i].cmd_buf_offset); return -EINVAL; } - } else if ((data->type == QSEECOM_LISTENER_SERVICE) && - (lstnr_resp->ifd_data[i].fd > 0)) { - if ((lstnr_resp->resp_len < sizeof(uint32_t)) || - (lstnr_resp->ifd_data[i].cmd_buf_offset > - lstnr_resp->resp_len - sizeof(uint32_t))) { - pr_err("Invalid offset (lstnr resp len) 0x%x\n", - lstnr_resp->ifd_data[i].cmd_buf_offset); - return -EINVAL; - } - } - return 0; -} -static int __boundary_checks_offset_64(struct qseecom_send_modfd_cmd_req *req, - struct qseecom_send_modfd_listener_resp *lstnr_resp, - struct qseecom_dev_handle *data, int i) -{ - - if ((data->type != QSEECOM_LISTENER_SERVICE) && - (req->ifd_data[i].fd > 0)) { - if ((req->cmd_req_len < sizeof(uint64_t)) || - (req->ifd_data[i].cmd_buf_offset > - req->cmd_req_len - sizeof(uint64_t))) { - pr_err("Invalid offset (req len) 0x%x\n", + curr_field = (char *) (req->cmd_req_buf + req->ifd_data[i].cmd_buf_offset); - return -EINVAL; + for (j = 0; j < MAX_ION_FD; j++) { + if ((req->ifd_data[j].fd > 0) && i != j) { + temp_field = (char *) (req->cmd_req_buf + + req->ifd_data[j].cmd_buf_offset); + if (temp_field >= curr_field && temp_field < + (curr_field + size)) { + pr_err("Invalid field offset 0x%x\n", + req->ifd_data[i].cmd_buf_offset); + return -EINVAL; + } + } } } else if ((data->type == QSEECOM_LISTENER_SERVICE) && (lstnr_resp->ifd_data[i].fd > 0)) { - if ((lstnr_resp->resp_len < sizeof(uint64_t)) || + if ((lstnr_resp->resp_len < size) || (lstnr_resp->ifd_data[i].cmd_buf_offset > - lstnr_resp->resp_len - sizeof(uint64_t))) { + lstnr_resp->resp_len - size)) { pr_err("Invalid offset (lstnr resp len) 0x%x\n", lstnr_resp->ifd_data[i].cmd_buf_offset); return -EINVAL; } + + curr_field = (char *) (lstnr_resp->resp_buf_ptr + + lstnr_resp->ifd_data[i].cmd_buf_offset); + for (j = 0; j < MAX_ION_FD; j++) { + if ((lstnr_resp->ifd_data[j].fd > 0) && i != j) { + temp_field = (char *) lstnr_resp->resp_buf_ptr + + lstnr_resp->ifd_data[j].cmd_buf_offset; + if (temp_field >= curr_field && temp_field < + (curr_field + size)) { + pr_err("Invalid lstnr field offset 0x%x\n", + lstnr_resp->ifd_data[i].cmd_buf_offset); + return -EINVAL; + } + } + } } return 0; } @@ -3945,8 +3956,10 @@ static int __qseecom_update_cmd_buf(void *msg, bool cleanup, if (sg_ptr->nents == 1) { uint32_t *update; - if (__boundary_checks_offset(req, lstnr_resp, data, i)) + if (__boundary_checks_offset(req, lstnr_resp, data, i, + sizeof(uint32_t))) goto err; + if ((data->type == QSEECOM_CLIENT_APP && (data->client.app_arch == ELFCLASS32 || data->client.app_arch == ELFCLASS64)) || @@ -3977,30 +3990,10 @@ static int __qseecom_update_cmd_buf(void *msg, bool cleanup, struct qseecom_sg_entry *update; int j = 0; - if ((data->type != QSEECOM_LISTENER_SERVICE) && - (req->ifd_data[i].fd > 0)) { - - if ((req->cmd_req_len < - SG_ENTRY_SZ * sg_ptr->nents) || - (req->ifd_data[i].cmd_buf_offset > - (req->cmd_req_len - - SG_ENTRY_SZ * sg_ptr->nents))) { - pr_err("Invalid offset = 0x%x\n", - req->ifd_data[i].cmd_buf_offset); - goto err; - } - - } else if ((data->type == QSEECOM_LISTENER_SERVICE) && - (lstnr_resp->ifd_data[i].fd > 0)) { + if (__boundary_checks_offset(req, lstnr_resp, data, i, + (SG_ENTRY_SZ * sg_ptr->nents))) + goto err; - if ((lstnr_resp->resp_len < - SG_ENTRY_SZ * sg_ptr->nents) || - (lstnr_resp->ifd_data[i].cmd_buf_offset > - (lstnr_resp->resp_len - - SG_ENTRY_SZ * sg_ptr->nents))) { - goto err; - } - } if ((data->type == QSEECOM_CLIENT_APP && (data->client.app_arch == ELFCLASS32 || data->client.app_arch == ELFCLASS64)) || @@ -4220,9 +4213,10 @@ static int __qseecom_update_cmd_buf_64(void *msg, bool cleanup, if (sg_ptr->nents == 1) { uint64_t *update_64bit; - if (__boundary_checks_offset_64(req, lstnr_resp, - data, i)) + if (__boundary_checks_offset(req, lstnr_resp, data, i, + sizeof(uint64_t))) goto err; + /* 64bit app uses 64bit address */ update_64bit = (uint64_t *) field; *update_64bit = cleanup ? 0 : @@ -4232,30 +4226,9 @@ static int __qseecom_update_cmd_buf_64(void *msg, bool cleanup, struct qseecom_sg_entry_64bit *update_64bit; int j = 0; - if ((data->type != QSEECOM_LISTENER_SERVICE) && - (req->ifd_data[i].fd > 0)) { - - if ((req->cmd_req_len < - SG_ENTRY_SZ_64BIT * sg_ptr->nents) || - (req->ifd_data[i].cmd_buf_offset > - (req->cmd_req_len - - SG_ENTRY_SZ_64BIT * sg_ptr->nents))) { - pr_err("Invalid offset = 0x%x\n", - req->ifd_data[i].cmd_buf_offset); - goto err; - } - - } else if ((data->type == QSEECOM_LISTENER_SERVICE) && - (lstnr_resp->ifd_data[i].fd > 0)) { - - if ((lstnr_resp->resp_len < - SG_ENTRY_SZ_64BIT * sg_ptr->nents) || - (lstnr_resp->ifd_data[i].cmd_buf_offset > - (lstnr_resp->resp_len - - SG_ENTRY_SZ_64BIT * sg_ptr->nents))) { - goto err; - } - } + if (__boundary_checks_offset(req, lstnr_resp, data, i, + (SG_ENTRY_SZ_64BIT * sg_ptr->nents))) + goto err; /* 64bit app uses 64bit address */ update_64bit = (struct qseecom_sg_entry_64bit *)field; for (j = 0; j < sg_ptr->nents; j++) { diff --git a/drivers/net/wireless/qualcomm/wcn39xx/fw-api/fw/wmi_unified.h b/drivers/net/wireless/qualcomm/wcn39xx/fw-api/fw/wmi_unified.h index 0268c5fd7659..8e5d23f37f90 100755 --- a/drivers/net/wireless/qualcomm/wcn39xx/fw-api/fw/wmi_unified.h +++ b/drivers/net/wireless/qualcomm/wcn39xx/fw-api/fw/wmi_unified.h @@ -2080,6 +2080,7 @@ typedef enum { #define WMI_CHAN_FLAG_DFS_CFREQ2 16 /* Enable radar event reporting for sec80 in VHT80p80 */ #define WMI_CHAN_FLAG_ALLOW_HE 17 /* HE (11ax) is allowed on this channel */ #define WMI_CHAN_FLAG_PSC 18 /* Indicate it is a PSC (preferred scanning channel) */ +#define WMI_CHAN_FLAG_NAN_DISABLED 19 /* Indicates that NAN operations are disabled on this channel */ #define WMI_SET_CHANNEL_FLAG(pwmi_channel,flag) do { \ (pwmi_channel)->info |= (1 << flag); \ @@ -3907,6 +3908,32 @@ typedef struct { #define WMI_RSRC_CFG_HOST_SERVICE_FLAG_NAN_IFACE_SUPPORT_SET(host_service_flags, val) \ WMI_SET_BITS(host_service_flags, 0, 1, val) +#define WMI_RSRC_CFG_HOST_SERVICE_FLAG_HOST_SUPPORT_MULTI_RADIO_EVTS_PER_RADIO_GET(host_service_flags) \ + WMI_GET_BITS(host_service_flags, 1, 1) +#define WMI_RSRC_CFG_HOST_SERVICE_FLAG_HOST_SUPPORT_MULTI_RADIO_EVTS_PER_RADIO_SET(host_service_flags, val) \ + WMI_SET_BITS(host_service_flags, 1, 1, val) + +#define WMI_RSRC_CFG_HOST_SERVICE_FLAG_SPLIT_AST_FEATURE_HOST_SUPPORT_GET(host_service_flags) \ + WMI_GET_BITS(host_service_flags, 2, 1) +#define WMI_RSRC_CFG_HOST_SERVICE_FLAG_SPLIT_AST_FEATURE_HOST_SUPPORT_SET(host_service_flags, val) \ + WMI_SET_BITS(host_service_flags, 2, 1, val) + +#define WMI_RSRC_CFG_HOST_SERVICE_FLAG_SAE_EAPOL_OFFLOAD_SUPPORT_GET(host_service_flags) \ + WMI_GET_BITS(host_service_flags, 3, 1) +#define WMI_RSRC_CFG_HOST_SERVICE_FLAG_SAE_EAPOL_OFFLOAD_SUPPORT_SET(host_service_flags, val) \ + WMI_SET_BITS(host_service_flags, 3, 1, val) + +#define WMI_RSRC_CFG_HOST_SERVICE_FLAG_REG_CC_EXT_SUPPORT_GET(host_service_flags) \ + WMI_GET_BITS(host_service_flags, 4, 1) +#define WMI_RSRC_CFG_HOST_SERVICE_FLAG_REG_CC_EXT_SUPPORT_SET(host_service_flags, val) \ + WMI_SET_BITS(host_service_flags, 4, 1, val) + +#define WMI_RSRC_CFG_HOST_SERVICE_FLAG_NAN_CHANNEL_SUPPORT_GET(host_service_flags) \ + WMI_GET_BITS(host_service_flags, 5, 1) +#define WMI_RSRC_CFG_HOST_SERVICE_FLAG_NAN_CHANNEL_SUPPORT_SET(host_service_flags, val) \ + WMI_SET_BITS(host_service_flags, 5, 1, val) + + typedef struct { A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_init_cmd_fixed_param */ diff --git a/drivers/net/wireless/qualcomm/wcn39xx/fw-api/fw/wmi_version.h b/drivers/net/wireless/qualcomm/wcn39xx/fw-api/fw/wmi_version.h index 9481ff4bb9ca..160707f9096f 100755 --- a/drivers/net/wireless/qualcomm/wcn39xx/fw-api/fw/wmi_version.h +++ b/drivers/net/wireless/qualcomm/wcn39xx/fw-api/fw/wmi_version.h @@ -36,7 +36,7 @@ #define __WMI_VER_MINOR_ 0 /** WMI revision number has to be incremented when there is a * change that may or may not break compatibility. */ -#define __WMI_REVISION_ 906 +#define __WMI_REVISION_ 992 /** The Version Namespace should not be normally changed. Only * host and firmware of the same WMI namespace will work diff --git a/drivers/net/wireless/qualcomm/wcn39xx/qca-wifi-host-cmn/os_if/linux/qca_vendor.h b/drivers/net/wireless/qualcomm/wcn39xx/qca-wifi-host-cmn/os_if/linux/qca_vendor.h index 043ec5fe5a49..dca3c1445fb7 100755 --- a/drivers/net/wireless/qualcomm/wcn39xx/qca-wifi-host-cmn/os_if/linux/qca_vendor.h +++ b/drivers/net/wireless/qualcomm/wcn39xx/qca-wifi-host-cmn/os_if/linux/qca_vendor.h @@ -140,7 +140,20 @@ * @QCA_NL80211_VENDOR_SUBCMD_GET_PREFERRED_FREQ_LIST: get preferred channel list * @QCA_NL80211_VENDOR_SUBCMD_SET_PROBABLE_OPER_CHANNEL: channel hint - * @QCA_NL80211_VENDOR_SUBCMD_SETBAND: vendor setband command + * @QCA_NL80211_VENDOR_SUBCMD_SETBAND: Command to configure the band + * to the host driver. This command sets the band through either + * the attribute QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE or + * QCA_WLAN_VENDOR_ATTR_SETBAND_MASK. QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE + * refers enum qca_set_band as unsigned integer values and + * QCA_WLAN_VENDOR_ATTR_SETBAND_MASK refers it as 32 bit unsigned BitMask + * values. Also, the acceptable values for + * QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE are only till QCA_SETBAND_2G. Further + * values/bitmask's are valid for QCA_WLAN_VENDOR_ATTR_SETBAND_MASK. The + * attribute QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE is deprecated and the + * recommendation is to use the QCA_WLAN_VENDOR_ATTR_SETBAND_MASK. If the + * implementations configure using both the attributes, the configurations + * through QCA_WLAN_VENDOR_ATTR_SETBAND_MASK shall always take the + * precedence. * @QCA_NL80211_VENDOR_SUBCMD_TRIGGER_SCAN: venodr scan command * @QCA_NL80211_VENDOR_SUBCMD_SCAN_DONE: vendor scan complete * @QCA_NL80211_VENDOR_SUBCMD_ABORT_SCAN: vendor abort scan @@ -620,6 +633,7 @@ enum qca_nl80211_vendor_subcmds { QCA_NL80211_VENDOR_SUBCMD_GET_SAR_LIMITS_EVENT = 187, QCA_NL80211_VENDOR_SUBCMD_UPDATE_STA_INFO = 188, QCA_NL80211_VENDOR_SUBCMD_DRIVER_DISCONNECT_REASON = 189, + QCA_NL80211_VENDOR_SUBCMD_GETBAND = 192, }; enum qca_wlan_vendor_tos { @@ -1068,6 +1082,11 @@ enum qca_wlan_vendor_attr_get_station_info { * @QCA_NL80211_VENDOR_SUBCMD_NAN_EXT_INDEX: NAN Extended index * @QCA_NL80211_VENDOR_SUBCMD_BEACON_REPORTING_INDEX: Beacon reporting index * @QCA_NL80211_VENDOR_SUBCMD_REQUEST_SAR_LIMITS_INDEX: Request SAR limit index + * + * @QCA_NL80211_VENDOR_SUBCMD_GETBAND: Command to get the configured band from + * the host driver. The band configurations obtained are referred through + * QCA_WLAN_VENDOR_ATTR_SETBAND_MASK. + * */ enum qca_nl80211_vendor_subcmds_index { @@ -1333,7 +1352,13 @@ enum qca_wlan_vendor_attr { QCA_WLAN_VENDOR_ATTR_MAX_CONCURRENT_CHANNELS_2_4_BAND = 10, /* Unsigned 32-bit value */ QCA_WLAN_VENDOR_ATTR_MAX_CONCURRENT_CHANNELS_5_0_BAND = 11, - /* Unsigned 32-bit value from enum qca_set_band. */ + /* Unsigned 32-bit value from enum qca_set_band. Also, the acceptable + * value for this attribute are only till QCA_SETBAND_2G. This attribute + * is deprecated. Recommendation is to use + * QCA_WLAN_VENDOR_ATTR_SETBAND_MASK instead. If the band is configured + * using both the attributes, the ones configured through + * QCA_WLAN_VENDOR_ATTR_SETBAND_MASK take the precedence. + */ QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE = 12, /* Dummy (NOP) attribute for 64 bit padding */ QCA_WLAN_VENDOR_ATTR_PAD = 13, @@ -1520,9 +1545,18 @@ enum qca_wlan_vendor_attr { */ QCA_WLAN_VENDOR_ATTR_FW_STATE = 42, + /* Unsigned 32-bitmask value from enum qca_set_band. Substitutes the + * attribute QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE for which only the + * integer values of enum qca_set_band till QCA_SETBAND_2G are valid. + * This attribute shall consider the bitmask combinations to define + * the respective Band combinations and always takes precedence over + * QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE. + */ + QCA_WLAN_VENDOR_ATTR_SETBAND_MASK = 43, + /* keep last */ QCA_WLAN_VENDOR_ATTR_AFTER_LAST, - QCA_WLAN_VENDOR_ATTR_MAX = QCA_WLAN_VENDOR_ATTR_AFTER_LAST - 1 + QCA_WLAN_VENDOR_ATTR_MAX = QCA_WLAN_VENDOR_ATTR_AFTER_LAST - 1 }; enum qca_wlan_vendor_attr_extscan_config_params { @@ -4772,9 +4806,10 @@ enum qca_wlan_vendor_attr_pcl_config { }; enum qca_set_band { - QCA_SETBAND_AUTO, - QCA_SETBAND_5G, - QCA_SETBAND_2G, + QCA_SETBAND_AUTO = 0, + QCA_SETBAND_5G = BIT(0), + QCA_SETBAND_2G = BIT(1), + QCA_SETBAND_6G = BIT(2), }; /** diff --git a/drivers/net/wireless/qualcomm/wcn39xx/qca-wifi-host-cmn/umac/regulatory/core/src/reg_build_chan_list.c b/drivers/net/wireless/qualcomm/wcn39xx/qca-wifi-host-cmn/umac/regulatory/core/src/reg_build_chan_list.c index f523857c7c4a..d783f8158316 100755 --- a/drivers/net/wireless/qualcomm/wcn39xx/qca-wifi-host-cmn/umac/regulatory/core/src/reg_build_chan_list.c +++ b/drivers/net/wireless/qualcomm/wcn39xx/qca-wifi-host-cmn/umac/regulatory/core/src/reg_build_chan_list.c @@ -253,18 +253,43 @@ static void reg_modify_chan_list_for_indoor_channels( } } +#ifdef CONFIG_BAND_6GHZ +static void reg_modify_chan_list_for_band_6G( + struct regulatory_channel *chan_list) +{ + enum channel_enum chan_enum; + + reg_debug("disabling 6G"); + for (chan_enum = MIN_6GHZ_CHANNEL; + chan_enum <= MAX_6GHZ_CHANNEL; chan_enum++) { + chan_list[chan_enum].chan_flags |= + REGULATORY_CHAN_DISABLED; + chan_list[chan_enum].state = CHANNEL_STATE_DISABLE; + } +} +#else +static inline void reg_modify_chan_list_for_band_6G( + struct regulatory_channel *chan_list) +{ +} +#endif + /** - * reg_modify_chan_list_for_band() - Based on the input band value, either - * disable 2GHz or 5GHz channels. + * reg_modify_chan_list_for_band() - Based on the input band bitmap, either + * disable 2GHz, 5GHz, or 6GHz channels. * @chan_list: Pointer to regulatory channel list. - * @band_val: Input band value. + * @band_bitmap: Input bitmap of reg_wifi_band values. */ static void reg_modify_chan_list_for_band(struct regulatory_channel *chan_list, - enum band_info band_val) + uint32_t band_bitmap) { enum channel_enum chan_enum; - if (band_val == BAND_2G) { + if (!band_bitmap) + return; + + if (!(band_bitmap & BIT(REG_BAND_5G))) { + reg_debug("disabling 5G"); for (chan_enum = MIN_5GHZ_CHANNEL; chan_enum <= MAX_5GHZ_CHANNEL; chan_enum++) { chan_list[chan_enum].chan_flags |= @@ -273,7 +298,8 @@ static void reg_modify_chan_list_for_band(struct regulatory_channel *chan_list, } } - if (band_val == BAND_5G) { + if (!(band_bitmap & BIT(REG_BAND_2G))) { + reg_debug("disabling 2G"); for (chan_enum = MIN_24GHZ_CHANNEL; chan_enum <= MAX_24GHZ_CHANNEL; chan_enum++) { chan_list[chan_enum].chan_flags |= @@ -281,6 +307,10 @@ static void reg_modify_chan_list_for_band(struct regulatory_channel *chan_list, chan_list[chan_enum].state = CHANNEL_STATE_DISABLE; } } + + if (!(band_bitmap & BIT(REG_BAND_6G))) + reg_modify_chan_list_for_band_6G(chan_list); + } /** @@ -1053,7 +1083,8 @@ QDF_STATUS reg_process_master_chan_list( REGULATORY_CHAN_DISABLED; mas_chan_list[chan_enum].state = CHANNEL_STATE_DISABLE; - mas_chan_list[chan_enum].nol_chan = false; + if (!soc_reg->retain_nol_across_regdmn_update) + mas_chan_list[chan_enum].nol_chan = false; } soc_reg->num_phy = regulat_info->num_phy; diff --git a/drivers/net/wireless/qualcomm/wcn39xx/qca-wifi-host-cmn/umac/regulatory/core/src/reg_priv_objs.c b/drivers/net/wireless/qualcomm/wcn39xx/qca-wifi-host-cmn/umac/regulatory/core/src/reg_priv_objs.c index edb10ba61baa..e4e665ab6a90 100755 --- a/drivers/net/wireless/qualcomm/wcn39xx/qca-wifi-host-cmn/umac/regulatory/core/src/reg_priv_objs.c +++ b/drivers/net/wireless/qualcomm/wcn39xx/qca-wifi-host-cmn/umac/regulatory/core/src/reg_priv_objs.c @@ -82,7 +82,8 @@ QDF_STATUS wlan_regulatory_psoc_obj_created_notification( soc_reg_obj->offload_enabled = false; soc_reg_obj->psoc_ptr = psoc; soc_reg_obj->dfs_enabled = true; - soc_reg_obj->band_capability = BAND_ALL; + soc_reg_obj->band_capability = (BIT(REG_BAND_2G) | BIT(REG_BAND_5G) | + BIT(REG_BAND_6G)); soc_reg_obj->enable_11d_supp = false; soc_reg_obj->indoor_chan_enabled = true; soc_reg_obj->force_ssc_disable_indoor_channel = false; @@ -92,6 +93,7 @@ QDF_STATUS wlan_regulatory_psoc_obj_created_notification( soc_reg_obj->restart_beaconing = CH_AVOID_RULE_RESTART; soc_reg_obj->enable_srd_chan_in_master_mode = true; soc_reg_obj->enable_11d_in_world_mode = false; + soc_reg_obj->retain_nol_across_regdmn_update = false; for (i = 0; i < MAX_STA_VDEV_CNT; i++) soc_reg_obj->vdev_ids_11d[i] = INVALID_VDEV_ID; @@ -204,7 +206,7 @@ QDF_STATUS wlan_regulatory_pdev_obj_created_notification( pdev_priv_obj->pdev_ptr = pdev; pdev_priv_obj->dfs_enabled = psoc_priv_obj->dfs_enabled; pdev_priv_obj->set_fcc_channel = false; - pdev_priv_obj->band_capability = psoc_priv_obj->band_capability; + pdev_priv_obj->band_capability = psoc_priv_obj->band_capability; pdev_priv_obj->indoor_chan_enabled = psoc_priv_obj->indoor_chan_enabled; pdev_priv_obj->en_chan_144 = true; diff --git a/drivers/net/wireless/qualcomm/wcn39xx/qca-wifi-host-cmn/umac/regulatory/core/src/reg_priv_objs.h b/drivers/net/wireless/qualcomm/wcn39xx/qca-wifi-host-cmn/umac/regulatory/core/src/reg_priv_objs.h index cf62e0eda76b..9743499b081f 100755 --- a/drivers/net/wireless/qualcomm/wcn39xx/qca-wifi-host-cmn/umac/regulatory/core/src/reg_priv_objs.h +++ b/drivers/net/wireless/qualcomm/wcn39xx/qca-wifi-host-cmn/umac/regulatory/core/src/reg_priv_objs.h @@ -89,8 +89,12 @@ struct chan_change_cbk_entry { * country update is pending for pdev (phy_id). * @world_country_pending: In this array, element[phy_id] is true if any world * country update is pending for pdev (phy_id). + * @band_capability: bitmap of bands enabled, using enum reg_wifi_band as the + * bit position value * @ignore_fw_reg_offload_ind: Ignore FW reg offload indication * @six_ghz_supported: whether 6ghz is supported + * @retain_nol_across_regdmn_update: Retain the NOL list across the regdomain + * changes. */ struct wlan_regulatory_psoc_priv_obj { struct mas_chan_params mas_chan_params[PSOC_MAX_PHY_REG_CAP]; @@ -109,7 +113,7 @@ struct wlan_regulatory_psoc_priv_obj { bool new_11d_ctry_pending[PSOC_MAX_PHY_REG_CAP]; bool world_country_pending[PSOC_MAX_PHY_REG_CAP]; bool dfs_enabled; - enum band_info band_capability; + uint32_t band_capability; bool indoor_chan_enabled; bool ignore_fw_reg_offload_ind; bool enable_11d_supp_original; @@ -140,11 +144,14 @@ struct wlan_regulatory_psoc_priv_obj { bool enable_srd_chan_in_master_mode; bool enable_11d_in_world_mode; qdf_spinlock_t cbk_list_lock; + bool retain_nol_across_regdmn_update; }; /** * struct wlan_regulatory_pdev_priv_obj - wlan regulatory pdev private object * @pdev_opened: whether pdev has been opened by application + * @band_capability: bitmap of bands enabled, using enum reg_wifi_band as the + * bit position value */ struct wlan_regulatory_pdev_priv_obj { struct regulatory_channel cur_chan_list[NUM_CHANNELS]; @@ -172,7 +179,7 @@ struct wlan_regulatory_pdev_priv_obj { qdf_freq_t range_5g_high; bool dfs_enabled; bool set_fcc_channel; - enum band_info band_capability; + uint32_t band_capability; bool indoor_chan_enabled; bool en_chan_144; uint32_t wireless_modes; diff --git a/drivers/net/wireless/qualcomm/wcn39xx/qca-wifi-host-cmn/umac/regulatory/core/src/reg_services_common.c b/drivers/net/wireless/qualcomm/wcn39xx/qca-wifi-host-cmn/umac/regulatory/core/src/reg_services_common.c index 8dbf1d60a790..c3abb6084707 100755 --- a/drivers/net/wireless/qualcomm/wcn39xx/qca-wifi-host-cmn/umac/regulatory/core/src/reg_services_common.c +++ b/drivers/net/wireless/qualcomm/wcn39xx/qca-wifi-host-cmn/umac/regulatory/core/src/reg_services_common.c @@ -1509,22 +1509,6 @@ void reg_set_channel_params(struct wlan_objmgr_pdev *pdev, } #endif /* CONFIG_CHAN_NUM_API */ -QDF_STATUS reg_get_curr_band(struct wlan_objmgr_pdev *pdev, - enum band_info *band) -{ - struct wlan_regulatory_pdev_priv_obj *pdev_reg; - - pdev_reg = reg_get_pdev_obj(pdev); - if (!IS_VALID_PDEV_REG_OBJ(pdev_reg)) { - reg_err("pdev reg component is NULL"); - return QDF_STATUS_E_INVAL; - } - - *band = pdev_reg->band_capability; - - return QDF_STATUS_SUCCESS; -} - QDF_STATUS reg_read_default_country(struct wlan_objmgr_psoc *psoc, uint8_t *country_code) { @@ -2357,6 +2341,32 @@ static inline bool BAND_5G_PRESENT(uint8_t band_mask) return !!(band_mask & (BIT(REG_BAND_5G))); } +bool reg_is_freq_indoor(struct wlan_objmgr_pdev *pdev, qdf_freq_t freq) +{ + struct regulatory_channel *cur_chan_list; + struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj; + enum channel_enum chan_enum; + + pdev_priv_obj = reg_get_pdev_obj(pdev); + + if (!IS_VALID_PDEV_REG_OBJ(pdev_priv_obj)) { + reg_err("reg pdev priv obj is NULL"); + return false; + } + + chan_enum = reg_get_chan_enum_for_freq(freq); + + if (chan_enum == INVALID_CHANNEL) { + reg_err_rl("Invalid chan enum %d", chan_enum); + return false; + } + + cur_chan_list = pdev_priv_obj->cur_chan_list; + + return (cur_chan_list[chan_enum].chan_flags & + REGULATORY_CHAN_INDOOR_ONLY); +} + #ifdef CONFIG_BAND_6GHZ bool reg_is_6ghz_chan_freq(uint16_t freq) { @@ -3410,13 +3420,46 @@ bool reg_is_dfs_for_freq(struct wlan_objmgr_pdev *pdev, qdf_freq_t freq) return chan_flags & REGULATORY_CHAN_RADAR; } +#ifdef CONFIG_REG_CLIENT +/** + * reg_get_psoc_mas_chan_list () - Get psoc master channel list + * @pdev: pointer to pdev object + * @psoc: pointer to psoc object + * + * Return: psoc master chanel list + */ +static struct regulatory_channel *reg_get_psoc_mas_chan_list( + struct wlan_objmgr_pdev *pdev, + struct wlan_objmgr_psoc *psoc) +{ + struct wlan_regulatory_psoc_priv_obj *soc_reg; + uint8_t pdev_id; + + soc_reg = reg_get_psoc_obj(psoc); + if (!soc_reg) { + reg_err("reg psoc private obj is NULL"); + return NULL; + } + pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev); + + return soc_reg->mas_chan_params[pdev_id].mas_chan_list; +} +#else +static inline struct regulatory_channel *reg_get_psoc_mas_chan_list( + struct wlan_objmgr_pdev *pdev, + struct wlan_objmgr_psoc *psoc) +{ + return NULL; +} +#endif + void reg_update_nol_ch_for_freq(struct wlan_objmgr_pdev *pdev, uint16_t *chan_freq_list, uint8_t num_chan, bool nol_chan) { enum channel_enum chan_enum; - struct regulatory_channel *mas_chan_list; + struct regulatory_channel *mas_chan_list, *psoc_mas_chan_list; struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj; struct wlan_objmgr_psoc *psoc; uint16_t i; @@ -3434,6 +3477,8 @@ void reg_update_nol_ch_for_freq(struct wlan_objmgr_pdev *pdev, return; } + psoc_mas_chan_list = reg_get_psoc_mas_chan_list(pdev, psoc); + mas_chan_list = pdev_priv_obj->mas_chan_list; for (i = 0; i < num_chan; i++) { chan_enum = reg_get_chan_enum_for_freq(chan_freq_list[i]); @@ -3443,6 +3488,8 @@ void reg_update_nol_ch_for_freq(struct wlan_objmgr_pdev *pdev, continue; } mas_chan_list[chan_enum].nol_chan = nol_chan; + if (psoc_mas_chan_list) + psoc_mas_chan_list[chan_enum].nol_chan = nol_chan; } reg_compute_pdev_current_chan_list(pdev_priv_obj); @@ -3645,3 +3692,30 @@ reg_get_unii_5g_bitmap(struct wlan_objmgr_pdev *pdev, uint8_t *bitmap) return QDF_STATUS_SUCCESS; } #endif + +#ifdef CONFIG_REG_CLIENT +enum band_info reg_band_bitmap_to_band_info(uint32_t band_bitmap) +{ + if ((band_bitmap & BIT(REG_BAND_2G)) && + (band_bitmap & BIT(REG_BAND_5G)) && + (band_bitmap & BIT(REG_BAND_6G))) + return BAND_ALL; + else if ((band_bitmap & BIT(REG_BAND_5G)) && + (band_bitmap & BIT(REG_BAND_6G))) + return BAND_5G; + else if ((band_bitmap & BIT(REG_BAND_2G)) && + (band_bitmap & BIT(REG_BAND_6G))) + return BAND_2G; + else if ((band_bitmap & BIT(REG_BAND_2G)) && + (band_bitmap & BIT(REG_BAND_5G))) + return BAND_ALL; + else if (band_bitmap & BIT(REG_BAND_2G)) + return BAND_2G; + else if (band_bitmap & BIT(REG_BAND_5G)) + return BAND_5G; + else if (band_bitmap & BIT(REG_BAND_6G)) + return BAND_2G; + else + return BAND_UNKNOWN; +} +#endif diff --git a/drivers/net/wireless/qualcomm/wcn39xx/qca-wifi-host-cmn/umac/regulatory/core/src/reg_services_common.h b/drivers/net/wireless/qualcomm/wcn39xx/qca-wifi-host-cmn/umac/regulatory/core/src/reg_services_common.h index 24ed4f5c743b..d18e01827905 100755 --- a/drivers/net/wireless/qualcomm/wcn39xx/qca-wifi-host-cmn/umac/regulatory/core/src/reg_services_common.h +++ b/drivers/net/wireless/qualcomm/wcn39xx/qca-wifi-host-cmn/umac/regulatory/core/src/reg_services_common.h @@ -354,16 +354,6 @@ QDF_STATUS reg_program_default_cc(struct wlan_objmgr_pdev *pdev, QDF_STATUS reg_get_current_cc(struct wlan_objmgr_pdev *pdev, struct cc_regdmn_s *rd); -/** - * reg_get_curr_band() - Get current band - * @pdev: Pdev pointer - * @band: Pointer to save the current band - * - * Return: QDF_STATUS - */ -QDF_STATUS reg_get_curr_band(struct wlan_objmgr_pdev *pdev, - enum band_info *band); - /** * reg_set_regdb_offloaded() - set/clear regulatory offloaded flag * @@ -499,6 +489,15 @@ bool reg_is_24ghz_ch_freq(uint32_t freq); */ bool reg_is_5ghz_ch_freq(uint32_t freq); +/** + * reg_is_freq_indoor() - Check if the input frequency is an indoor frequency. + * @pdev: Pointer to pdev. + * @freq: Channel frequency. + * + * Return: Return true if the input frequency is indoor, else false. + */ +bool reg_is_freq_indoor(struct wlan_objmgr_pdev *pdev, qdf_freq_t freq); + #ifdef CONFIG_BAND_6GHZ /** * reg_is_6ghz_chan_freq() - Check if the given channel frequency is 6GHz @@ -1015,4 +1014,17 @@ QDF_STATUS reg_get_unii_5g_bitmap(struct wlan_objmgr_pdev *pdev, uint8_t *bitmap); #endif +#ifdef CONFIG_REG_CLIENT +/** + * reg_band_bitmap_to_band_info() - Convert the band_bitmap to a band_info enum. + * Since band_info enum only has combinations for 2G and 5G, 6G is not + * considered in this function. + * @band_bitmap: bitmap on top of reg_wifi_band of bands enabled + * + * Return: BAND_ALL if both 2G and 5G band is enabled + * BAND_2G if 2G is enabled but 5G isn't + * BAND_5G if 5G is enabled but 2G isn't + */ +enum band_info reg_band_bitmap_to_band_info(uint32_t band_bitmap); +#endif #endif diff --git a/drivers/net/wireless/qualcomm/wcn39xx/qca-wifi-host-cmn/umac/regulatory/core/src/reg_utils.c b/drivers/net/wireless/qualcomm/wcn39xx/qca-wifi-host-cmn/umac/regulatory/core/src/reg_utils.c index 5782489e2e92..5ebd0931b37e 100755 --- a/drivers/net/wireless/qualcomm/wcn39xx/qca-wifi-host-cmn/umac/regulatory/core/src/reg_utils.c +++ b/drivers/net/wireless/qualcomm/wcn39xx/qca-wifi-host-cmn/umac/regulatory/core/src/reg_utils.c @@ -449,8 +449,7 @@ bool reg_is_etsi13_srd_chan_allowed_master_mode(struct wlan_objmgr_pdev *pdev) } #endif -QDF_STATUS reg_set_band(struct wlan_objmgr_pdev *pdev, - enum band_info band) +QDF_STATUS reg_set_band(struct wlan_objmgr_pdev *pdev, uint32_t band_bitmap) { struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj; struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj; @@ -464,8 +463,8 @@ QDF_STATUS reg_set_band(struct wlan_objmgr_pdev *pdev, return QDF_STATUS_E_INVAL; } - if (pdev_priv_obj->band_capability == band) { - reg_info("same band %d", band); + if (pdev_priv_obj->band_capability == band_bitmap) { + reg_info("same band %d", band_bitmap); return QDF_STATUS_SUCCESS; } @@ -481,8 +480,8 @@ QDF_STATUS reg_set_band(struct wlan_objmgr_pdev *pdev, return QDF_STATUS_E_INVAL; } - reg_info("set band_info: %d", band); - pdev_priv_obj->band_capability = band; + reg_info("set band bitmap: %d", band_bitmap); + pdev_priv_obj->band_capability = band_bitmap; reg_compute_pdev_current_chan_list(pdev_priv_obj); @@ -492,11 +491,9 @@ QDF_STATUS reg_set_band(struct wlan_objmgr_pdev *pdev, } QDF_STATUS reg_get_band(struct wlan_objmgr_pdev *pdev, - enum band_info *band) + uint32_t *band_bitmap) { - struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj; struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj; - struct wlan_objmgr_psoc *psoc; pdev_priv_obj = reg_get_pdev_obj(pdev); @@ -505,20 +502,8 @@ QDF_STATUS reg_get_band(struct wlan_objmgr_pdev *pdev, return QDF_STATUS_E_INVAL; } - psoc = wlan_pdev_get_psoc(pdev); - if (!psoc) { - reg_err("psoc is NULL"); - return QDF_STATUS_E_INVAL; - } - - psoc_priv_obj = reg_get_psoc_obj(psoc); - if (!IS_VALID_PSOC_REG_OBJ(psoc_priv_obj)) { - reg_err("psoc reg component is NULL"); - return QDF_STATUS_E_INVAL; - } - - reg_debug("get band_info: %d", pdev_priv_obj->band_capability); - *band = pdev_priv_obj->band_capability; + reg_debug("get band bitmap: %d", pdev_priv_obj->band_capability); + *band_bitmap = pdev_priv_obj->band_capability; return QDF_STATUS_SUCCESS; } @@ -802,6 +787,8 @@ QDF_STATUS reg_set_config_vars(struct wlan_objmgr_psoc *psoc, config_vars.enable_srd_chan_in_master_mode; psoc_priv_obj->enable_11d_in_world_mode = config_vars.enable_11d_in_world_mode; + psoc_priv_obj->retain_nol_across_regdmn_update = + config_vars.retain_nol_across_regdmn_update; status = wlan_objmgr_psoc_try_get_ref(psoc, WLAN_REGULATORY_SB_ID); if (QDF_IS_STATUS_ERROR(status)) { diff --git a/drivers/net/wireless/qualcomm/wcn39xx/qca-wifi-host-cmn/umac/regulatory/core/src/reg_utils.h b/drivers/net/wireless/qualcomm/wcn39xx/qca-wifi-host-cmn/umac/regulatory/core/src/reg_utils.h index 059c1b3240c1..f41b6342c06b 100755 --- a/drivers/net/wireless/qualcomm/wcn39xx/qca-wifi-host-cmn/umac/regulatory/core/src/reg_utils.h +++ b/drivers/net/wireless/qualcomm/wcn39xx/qca-wifi-host-cmn/umac/regulatory/core/src/reg_utils.h @@ -216,20 +216,20 @@ QDF_STATUS reg_cache_channel_state(struct wlan_objmgr_pdev *pdev, /** * reg_set_band() - Sets the band information for the PDEV * @pdev: The physical dev to set the band for - * @band: The set band parameters to configure for the physical device + * @band_bitmap: The set band parameters to configure for the physical device * * Return: QDF_STATUS */ -QDF_STATUS reg_set_band(struct wlan_objmgr_pdev *pdev, enum band_info band); +QDF_STATUS reg_set_band(struct wlan_objmgr_pdev *pdev, uint32_t band_bitmap); /** * reg_get_band() - Get the band information for the PDEV * @pdev: The physical dev to get the band for - * @band: The band parameters of the physical device + * @band_bitmap: The band parameters of the physical device * * Return: QDF_STATUS */ -QDF_STATUS reg_get_band(struct wlan_objmgr_pdev *pdev, enum band_info *band); +QDF_STATUS reg_get_band(struct wlan_objmgr_pdev *pdev, uint32_t *band_bitmap); /** * reg_set_fcc_constraint() - Apply fcc constraints on channels 12/13 @@ -655,4 +655,5 @@ static inline void set_disable_channel_state( { } #endif + #endif diff --git a/drivers/net/wireless/qualcomm/wcn39xx/qca-wifi-host-cmn/umac/regulatory/dispatcher/inc/reg_services_public_struct.h b/drivers/net/wireless/qualcomm/wcn39xx/qca-wifi-host-cmn/umac/regulatory/dispatcher/inc/reg_services_public_struct.h index 08a058fe4263..dd3246356ac8 100755 --- a/drivers/net/wireless/qualcomm/wcn39xx/qca-wifi-host-cmn/umac/regulatory/dispatcher/inc/reg_services_public_struct.h +++ b/drivers/net/wireless/qualcomm/wcn39xx/qca-wifi-host-cmn/umac/regulatory/dispatcher/inc/reg_services_public_struct.h @@ -949,18 +949,20 @@ enum restart_beaconing_on_ch_avoid_rule { * away from active LTE channels * @enable_srd_chan_in_master_mode: SRD channel support in master mode * @enable_11d_in_world_mode: enable 11d in world mode + * @retain_nol_across_regdmn_update: Retain the NOL list across the regdomain. */ struct reg_config_vars { uint32_t enable_11d_support; uint32_t scan_11d_interval; uint32_t userspace_ctry_priority; - enum band_info band_capability; + uint32_t band_capability; uint32_t dfs_enabled; uint32_t indoor_chan_enabled; uint32_t force_ssc_disable_indoor_channel; enum restart_beaconing_on_ch_avoid_rule restart_beaconing; bool enable_srd_chan_in_master_mode; bool enable_11d_in_world_mode; + bool retain_nol_across_regdmn_update; }; /** diff --git a/drivers/net/wireless/qualcomm/wcn39xx/qca-wifi-host-cmn/umac/regulatory/dispatcher/inc/wlan_reg_services_api.h b/drivers/net/wireless/qualcomm/wcn39xx/qca-wifi-host-cmn/umac/regulatory/dispatcher/inc/wlan_reg_services_api.h index 3f32a9c30e4e..0c8f420ee0ce 100755 --- a/drivers/net/wireless/qualcomm/wcn39xx/qca-wifi-host-cmn/umac/regulatory/dispatcher/inc/wlan_reg_services_api.h +++ b/drivers/net/wireless/qualcomm/wcn39xx/qca-wifi-host-cmn/umac/regulatory/dispatcher/inc/wlan_reg_services_api.h @@ -132,6 +132,15 @@ bool wlan_reg_is_24ghz_ch_freq(qdf_freq_t freq); #define WLAN_REG_IS_5GHZ_CH_FREQ(freq) wlan_reg_is_5ghz_ch_freq(freq) bool wlan_reg_is_5ghz_ch_freq(qdf_freq_t freq); +/** + * wlan_reg_is_freq_indoor() - Check if a frequency is indoor. + * @pdev: Pointer to pdev. + * @freq: Channel frequency. + * + * Return: Return true if a frequency is indoor, else false. + */ +bool wlan_reg_is_freq_indoor(struct wlan_objmgr_pdev *pdev, qdf_freq_t freq); + #ifdef CONFIG_BAND_6GHZ /** * wlan_reg_is_6ghz_chan_freq() - Check if the given channel frequency is 6GHz @@ -1294,4 +1303,16 @@ wlan_reg_country_chan_opclass_to_freq(struct wlan_objmgr_pdev *pdev, uint16_t wlan_reg_chan_opclass_to_freq(uint8_t chan, uint8_t op_class, bool global_tbl_lookup); +#ifdef CONFIG_REG_CLIENT +/** + * wlan_reg_band_bitmap_to_band_info() - Convert the band_bitmap to a + * band_info enum + * @band_bitmap: bitmap on top of reg_wifi_band of bands enabled + * + * Return: BAND_ALL if both 2G and 5G band is enabled + * BAND_2G if 2G is enabled but 5G isn't + * BAND_5G if 5G is enabled but 2G isn't + */ +enum band_info wlan_reg_band_bitmap_to_band_info(uint32_t band_bitmap); +#endif #endif diff --git a/drivers/net/wireless/qualcomm/wcn39xx/qca-wifi-host-cmn/umac/regulatory/dispatcher/inc/wlan_reg_ucfg_api.h b/drivers/net/wireless/qualcomm/wcn39xx/qca-wifi-host-cmn/umac/regulatory/dispatcher/inc/wlan_reg_ucfg_api.h index c98f728f186d..3697ce78c60d 100755 --- a/drivers/net/wireless/qualcomm/wcn39xx/qca-wifi-host-cmn/umac/regulatory/dispatcher/inc/wlan_reg_ucfg_api.h +++ b/drivers/net/wireless/qualcomm/wcn39xx/qca-wifi-host-cmn/umac/regulatory/dispatcher/inc/wlan_reg_ucfg_api.h @@ -31,22 +31,23 @@ typedef QDF_STATUS (*reg_event_cb)(void *status_struct); /** * ucfg_reg_set_band() - Sets the band information for the PDEV * @pdev: The physical pdev to set the band for - * @band: The set band parameter to configure for the physical device + * @band_bitmap: The band bitmap parameter (over reg_wifi_band) to configure + * for the physical device * * Return: QDF_STATUS */ QDF_STATUS ucfg_reg_set_band(struct wlan_objmgr_pdev *pdev, - enum band_info band); + uint32_t band_bitmap); /** * ucfg_reg_get_band() - Gets the band information for the PDEV * @pdev: The physical pdev to get the band for - * @band: The band parameter of the physical device + * @band_bitmap: The band parameter of the physical device * * Return: QDF_STATUS */ QDF_STATUS ucfg_reg_get_band(struct wlan_objmgr_pdev *pdev, - enum band_info *band); + uint32_t *band_bitmap); /** * ucfg_reg_notify_sap_event() - Notify regulatory domain for sap event @@ -175,15 +176,6 @@ QDF_STATUS ucfg_reg_set_country(struct wlan_objmgr_pdev *dev, */ QDF_STATUS ucfg_reg_reset_country(struct wlan_objmgr_psoc *psoc); -/** - * ucfg_reg_get_curr_band() - Get the current band capability - * @pdev: The physical dev to get default country from - * @band: buffer to populate the band into - * - * Return: QDF_STATUS - */ -QDF_STATUS ucfg_reg_get_curr_band(struct wlan_objmgr_pdev *pdev, - enum band_info *band); /** * ucfg_reg_enable_dfs_channels() - Enable the use of DFS channels * @pdev: The physical dev to enable DFS channels for diff --git a/drivers/net/wireless/qualcomm/wcn39xx/qca-wifi-host-cmn/umac/regulatory/dispatcher/src/wlan_reg_services_api.c b/drivers/net/wireless/qualcomm/wcn39xx/qca-wifi-host-cmn/umac/regulatory/dispatcher/src/wlan_reg_services_api.c index 623fcefeb6cf..baa186a724ae 100755 --- a/drivers/net/wireless/qualcomm/wcn39xx/qca-wifi-host-cmn/umac/regulatory/dispatcher/src/wlan_reg_services_api.c +++ b/drivers/net/wireless/qualcomm/wcn39xx/qca-wifi-host-cmn/umac/regulatory/dispatcher/src/wlan_reg_services_api.c @@ -751,6 +751,11 @@ bool wlan_reg_is_5ghz_ch_freq(qdf_freq_t freq) return reg_is_5ghz_ch_freq(freq); } +bool wlan_reg_is_freq_indoor(struct wlan_objmgr_pdev *pdev, qdf_freq_t freq) +{ + return reg_is_freq_indoor(pdev, freq); +} + #ifdef CONFIG_BAND_6GHZ bool wlan_reg_is_6ghz_chan_freq(uint16_t freq) { @@ -1111,3 +1116,10 @@ uint16_t wlan_reg_chan_opclass_to_freq(uint8_t chan, return reg_chan_opclass_to_freq(chan, op_class, global_tbl_lookup); } + +#ifdef CONFIG_REG_CLIENT +enum band_info wlan_reg_band_bitmap_to_band_info(uint32_t band_bitmap) +{ + return reg_band_bitmap_to_band_info(band_bitmap); +} +#endif diff --git a/drivers/net/wireless/qualcomm/wcn39xx/qca-wifi-host-cmn/umac/regulatory/dispatcher/src/wlan_reg_ucfg_api.c b/drivers/net/wireless/qualcomm/wcn39xx/qca-wifi-host-cmn/umac/regulatory/dispatcher/src/wlan_reg_ucfg_api.c index c500982a266f..3d423789fa2a 100755 --- a/drivers/net/wireless/qualcomm/wcn39xx/qca-wifi-host-cmn/umac/regulatory/dispatcher/src/wlan_reg_ucfg_api.c +++ b/drivers/net/wireless/qualcomm/wcn39xx/qca-wifi-host-cmn/umac/regulatory/dispatcher/src/wlan_reg_ucfg_api.c @@ -119,15 +119,15 @@ QDF_STATUS ucfg_reg_get_current_cc(struct wlan_objmgr_pdev *pdev, #ifdef CONFIG_REG_CLIENT QDF_STATUS ucfg_reg_set_band(struct wlan_objmgr_pdev *pdev, - enum band_info band) + uint32_t band_bitmap) { - return reg_set_band(pdev, band); + return reg_set_band(pdev, band_bitmap); } QDF_STATUS ucfg_reg_get_band(struct wlan_objmgr_pdev *pdev, - enum band_info *band) + uint32_t *band_bitmap) { - return reg_get_band(pdev, band); + return reg_get_band(pdev, band_bitmap); } /** @@ -227,13 +227,6 @@ QDF_STATUS ucfg_reg_enable_dfs_channels(struct wlan_objmgr_pdev *pdev, return reg_enable_dfs_channels(pdev, dfs_enable); } -QDF_STATUS ucfg_reg_get_curr_band(struct wlan_objmgr_pdev *pdev, - enum band_info *band) -{ - return reg_get_curr_band(pdev, band); - -} - void ucfg_reg_register_chan_change_callback(struct wlan_objmgr_psoc *psoc, void *cbk, void *arg) { diff --git a/drivers/net/wireless/qualcomm/wcn39xx/qca-wifi-host-cmn/umac/scan/dispatcher/inc/wlan_scan_utils_api.h b/drivers/net/wireless/qualcomm/wcn39xx/qca-wifi-host-cmn/umac/scan/dispatcher/inc/wlan_scan_utils_api.h index a907b3fac65f..36df0055a134 100755 --- a/drivers/net/wireless/qualcomm/wcn39xx/qca-wifi-host-cmn/umac/scan/dispatcher/inc/wlan_scan_utils_api.h +++ b/drivers/net/wireless/qualcomm/wcn39xx/qca-wifi-host-cmn/umac/scan/dispatcher/inc/wlan_scan_utils_api.h @@ -1401,7 +1401,7 @@ util_scan_entry_get_extcap(struct scan_cache_entry *scan_entry, if (!ext_cap) return QDF_STATUS_E_NULL_VALUE; - if (ext_cap->ext_cap_len < ext_caps_byte) + if (ext_cap->ext_cap_len <= ext_caps_byte) return QDF_STATUS_E_NULL_VALUE; *extcap_value = diff --git a/drivers/net/wireless/qualcomm/wcn39xx/qca-wifi-host-cmn/wmi/inc/wmi_unified_param.h b/drivers/net/wireless/qualcomm/wcn39xx/qca-wifi-host-cmn/wmi/inc/wmi_unified_param.h index 828ddcaee2a5..4bb61a280d23 100755 --- a/drivers/net/wireless/qualcomm/wcn39xx/qca-wifi-host-cmn/wmi/inc/wmi_unified_param.h +++ b/drivers/net/wireless/qualcomm/wcn39xx/qca-wifi-host-cmn/wmi/inc/wmi_unified_param.h @@ -620,6 +620,7 @@ typedef enum { * @set_agile: is agile mode * @allow_he: HE allowed on chan * @psc_channel: 6 ghz preferred scan chan + * @nan_disabled: is NAN disabled on @mhz * @phy_mode: phymode (vht80 or ht40 or ...) * @cfreq1: centre frequency on primary * @cfreq2: centre frequency on secondary @@ -644,7 +645,8 @@ struct channel_param { allow_vht:1, set_agile:1, allow_he:1, - psc_channel:1; + psc_channel:1, + nan_disabled:1; uint32_t phy_mode; uint32_t cfreq1; uint32_t cfreq2; diff --git a/drivers/net/wireless/qualcomm/wcn39xx/qca-wifi-host-cmn/wmi/src/wmi_unified_tlv.c b/drivers/net/wireless/qualcomm/wcn39xx/qca-wifi-host-cmn/wmi/src/wmi_unified_tlv.c index 3d4a346e789d..0cfb18f64712 100755 --- a/drivers/net/wireless/qualcomm/wcn39xx/qca-wifi-host-cmn/wmi/src/wmi_unified_tlv.c +++ b/drivers/net/wireless/qualcomm/wcn39xx/qca-wifi-host-cmn/wmi/src/wmi_unified_tlv.c @@ -3297,6 +3297,10 @@ static QDF_STATUS send_scan_chan_list_cmd_tlv(wmi_unified_t wmi_handle, WMI_SET_CHANNEL_FLAG(chan_info, WMI_CHAN_FLAG_PSC); + if (tchan_info->nan_disabled) + WMI_SET_CHANNEL_FLAG(chan_info, + WMI_CHAN_FLAG_NAN_DISABLED); + /* also fill in power information */ WMI_SET_CHANNEL_MIN_POWER(chan_info, tchan_info->minpower); @@ -6648,6 +6652,19 @@ static void wmi_copy_twt_resource_config(wmi_resource_config *resource_cfg, } #endif +#ifdef WLAN_FEATURE_NAN +static void wmi_set_nan_channel_support(wmi_resource_config *resource_cfg) +{ + WMI_RSRC_CFG_HOST_SERVICE_FLAG_NAN_CHANNEL_SUPPORT_SET( + resource_cfg->host_service_flags, 1); +} +#else +static inline +void wmi_set_nan_channel_support(wmi_resource_config *resource_cfg) +{ +} +#endif + static void wmi_copy_resource_config(wmi_resource_config *resource_cfg, target_resource_config *tgt_res_cfg) @@ -6855,6 +6872,7 @@ void wmi_copy_resource_config(wmi_resource_config *resource_cfg, resource_cfg->host_service_flags, tgt_res_cfg->nan_separate_iface_support); + wmi_set_nan_channel_support(resource_cfg); } /* copy_hw_mode_id_in_init_cmd() - Helper routine to copy hw_mode in init cmd diff --git a/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/components/cmn_services/policy_mgr/src/wlan_policy_mgr_action.c b/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/components/cmn_services/policy_mgr/src/wlan_policy_mgr_action.c index 46fa140d5af7..e600dca217b8 100755 --- a/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/components/cmn_services/policy_mgr/src/wlan_policy_mgr_action.c +++ b/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/components/cmn_services/policy_mgr/src/wlan_policy_mgr_action.c @@ -35,6 +35,7 @@ #include "wlan_nan_api.h" #include "nan_ucfg_api.h" #include "sap_api.h" +#include "wlan_mlme_api.h" enum policy_mgr_conc_next_action (*policy_mgr_get_current_pref_hw_mode_ptr) (struct wlan_objmgr_psoc *psoc); @@ -1940,6 +1941,22 @@ QDF_STATUS policy_mgr_valid_sap_conc_channel_check( uint32_t temp_ch_freq = 0; struct policy_mgr_psoc_priv_obj *pm_ctx; bool sta_sap_scc_on_dfs_chan; + struct wlan_objmgr_vdev *vdev; + enum QDF_OPMODE vdev_opmode; + bool enable_srd_channel; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, sap_vdev_id, + WLAN_POLICY_MGR_ID); + if (!vdev) { + policy_mgr_err("vdev is NULL"); + return QDF_STATUS_E_INVAL; + } + + vdev_opmode = wlan_vdev_mlme_get_opmode(vdev); + wlan_objmgr_vdev_release_ref(vdev, WLAN_POLICY_MGR_ID); + + wlan_mlme_get_srd_master_mode_for_vdev(psoc, vdev_opmode, + &enable_srd_channel); pm_ctx = policy_mgr_get_context(psoc); if (!pm_ctx) { @@ -1981,8 +1998,7 @@ QDF_STATUS policy_mgr_valid_sap_conc_channel_check( ch_freq) || !(policy_mgr_sta_sap_scc_on_lte_coex_chan(psoc) || policy_mgr_is_safe_channel(psoc, ch_freq)) || - (!wlan_reg_is_etsi13_srd_chan_allowed_master_mode( - pm_ctx->pdev) && + (!enable_srd_channel && wlan_reg_is_etsi13_srd_chan_for_freq(pm_ctx->pdev, ch_freq))) { if (wlan_reg_is_dfs_for_freq(pm_ctx->pdev, ch_freq) && diff --git a/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/components/cmn_services/policy_mgr/src/wlan_policy_mgr_core.c b/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/components/cmn_services/policy_mgr/src/wlan_policy_mgr_core.c index a94030dc9751..8b17d4c23069 100755 --- a/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/components/cmn_services/policy_mgr/src/wlan_policy_mgr_core.c +++ b/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/components/cmn_services/policy_mgr/src/wlan_policy_mgr_core.c @@ -2116,7 +2116,6 @@ QDF_STATUS policy_mgr_get_channel_list(struct wlan_objmgr_psoc *psoc, uint32_t sbs_num_channels = 0; uint32_t chan_index_24 = 0, chan_index_5 = 0, chan_index_6 = 0; bool skip_dfs_channel = false; - bool is_etsi13_srd_chan_allowed_in_mas_mode = true; uint32_t i = 0, j = 0; struct policy_mgr_psoc_priv_obj *pm_ctx; bool sta_sap_scc_on_dfs_chan; @@ -2180,9 +2179,6 @@ QDF_STATUS policy_mgr_get_channel_list(struct wlan_objmgr_psoc *psoc, policy_mgr_debug("skip DFS ch from pcl for SAP/Go"); skip_dfs_channel = true; } - is_etsi13_srd_chan_allowed_in_mas_mode = - wlan_reg_is_etsi13_srd_chan_allowed_master_mode(pm_ctx-> - pdev); } /* Let's divide the list in 2.4 & 5 Ghz lists */ @@ -2195,11 +2191,6 @@ QDF_STATUS policy_mgr_get_channel_list(struct wlan_objmgr_psoc *psoc, channel_list[i])) continue; - if (!is_etsi13_srd_chan_allowed_in_mas_mode && - wlan_reg_is_etsi13_srd_chan_for_freq( - pm_ctx->pdev, channel_list[i])) - continue; - channel_list_5[chan_index_5++] = channel_list[i]; } else if (wlan_reg_is_6ghz_chan_freq(channel_list[i])) { /* Add to 5G list untill 6G conc support is enabled */ diff --git a/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/components/cmn_services/policy_mgr/src/wlan_policy_mgr_pcl.c b/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/components/cmn_services/policy_mgr/src/wlan_policy_mgr_pcl.c index 2c3eecfd967e..707a3a84a6f5 100755 --- a/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/components/cmn_services/policy_mgr/src/wlan_policy_mgr_pcl.c +++ b/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/components/cmn_services/policy_mgr/src/wlan_policy_mgr_pcl.c @@ -545,18 +545,12 @@ policy_mgr_modify_pcl_based_on_srd(struct wlan_objmgr_psoc *psoc, uint32_t pcl_list[NUM_CHANNELS]; uint8_t weight_list[NUM_CHANNELS]; struct policy_mgr_psoc_priv_obj *pm_ctx; - bool is_etsi13_srd_chan_allowed_in_mas_mode = true; pm_ctx = policy_mgr_get_context(psoc); if (!pm_ctx) { policy_mgr_err("Invalid Context"); return QDF_STATUS_E_FAILURE; } - is_etsi13_srd_chan_allowed_in_mas_mode = - wlan_reg_is_etsi13_srd_chan_allowed_master_mode(pm_ctx->pdev); - - if (is_etsi13_srd_chan_allowed_in_mas_mode) - return QDF_STATUS_SUCCESS; if (*pcl_len_org > NUM_CHANNELS) { policy_mgr_err("Invalid PCL List Length %d", *pcl_len_org); @@ -589,6 +583,7 @@ static QDF_STATUS policy_mgr_pcl_modification_for_sap( bool nol_modified_pcl = false; bool dfs_modified_pcl = false; bool modified_final_pcl = false; + bool srd_chan_enabled; if (policy_mgr_is_sap_mandatory_channel_set(psoc)) { status = policy_mgr_modify_sap_pcl_based_on_mandatory_channel( @@ -617,12 +612,18 @@ static QDF_STATUS policy_mgr_pcl_modification_for_sap( } dfs_modified_pcl = true; - status = policy_mgr_modify_pcl_based_on_srd - (psoc, pcl_channels, pcl_weight, len); - if (QDF_IS_STATUS_ERROR(status)) { - policy_mgr_err("failed to get srd modified pcl for SAP"); - return status; + wlan_mlme_get_srd_master_mode_for_vdev(psoc, QDF_SAP_MODE, + &srd_chan_enabled); + + if (!srd_chan_enabled) { + status = policy_mgr_modify_pcl_based_on_srd + (psoc, pcl_channels, pcl_weight, len); + if (QDF_IS_STATUS_ERROR(status)) { + policy_mgr_err("Failed to modify SRD in pcl for SAP"); + return status; + } } + modified_final_pcl = true; policy_mgr_debug(" %d %d %d %d", mandatory_modified_pcl, @@ -640,6 +641,7 @@ static QDF_STATUS policy_mgr_pcl_modification_for_p2p_go( { QDF_STATUS status = QDF_STATUS_E_FAILURE; struct policy_mgr_psoc_priv_obj *pm_ctx; + bool srd_chan_enabled; pm_ctx = policy_mgr_get_context(psoc); if (!pm_ctx) { @@ -654,12 +656,18 @@ static QDF_STATUS policy_mgr_pcl_modification_for_p2p_go( return status; } - status = policy_mgr_modify_pcl_based_on_srd - (psoc, pcl_channels, pcl_weight, len); - if (QDF_IS_STATUS_ERROR(status)) { - policy_mgr_err("failed to get srd modified pcl for P2P-GO"); - return status; + wlan_mlme_get_srd_master_mode_for_vdev(psoc, QDF_P2P_GO_MODE, + &srd_chan_enabled); + + if (!srd_chan_enabled) { + status = policy_mgr_modify_pcl_based_on_srd + (psoc, pcl_channels, pcl_weight, len); + if (QDF_IS_STATUS_ERROR(status)) { + policy_mgr_err("Failed to modify SRD in pcl for GO"); + return status; + } } + policy_mgr_dump_channel_list(*len, pcl_channels, pcl_weight); return QDF_STATUS_SUCCESS; diff --git a/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/components/mlme/core/src/wlan_mlme_main.c b/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/components/mlme/core/src/wlan_mlme_main.c index 627a761a455d..cfe89715c308 100755 --- a/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/components/mlme/core/src/wlan_mlme_main.c +++ b/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/components/mlme/core/src/wlan_mlme_main.c @@ -2392,8 +2392,8 @@ static void mlme_init_reg_cfg(struct wlan_objmgr_psoc *psoc, struct wlan_objmgr_pdev *pdev = NULL; reg->self_gen_frm_pwr = cfg_get(psoc, CFG_SELF_GEN_FRM_PWR); - reg->etsi13_srd_chan_in_master_mode = - cfg_get(psoc, CFG_ETSI13_SRD_CHAN_IN_MASTER_MODE); + reg->etsi_srd_chan_in_master_mode = + cfg_get(psoc, CFG_ETSI_SRD_CHAN_IN_MASTER_MODE); reg->restart_beaconing_on_ch_avoid = cfg_get(psoc, CFG_RESTART_BEACONING_ON_CH_AVOID); reg->indoor_channel_support = cfg_get(psoc, CFG_INDOOR_CHANNEL_SUPPORT); @@ -2405,6 +2405,8 @@ static void mlme_init_reg_cfg(struct wlan_objmgr_psoc *psoc, reg->ignore_fw_reg_offload_ind = cfg_get( psoc, CFG_IGNORE_FW_REG_OFFLOAD_IND); + reg->retain_nol_across_regdmn_update = + cfg_get(psoc, CFG_RETAIN_NOL_ACROSS_REG_DOMAIN); qdf_uint8_array_parse(cfg_default(CFG_VALID_CHANNEL_LIST), channel_list, @@ -2412,6 +2414,9 @@ static void mlme_init_reg_cfg(struct wlan_objmgr_psoc *psoc, &valid_channel_list_num); reg->valid_channel_list_num = (uint8_t)valid_channel_list_num; + reg->enable_nan_on_indoor_channels = + cfg_get(psoc, CFG_INDOOR_CHANNEL_SUPPORT_FOR_NAN); + pdev = wlan_objmgr_get_pdev_by_id(psoc, 0, WLAN_MLME_NB_ID); if (!pdev) { mlme_legacy_err("null pdev"); diff --git a/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_reg.h b/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_reg.h index 7f435eda8df1..4da66ab7aa7f 100755 --- a/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_reg.h +++ b/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_reg.h @@ -73,14 +73,20 @@ /* * - * etsi13_srd_chan_in_master_mode - Enable/disable ETSI SRD channels in + * etsi_srd_chan_in_master_mode - Enable/disable ETSI SRD channels in * master mode PCL and ACS functionality * @Min: 0 - * @Max: 1 - * @Default: 0 + * @Max: 0xFF + * @Default: 6 * - * etsi13_srd_chan_in_master_mode is to enable/disable ETSI SRD channels in + * etsi_srd_chan_in_master_mode is to enable/disable ETSI SRD channels in * master mode PCL and ACS functionality + * Bit map for enabling the SRD mode in various modes are as follows:- + * BIT 0:- Enable/Disable SRD channels for SAP. + * BIT 1:- Enable/Disable SRD channels for P2P-GO. + * BIT 2:- Enable/Disable SRD channels for NAN. + * Rest of the bits are currently reserved for future SRD channel support for + * other vdevs. * * Related: None * @@ -90,11 +96,37 @@ * * */ -#define CFG_ETSI13_SRD_CHAN_IN_MASTER_MODE CFG_INI_BOOL( \ +#define CFG_ETSI_SRD_CHAN_IN_MASTER_MODE CFG_INI_UINT( \ "etsi13_srd_chan_in_master_mode", \ 0, \ + 0xff, \ + 6, \ + CFG_VALUE_OR_DEFAULT, \ "enable/disable ETSI SRD channels in master mode") +/* + * + * enable_nan_indoor_channel - Enable Indoor channels for NAN + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to support to indoor channels for NAN interface + * Customer can config this item to enable/disable NAN in indoor channel + * + * Related: None + * + * Supported Feature: NAN + * + * Usage: External + * + * + */ +#define CFG_INDOOR_CHANNEL_SUPPORT_FOR_NAN CFG_INI_BOOL( \ + "enable_nan_indoor_channel", \ + 0, \ + "enable/disable indoor channels for NAN") + #ifdef SAP_AVOID_ACS_FREQ_LIST #define SAP_AVOID_ACS_FREQ_LIST_DEFAULT "" @@ -297,17 +329,42 @@ 0, \ "Enable Pending list req") +/* + * + * retain_nol_across_regdmn - Retain NOL across reg domain + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to set if NOL needs to be retained + * on the reg domain change. + * + * Related: None + * + * Supported Feature: SAP + * + * Usage: External + * + * + */ +#define CFG_RETAIN_NOL_ACROSS_REG_DOMAIN CFG_INI_BOOL( \ + "retain_nol_across_regdmn", \ + 1, \ + "Retain NOL even if the regdomain changes") + #define CFG_REG_ALL \ CFG(CFG_SELF_GEN_FRM_PWR) \ CFG(CFG_ENABLE_PENDING_CHAN_LIST_REQ) \ CFG(CFG_ENABLE_11D_IN_WORLD_MODE) \ - CFG(CFG_ETSI13_SRD_CHAN_IN_MASTER_MODE) \ + CFG(CFG_ETSI_SRD_CHAN_IN_MASTER_MODE) \ + CFG(CFG_INDOOR_CHANNEL_SUPPORT_FOR_NAN) \ CFG(CFG_RESTART_BEACONING_ON_CH_AVOID) \ CFG(CFG_INDOOR_CHANNEL_SUPPORT) \ CFG(CFG_SCAN_11D_INTERVAL) \ CFG(CFG_VALID_CHANNEL_LIST) \ CFG(CFG_COUNTRY_CODE) \ CFG(CFG_IGNORE_FW_REG_OFFLOAD_IND) \ + CFG(CFG_RETAIN_NOL_ACROSS_REG_DOMAIN) \ CFG_SAP_AVOID_ACS_FREQ_LIST_ALL #endif /* CFG_MLME_REG_H__ */ diff --git a/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/components/mlme/dispatcher/inc/wlan_mlme_api.h b/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/components/mlme/dispatcher/inc/wlan_mlme_api.h index 4ddc898898c8..f3f72335646d 100755 --- a/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/components/mlme/dispatcher/inc/wlan_mlme_api.h +++ b/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/components/mlme/dispatcher/inc/wlan_mlme_api.h @@ -1903,6 +1903,30 @@ QDF_STATUS wlan_mlme_get_vht_tx_mcs_2x2(struct wlan_objmgr_psoc *psoc, QDF_STATUS wlan_mlme_get_vht20_mcs9(struct wlan_objmgr_psoc *psoc, bool *value); +/** + * wlan_mlme_get_srd_master_mode_for_vdev - Get SRD master mode for vdev + * @psoc: pointer to psoc object + * @vdev_opmode: vdev operating mode + * @value: pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +wlan_mlme_get_srd_master_mode_for_vdev(struct wlan_objmgr_psoc *psoc, + enum QDF_OPMODE vdev_opmode, + bool *value); + +/** + * wlan_mlme_get_indoor_support_for_nan - Get indoor channel support for NAN + * @psoc: pointer to psoc object + * @value: pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +wlan_mlme_get_indoor_support_for_nan(struct wlan_objmgr_psoc *psoc, + bool *value); + /** * wlan_mlme_get_vht_enable2x2() - Enables/disables VHT Tx/Rx MCS values for 2x2 * @psoc: psoc context diff --git a/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/components/mlme/dispatcher/inc/wlan_mlme_public_struct.h b/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/components/mlme/dispatcher/inc/wlan_mlme_public_struct.h index 1d5f49caf06e..b07bd6aaec0d 100755 --- a/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/components/mlme/dispatcher/inc/wlan_mlme_public_struct.h +++ b/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/components/mlme/dispatcher/inc/wlan_mlme_public_struct.h @@ -2211,11 +2211,23 @@ struct wlan_mlme_mwc { }; #endif +/** + * enum mlme_reg_srd_master_modes - Bitmap of SRD master modes supported + * @MLME_SRD_MASTER_MODE_SAP: SRD master mode for SAP + * @MLME_SRD_MASTER_MODE_P2P_GO: SRD master mode for P2P-GO + * @MLME_SRD_MASTER_MODE_NAN: SRD master mode for NAN + */ +enum mlme_reg_srd_master_modes { + MLME_SRD_MASTER_MODE_SAP = 1, + MLME_SRD_MASTER_MODE_P2P_GO = 2, + MLME_SRD_MASTER_MODE_NAN = 4, +}; + /** * struct wlan_mlme_reg - REG related configs * @self_gen_frm_pwr: self-generated frame power in tx chain mask * for CCK rates - * @etsi13_srd_chan_in_master_mode: etsi13 srd chan in master mode + * @etsi_srd_chan_in_master_mode: etsi srd chan in master mode * @restart_beaconing_on_ch_avoid: restart beaconing on ch avoid * @indoor_channel_support: indoor channel support * @scan_11d_interval: scan 11d interval @@ -2230,10 +2242,12 @@ struct wlan_mlme_mwc { * @ignore_fw_reg_offload_ind: Ignore fw regulatory offload indication * @enable_pending_chan_list_req: enables/disables scan channel * list command to FW till the current scan is complete. + * @retain_nol_across_regdmn_update: Retain the NOL list across the regdomain. + * @enable_nan_on_indoor_channels: Enable nan on Indoor channels */ struct wlan_mlme_reg { uint32_t self_gen_frm_pwr; - bool etsi13_srd_chan_in_master_mode; + uint8_t etsi_srd_chan_in_master_mode; enum restart_beaconing_on_ch_avoid_rule restart_beaconing_on_ch_avoid; bool indoor_channel_support; @@ -2249,6 +2263,8 @@ struct wlan_mlme_reg { #endif bool ignore_fw_reg_offload_ind; bool enable_pending_chan_list_req; + bool retain_nol_across_regdmn_update; + bool enable_nan_on_indoor_channels; }; /** diff --git a/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/components/mlme/dispatcher/inc/wlan_mlme_ucfg_api.h b/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/components/mlme/dispatcher/inc/wlan_mlme_ucfg_api.h index 94cb53f7bf07..155cfc94f031 100755 --- a/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/components/mlme/dispatcher/inc/wlan_mlme_ucfg_api.h +++ b/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/components/mlme/dispatcher/inc/wlan_mlme_ucfg_api.h @@ -3750,7 +3750,7 @@ ucfg_mlme_get_mws_coex_scc_channel_avoid_delay(struct wlan_objmgr_psoc *psoc, #endif /** - * ucfg_mlme_get_etsi13_srd_chan_in_master_mode - get etsi13 srd chan + * ucfg_mlme_get_etsi_srd_chan_in_master_mode - get etsi srd chan * in master mode * @psoc: pointer to psoc object * @value: pointer to the value which will be filled for the caller @@ -3758,8 +3758,21 @@ ucfg_mlme_get_mws_coex_scc_channel_avoid_delay(struct wlan_objmgr_psoc *psoc, * Return: QDF Status */ QDF_STATUS -ucfg_mlme_get_etsi13_srd_chan_in_master_mode(struct wlan_objmgr_psoc *psoc, - bool *value); +ucfg_mlme_get_etsi_srd_chan_in_master_mode(struct wlan_objmgr_psoc *psoc, + uint8_t *value); + +/** + * ucfg_mlme_get_srd_master_mode_for_vdev() - Get SRD master mode for vdev + * @psoc: pointer to psoc object + * @vdev_opmode: vdev opmode + * @value: pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_get_srd_master_mode_for_vdev(struct wlan_objmgr_psoc *psoc, + enum QDF_OPMODE vdev_opmode, + bool *value); #ifdef SAP_AVOID_ACS_FREQ_LIST /** @@ -3830,6 +3843,17 @@ QDF_STATUS ucfg_mlme_get_scan_11d_interval(struct wlan_objmgr_psoc *psoc, uint32_t *value); +/** + * ucfg_mlme_get_nol_across_regdmn() - get scan 11d interval + * @psoc: pointer to psoc object + * @value: Pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ + +QDF_STATUS +ucfg_mlme_get_nol_across_regdmn(struct wlan_objmgr_psoc *psoc, bool *value); + /** * ucfg_mlme_get_valid_channel_freq_list() - get valid channel * list diff --git a/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/components/mlme/dispatcher/src/wlan_mlme_api.c b/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/components/mlme/dispatcher/src/wlan_mlme_api.c index 9b2bb0156f5c..4544c5f501cd 100755 --- a/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/components/mlme/dispatcher/src/wlan_mlme_api.c +++ b/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/components/mlme/dispatcher/src/wlan_mlme_api.c @@ -2971,6 +2971,59 @@ wlan_mlme_get_vht20_mcs9(struct wlan_objmgr_psoc *psoc, bool *value) return QDF_STATUS_SUCCESS; } +QDF_STATUS +wlan_mlme_get_indoor_support_for_nan(struct wlan_objmgr_psoc *psoc, + bool *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *value = false; + mlme_legacy_err("Failed to get MLME Obj"); + return QDF_STATUS_E_INVAL; + } + + *value = mlme_obj->cfg.reg.enable_nan_on_indoor_channels; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_get_srd_master_mode_for_vdev(struct wlan_objmgr_psoc *psoc, + enum QDF_OPMODE vdev_opmode, + bool *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *value = false; + mlme_legacy_err("Failed to get MLME Obj"); + return QDF_STATUS_E_INVAL; + } + + switch (vdev_opmode) { + case QDF_SAP_MODE: + *value = mlme_obj->cfg.reg.etsi_srd_chan_in_master_mode & + MLME_SRD_MASTER_MODE_SAP; + break; + case QDF_P2P_GO_MODE: + *value = mlme_obj->cfg.reg.etsi_srd_chan_in_master_mode & + MLME_SRD_MASTER_MODE_P2P_GO; + break; + case QDF_NAN_DISC_MODE: + *value = mlme_obj->cfg.reg.etsi_srd_chan_in_master_mode & + MLME_SRD_MASTER_MODE_NAN; + break; + default: + mlme_legacy_err("Unexpected opmode %d", vdev_opmode); + *value = false; + } + + return QDF_STATUS_SUCCESS; +} + QDF_STATUS wlan_mlme_get_vht_enable2x2(struct wlan_objmgr_psoc *psoc, bool *value) { diff --git a/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/components/mlme/dispatcher/src/wlan_mlme_ucfg_api.c b/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/components/mlme/dispatcher/src/wlan_mlme_ucfg_api.c index 476989a420d6..cddde86da071 100755 --- a/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/components/mlme/dispatcher/src/wlan_mlme_ucfg_api.c +++ b/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/components/mlme/dispatcher/src/wlan_mlme_ucfg_api.c @@ -1537,23 +1537,31 @@ ucfg_mlme_get_mws_coex_scc_channel_avoid_delay(struct wlan_objmgr_psoc *psoc, #endif QDF_STATUS -ucfg_mlme_get_etsi13_srd_chan_in_master_mode(struct wlan_objmgr_psoc *psoc, - bool *value) +ucfg_mlme_get_etsi_srd_chan_in_master_mode(struct wlan_objmgr_psoc *psoc, + uint8_t *value) { struct wlan_mlme_psoc_ext_obj *mlme_obj; mlme_obj = mlme_get_psoc_ext_obj(psoc); if (!mlme_obj) { - *value = cfg_default(CFG_ETSI13_SRD_CHAN_IN_MASTER_MODE); + *value = cfg_default(CFG_ETSI_SRD_CHAN_IN_MASTER_MODE); mlme_legacy_err("Failed to get MLME Obj"); return QDF_STATUS_E_INVAL; } - *value = mlme_obj->cfg.reg.etsi13_srd_chan_in_master_mode; + *value = mlme_obj->cfg.reg.etsi_srd_chan_in_master_mode; return QDF_STATUS_SUCCESS; } +QDF_STATUS +ucfg_mlme_get_srd_master_mode_for_vdev(struct wlan_objmgr_psoc *psoc, + enum QDF_OPMODE vdev_opmode, + bool *value) +{ + return wlan_mlme_get_srd_master_mode_for_vdev(psoc, vdev_opmode, value); +} + #ifdef SAP_AVOID_ACS_FREQ_LIST QDF_STATUS ucfg_mlme_get_acs_avoid_freq_list(struct wlan_objmgr_psoc *psoc, @@ -1653,6 +1661,22 @@ ucfg_mlme_get_scan_11d_interval(struct wlan_objmgr_psoc *psoc, return QDF_STATUS_SUCCESS; } +QDF_STATUS +ucfg_mlme_get_nol_across_regdmn(struct wlan_objmgr_psoc *psoc, bool *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *value = cfg_default(CFG_RETAIN_NOL_ACROSS_REG_DOMAIN); + mlme_legacy_err("Failed to get MLME Obj"); + return QDF_STATUS_E_INVAL; + } + + *value = mlme_obj->cfg.reg.retain_nol_across_regdmn_update; + return QDF_STATUS_SUCCESS; +} + QDF_STATUS ucfg_mlme_get_valid_channel_freq_list(struct wlan_objmgr_psoc *psoc, uint32_t *channel_list, diff --git a/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/components/nan/core/inc/wlan_nan_api.h b/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/components/nan/core/inc/wlan_nan_api.h index d7d84eeb9294..9cba0fffd401 100755 --- a/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/components/nan/core/inc/wlan_nan_api.h +++ b/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/components/nan/core/inc/wlan_nan_api.h @@ -207,6 +207,18 @@ bool wlan_nan_get_sap_conc_support(struct wlan_objmgr_psoc *psoc); * Return: Cleanup NAN state upon NAN disable */ QDF_STATUS nan_disable_cleanup(struct wlan_objmgr_psoc *psoc); + +/** + * wlan_is_nan_allowed_on_freq() - Check if NAN is allowed on given freq + * @pdev: pdev context + * @freq: Frequency to be checked + * + * Check if NAN/NDP can be enabled on given frequency. + * + * Return: True if NAN is allowed on the given frequency + */ +bool wlan_is_nan_allowed_on_freq(struct wlan_objmgr_pdev *pdev, uint32_t freq); + #else /* WLAN_FEATURE_NAN */ static inline QDF_STATUS nan_init(void) { @@ -252,5 +264,11 @@ QDF_STATUS nan_disable_cleanup(struct wlan_objmgr_psoc *psoc) { return QDF_STATUS_E_FAILURE; } + +static inline +bool wlan_is_nan_allowed_on_freq(struct wlan_objmgr_pdev *pdev, uint32_t freq) +{ + return false; +} #endif /* WLAN_FEATURE_NAN */ #endif /* _WLAN_NAN_API_H_ */ diff --git a/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/components/nan/core/src/nan_api.c b/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/components/nan/core/src/nan_api.c index 769c4722b02e..64c3bd3aaaf5 100755 --- a/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/components/nan/core/src/nan_api.c +++ b/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/components/nan/core/src/nan_api.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2021 The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the @@ -30,6 +30,7 @@ #include "wlan_objmgr_pdev_obj.h" #include "wlan_objmgr_vdev_obj.h" #include "nan_ucfg_api.h" +#include static QDF_STATUS nan_psoc_obj_created_notification( struct wlan_objmgr_psoc *psoc, void *arg_list) @@ -414,3 +415,24 @@ QDF_STATUS nan_psoc_disable(struct wlan_objmgr_psoc *psoc) return QDF_STATUS_SUCCESS; } + +bool wlan_is_nan_allowed_on_freq(struct wlan_objmgr_pdev *pdev, uint32_t freq) +{ + bool nan_allowed = true; + + /* Check for SRD channels */ + if (wlan_reg_is_etsi13_srd_chan_for_freq(pdev, freq)) + wlan_mlme_get_srd_master_mode_for_vdev(wlan_pdev_get_psoc(pdev), + QDF_NAN_DISC_MODE, + &nan_allowed); + + /* Check for Indoor channels */ + if (wlan_reg_is_freq_indoor(pdev, freq)) + wlan_mlme_get_indoor_support_for_nan(wlan_pdev_get_psoc(pdev), + &nan_allowed); + /* Check for dfs only if channel is not indoor */ + else if (wlan_reg_is_dfs_for_freq(pdev, freq)) + nan_allowed = false; + + return nan_allowed; +} diff --git a/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/components/nan/dispatcher/inc/nan_ucfg_api.h b/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/components/nan/dispatcher/inc/nan_ucfg_api.h index 23317241807b..4504b592acce 100755 --- a/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/components/nan/dispatcher/inc/nan_ucfg_api.h +++ b/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/components/nan/dispatcher/inc/nan_ucfg_api.h @@ -455,6 +455,19 @@ bool ucfg_is_nan_vdev(struct wlan_objmgr_vdev *vdev); * Return: QDF_STATUS */ QDF_STATUS ucfg_nan_disable_ind_to_userspace(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_is_nan_allowed_on_freq() - Check if NAN is allowed on given freq + * @pdev: pdev context + * @freq: Frequency to be checked + * + * Check if NAN/NDP can be enabled on given frequency. + * Validate SRD channels based on the ini and reg domain. Assume rest of the + * channels support NAN/NDP for now. + * + * Return: True if NAN is allowed on the given frequency + */ +bool ucfg_is_nan_allowed_on_freq(struct wlan_objmgr_pdev *pdev, uint32_t freq); #else /* WLAN_FEATURE_NAN */ static inline @@ -562,5 +575,11 @@ QDF_STATUS ucfg_nan_disable_ind_to_userspace(struct wlan_objmgr_psoc *psoc) { return QDF_STATUS_SUCCESS; } + +static inline +bool ucfg_is_nan_allowed_on_freq(struct wlan_objmgr_pdev *pdev, uint32_t freq) +{ + return false; +} #endif /* WLAN_FEATURE_NAN */ #endif /* _NAN_UCFG_API_H_ */ diff --git a/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/components/nan/dispatcher/src/nan_ucfg_api.c b/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/components/nan/dispatcher/src/nan_ucfg_api.c index 769784e702ef..5c150af68f73 100755 --- a/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/components/nan/dispatcher/src/nan_ucfg_api.c +++ b/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/components/nan/dispatcher/src/nan_ucfg_api.c @@ -32,6 +32,7 @@ #include "wlan_policy_mgr_api.h" #include "cfg_ucfg_api.h" #include "cfg_nan.h" +#include "wlan_mlme_api.h" struct wlan_objmgr_psoc; struct wlan_objmgr_vdev; @@ -1272,3 +1273,8 @@ QDF_STATUS ucfg_nan_disable_ind_to_userspace(struct wlan_objmgr_psoc *psoc) qdf_mem_free(disable_ind); return QDF_STATUS_SUCCESS; } + +bool ucfg_is_nan_allowed_on_freq(struct wlan_objmgr_pdev *pdev, uint32_t freq) +{ + return wlan_is_nan_allowed_on_freq(pdev, freq); +} diff --git a/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/components/tdls/core/src/wlan_tdls_peer.c b/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/components/tdls/core/src/wlan_tdls_peer.c index 104c39081b45..1107f8956b3e 100755 --- a/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/components/tdls/core/src/wlan_tdls_peer.c +++ b/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/components/tdls/core/src/wlan_tdls_peer.c @@ -477,7 +477,7 @@ void tdls_extract_peer_state_param(struct tdls_peer_update_state *peer_param, enum channel_state ch_state; struct wlan_objmgr_pdev *pdev; uint8_t chan_id; - enum band_info cur_band = BAND_ALL; + uint32_t cur_band; qdf_freq_t ch_freq; vdev_obj = peer->vdev_priv; @@ -513,7 +513,7 @@ void tdls_extract_peer_state_param(struct tdls_peer_update_state *peer_param, return; } - if (BAND_2G == cur_band) { + if (BIT(REG_BAND_2G) == cur_band) { tdls_err("sending the offchannel value as 0 as only 2g is supported"); peer_param->peer_cap.pref_off_channum = 0; peer_param->peer_cap.opclass_for_prefoffchan = 0; diff --git a/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/core/hdd/inc/wlan_hdd_regulatory.h b/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/core/hdd/inc/wlan_hdd_regulatory.h index 789231c80035..4ab1b717eb59 100755 --- a/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/core/hdd/inc/wlan_hdd_regulatory.h +++ b/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/core/hdd/inc/wlan_hdd_regulatory.h @@ -61,14 +61,24 @@ void hdd_send_wiphy_regd_sync_event(struct hdd_context *hdd_ctx); */ int hdd_reg_set_country(struct hdd_context *hdd_ctx, char *country_code); +/** + * hdd_reg_legacy_setband_to_reg_wifi_band_bitmap() - Convert the user space + * band input to a bitmap of band capabilities, with reg_wifi_band as the + * bit value + * @qca_setband: user space/setband value band input, can be 0, 1, or 2 + * + * Return: bitmap on top of reg_wifi_band of bands enabled + */ +uint32_t hdd_reg_legacy_setband_to_reg_wifi_band_bitmap(uint8_t qca_setband); + /** * hdd_reg_set_band() - helper function for setting the regulatory band * @hdd_ctx: the HDD context to set the band for - * @ui_band: the UI band to configure + * @band_bitmap: the band bitmap to configure * * Return: zero for success, non-zero error code for failure */ -int hdd_reg_set_band(struct net_device *dev, u8 ui_band); +int hdd_reg_set_band(struct net_device *dev, uint32_t band_bitmap); /** * hdd_update_indoor_channel() - enable/disable indoor channel diff --git a/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/core/hdd/src/wlan_hdd_cfg80211.c b/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/core/hdd/src/wlan_hdd_cfg80211.c index e086ac65d3ce..6c9d72c2324b 100755 --- a/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/core/hdd/src/wlan_hdd_cfg80211.c +++ b/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/core/hdd/src/wlan_hdd_cfg80211.c @@ -11512,6 +11512,26 @@ static int wlan_hdd_cfg80211_get_bus_size(struct wiphy *wiphy, return errno; } +const struct nla_policy setband_policy[QCA_WLAN_VENDOR_ATTR_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE] = {.type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_SETBAND_MASK] = {.type = NLA_U32}, +}; + +static uint32_t +wlan_vendor_bitmap_to_reg_wifi_band_bitmap(uint32_t vendor_bitmap) +{ + uint32_t reg_bitmap = 0; + + if (vendor_bitmap & QCA_SETBAND_2G) + reg_bitmap |= BIT(REG_BAND_2G); + if (vendor_bitmap & QCA_SETBAND_5G) + reg_bitmap |= BIT(REG_BAND_5G); + if (vendor_bitmap & QCA_SETBAND_6G) + reg_bitmap |= BIT(REG_BAND_6G); + + return reg_bitmap; +} + /** *__wlan_hdd_cfg80211_setband() - set band * @wiphy: Pointer to wireless phy @@ -11529,8 +11549,7 @@ static int __wlan_hdd_cfg80211_setband(struct wiphy *wiphy, struct net_device *dev = wdev->netdev; struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_MAX + 1]; int ret; - static const struct nla_policy policy[QCA_WLAN_VENDOR_ATTR_MAX + 1] - = {[QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE] = { .type = NLA_U32 } }; + uint32_t reg_wifi_band_bitmap = 0, band_val, band_mask; hdd_enter(); @@ -11539,18 +11558,28 @@ static int __wlan_hdd_cfg80211_setband(struct wiphy *wiphy, return ret; if (wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_MAX, - data, data_len, policy)) { + data, data_len, setband_policy)) { hdd_err("Invalid ATTR"); return -EINVAL; } - if (!tb[QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE]) { + if (tb[QCA_WLAN_VENDOR_ATTR_SETBAND_MASK]) { + band_mask = nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_SETBAND_MASK]); + reg_wifi_band_bitmap = + wlan_vendor_bitmap_to_reg_wifi_band_bitmap(band_mask); + } else if (tb[QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE]) { + band_val = nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE]); + reg_wifi_band_bitmap = + hdd_reg_legacy_setband_to_reg_wifi_band_bitmap( + band_val); + } + + if (!reg_wifi_band_bitmap) { hdd_err("attr SETBAND_VALUE failed"); return -EINVAL; } - ret = hdd_reg_set_band(dev, - nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE])); + ret = hdd_reg_set_band(dev, reg_wifi_band_bitmap); hdd_exit(); return ret; @@ -12180,6 +12209,108 @@ static int wlan_hdd_cfg80211_setband(struct wiphy *wiphy, return errno; } +static uint32_t +wlan_reg_wifi_band_bitmap_to_vendor_bitmap(uint32_t reg_wifi_band_bitmap) +{ + uint32_t vendor_mask = 0; + + if (reg_wifi_band_bitmap & BIT(REG_BAND_2G)) + vendor_mask |= QCA_SETBAND_2G; + if (reg_wifi_band_bitmap & BIT(REG_BAND_5G)) + vendor_mask |= QCA_SETBAND_5G; + if (reg_wifi_band_bitmap & BIT(REG_BAND_6G)) + vendor_mask |= QCA_SETBAND_6G; + + return vendor_mask; +} + +/** + *__wlan_hdd_cfg80211_getband() - get band + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Length of @data + * + * Return: 0 on success, negative errno on failure + */ +static int __wlan_hdd_cfg80211_getband(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct sk_buff *skb; + QDF_STATUS status = QDF_STATUS_SUCCESS; + int ret; + uint32_t reg_wifi_band_bitmap, vendor_band_mask; + + hdd_enter(); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + skb = cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, + sizeof(uint32_t) + + NLA_HDRLEN); + + if (!skb) { + hdd_err("cfg80211_vendor_event_alloc failed"); + return -ENOMEM; + } + + status = ucfg_reg_get_band(hdd_ctx->pdev, ®_wifi_band_bitmap); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("failed to get band"); + goto failure; + } + + vendor_band_mask = wlan_reg_wifi_band_bitmap_to_vendor_bitmap( + reg_wifi_band_bitmap); + + if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_SETBAND_MASK, + vendor_band_mask)) { + hdd_err("nla put failure"); + goto failure; + } + + cfg80211_vendor_cmd_reply(skb); + + hdd_exit(); + + return 0; + +failure: + kfree_skb(skb); + return -EINVAL; +} + +/** + * wlan_hdd_cfg80211_getband() - Wrapper to getband + * @wiphy: wiphy structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of @data + * + * Return: 0 on success; errno on failure + */ +static int wlan_hdd_cfg80211_getband(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_getband(wiphy, wdev, data, data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + /** * wlan_hdd_cfg80211_sar_convert_limit_set() - Convert limit set value * @nl80211_value: Vendor command attribute value @@ -12190,6 +12321,7 @@ static int wlan_hdd_cfg80211_setband(struct wiphy *wiphy, */ static int wlan_hdd_cfg80211_sar_convert_limit_set(u32 nl80211_value, u32 *wmi_value) + { int ret = 0; @@ -15137,6 +15269,14 @@ const struct wiphy_vendor_command hdd_wiphy_vendor_commands[] = { WIPHY_VENDOR_CMD_NEED_RUNNING, .doit = wlan_hdd_cfg80211_setband }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_GETBAND, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_getband, + }, { .info.vendor_id = QCA_NL80211_VENDOR_ID, .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_ROAMING, @@ -15442,6 +15582,7 @@ static void wlan_hdd_copy_dsrc_ch(char *ch_ptr, int ch_arr_len) qdf_mem_copy(ch_ptr, &hdd_channels_dot11p[0], ch_arr_len); } + static void wlan_hdd_get_num_srd_ch_and_len(struct hdd_config *hdd_cfg, int *num_ch, int *ch_len) { diff --git a/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/core/hdd/src/wlan_hdd_hostapd.c b/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/core/hdd/src/wlan_hdd_hostapd.c index c9b0b2452c4b..2287c612fdc8 100755 --- a/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/core/hdd/src/wlan_hdd_hostapd.c +++ b/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/core/hdd/src/wlan_hdd_hostapd.c @@ -6278,6 +6278,8 @@ static int __wlan_hdd_cfg80211_start_ap(struct wiphy *wiphy, struct cfg80211_chan_def new_chandef; struct cfg80211_chan_def *chandef; uint16_t sap_ch; + bool srd_channel_allowed; + enum QDF_OPMODE vdev_opmode; hdd_enter(); @@ -6382,9 +6384,15 @@ static int __wlan_hdd_cfg80211_start_ap(struct wiphy *wiphy, hdd_err("SAP not allowed on DFS channel if no dfs master capability!!"); return -EINVAL; } - if (!wlan_reg_is_etsi13_srd_chan_allowed_master_mode(hdd_ctx->pdev) && + + vdev_opmode = wlan_vdev_mlme_get_opmode(adapter->vdev); + ucfg_mlme_get_srd_master_mode_for_vdev(hdd_ctx->psoc, vdev_opmode, + &srd_channel_allowed); + + if (!srd_channel_allowed && wlan_reg_is_etsi13_srd_chan(hdd_ctx->pdev, channel)) { - hdd_err("SAP not allowed on SRD channel."); + hdd_err("vdev opmode %d not allowed on SRD channel.", + vdev_opmode); return -EINVAL; } if (cds_is_sub_20_mhz_enabled()) { diff --git a/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/core/hdd/src/wlan_hdd_ioctl.c b/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/core/hdd/src/wlan_hdd_ioctl.c index 51a9054f31d7..a166b56517c4 100755 --- a/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/core/hdd/src/wlan_hdd_ioctl.c +++ b/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/core/hdd/src/wlan_hdd_ioctl.c @@ -3382,6 +3382,7 @@ static int drv_cmd_set_band(struct hdd_adapter *adapter, { int err; uint8_t band; + uint32_t band_bitmap; /* * Parse the band value passed from userspace. The first 8 bytes @@ -3393,7 +3394,9 @@ static int drv_cmd_set_band(struct hdd_adapter *adapter, return err; } - return hdd_reg_set_band(adapter->dev, band); + band_bitmap = hdd_reg_legacy_setband_to_reg_wifi_band_bitmap(band); + + return hdd_reg_set_band(adapter->dev, band_bitmap); } static int drv_cmd_set_wmmps(struct hdd_adapter *adapter, diff --git a/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/core/hdd/src/wlan_hdd_regulatory.c b/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/core/hdd/src/wlan_hdd_regulatory.c index 40766a31a757..dda42bd132ef 100755 --- a/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/core/hdd/src/wlan_hdd_regulatory.c +++ b/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/core/hdd/src/wlan_hdd_regulatory.c @@ -212,7 +212,7 @@ static void reg_program_config_vars(struct hdd_context *hdd_ctx, uint32_t scan_11d_interval = 0; bool indoor_chan_enabled = false; uint32_t restart_beaconing = 0; - bool enable_srd_chan = false; + uint8_t enable_srd_chan; QDF_STATUS status; bool country_priority = 0; bool value = false; @@ -232,6 +232,9 @@ static void reg_program_config_vars(struct hdd_context *hdd_ctx, hdd_err("Invalid 11d_enable flag"); config_vars->enable_11d_support = value; + ucfg_mlme_get_nol_across_regdmn(hdd_ctx->psoc, &value); + config_vars->retain_nol_across_regdmn_update = value; + ucfg_mlme_get_scan_11d_interval(hdd_ctx->psoc, &scan_11d_interval); config_vars->scan_11d_interval = scan_11d_interval; @@ -255,8 +258,8 @@ static void reg_program_config_vars(struct hdd_context *hdd_ctx, &restart_beaconing); config_vars->restart_beaconing = restart_beaconing; - ucfg_mlme_get_etsi13_srd_chan_in_master_mode(hdd_ctx->psoc, - &enable_srd_chan); + ucfg_mlme_get_etsi_srd_chan_in_master_mode(hdd_ctx->psoc, + &enable_srd_chan); config_vars->enable_srd_chan_in_master_mode = enable_srd_chan; ucfg_mlme_get_11d_in_world_mode(hdd_ctx->psoc, @@ -746,92 +749,60 @@ int hdd_reg_set_country(struct hdd_context *hdd_ctx, char *country_code) return qdf_status_to_os_return(status); } -int hdd_reg_set_band(struct net_device *dev, u8 ui_band) +uint32_t hdd_reg_legacy_setband_to_reg_wifi_band_bitmap(uint8_t qca_setband) { - struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); - mac_handle_t mac_handle; - enum band_info band; - QDF_STATUS status; - struct hdd_context *hdd_ctx; - enum band_info current_band; - enum band_info connected_band; + uint32_t band_bitmap = 0; - hdd_ctx = WLAN_HDD_GET_CTX(adapter); - - switch (ui_band) { - case WLAN_HDD_UI_BAND_AUTO: - band = BAND_ALL; + switch (qca_setband) { + case QCA_SETBAND_AUTO: + band_bitmap |= (BIT(REG_BAND_2G) | BIT(REG_BAND_5G)); break; - case WLAN_HDD_UI_BAND_5_GHZ: - band = BAND_5G; + case QCA_SETBAND_5G: + band_bitmap |= BIT(REG_BAND_5G); break; - case WLAN_HDD_UI_BAND_2_4_GHZ: - band = BAND_2G; + case QCA_SETBAND_2G: + band_bitmap |= BIT(REG_BAND_2G); break; default: - hdd_err("Invalid band value %u", ui_band); + hdd_err("Invalid band value %u", qca_setband); + return 0; + } + + return band_bitmap; +} + +int hdd_reg_set_band(struct net_device *dev, uint32_t band_bitmap) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx; + uint32_t current_band; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + if (!band_bitmap) { + hdd_err("Can't disable all bands"); return -EINVAL; } - hdd_debug("change band to %u", band); + hdd_debug("change band to %u", band_bitmap); - if (ucfg_reg_get_curr_band(hdd_ctx->pdev, ¤t_band) != + if (ucfg_reg_get_band(hdd_ctx->pdev, ¤t_band) != QDF_STATUS_SUCCESS) { hdd_debug("Failed to get current band config"); return -EIO; } - if (current_band == band) + if (current_band == band_bitmap) { + hdd_debug("band is the same so not updating"); return 0; - - hdd_ctx->curr_band = band; - - /* Change band request received. - * Abort pending scan requests, flush the existing scan results, - * and change the band capability - */ - hdd_debug("Current band value = %u, new setting %u ", - current_band, band); - - mac_handle = hdd_ctx->mac_handle; - hdd_for_each_adapter(hdd_ctx, adapter) { - wlan_abort_scan(hdd_ctx->pdev, INVAL_PDEV_ID, - adapter->vdev_id, INVALID_SCAN_ID, false); - connected_band = hdd_conn_get_connected_band( - WLAN_HDD_GET_STATION_CTX_PTR(adapter)); - - /* Handling is done only for STA and P2P */ - if (band != BAND_ALL && - ((adapter->device_mode == QDF_STA_MODE) || - (adapter->device_mode == QDF_P2P_CLIENT_MODE)) && - (hdd_conn_is_connected( - WLAN_HDD_GET_STATION_CTX_PTR(adapter))) - && (connected_band != band)) { - status = QDF_STATUS_SUCCESS; - - /* STA already connected on current - * band, So issue disconnect first, - * then change the band - */ - - hdd_debug("STA (Device mode %s(%d)) connected in band %u, Changing band to %u, Issuing Disconnect", - qdf_opmode_str(adapter->device_mode), - adapter->device_mode, current_band, band); - - status = wlan_hdd_disconnect(adapter, - eCSR_DISCONNECT_REASON_UNSPECIFIED, - eSIR_MAC_OPER_CHANNEL_BAND_CHANGE); - if (status) { - hdd_err("Hdd disconnect failed, status: %d", - status); - return -EINVAL; - } - } - ucfg_scan_flush_results(hdd_ctx->pdev, NULL); } - if (QDF_IS_STATUS_ERROR(ucfg_reg_set_band(hdd_ctx->pdev, band))) { - hdd_err("Failed to set the band value to %u", band); + hdd_ctx->curr_band = wlan_reg_band_bitmap_to_band_info(band_bitmap); + + if (QDF_IS_STATUS_ERROR(ucfg_reg_set_band(hdd_ctx->pdev, + band_bitmap))) { + hdd_err("Failed to set the band bitmap value to %u", + band_bitmap); return -EINVAL; } diff --git a/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/core/hdd/src/wlan_hdd_tdls.c b/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/core/hdd/src/wlan_hdd_tdls.c index 4c2ed525cfd1..f4341236e486 100755 --- a/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/core/hdd/src/wlan_hdd_tdls.c +++ b/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/core/hdd/src/wlan_hdd_tdls.c @@ -879,7 +879,7 @@ void hdd_config_tdls_with_band_switch(struct hdd_context *hdd_ctx) { struct wlan_objmgr_vdev *tdls_obj_vdev; int offchmode; - enum band_info current_band; + uint32_t current_band; bool tdls_off_ch; if (!hdd_ctx) { @@ -887,7 +887,7 @@ void hdd_config_tdls_with_band_switch(struct hdd_context *hdd_ctx) return; } - if (ucfg_reg_get_curr_band(hdd_ctx->pdev, ¤t_band) != + if (ucfg_reg_get_band(hdd_ctx->pdev, ¤t_band) != QDF_STATUS_SUCCESS) { hdd_err("Failed to get current band config"); return; @@ -902,7 +902,8 @@ void hdd_config_tdls_with_band_switch(struct hdd_context *hdd_ctx) * If 2g or 5g is not supported. Disable tdls off channel only when * tdls off channel is enabled currently. */ - if (current_band == BAND_ALL) { + if ((current_band & BIT(REG_BAND_2G)) && + (current_band & BIT(REG_BAND_5G))) { if (cfg_tdls_get_off_channel_enable_orig( hdd_ctx->psoc, &tdls_off_ch) != QDF_STATUS_SUCCESS) { diff --git a/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/core/mac/inc/qwlan_version.h b/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/core/mac/inc/qwlan_version.h index 89589751ce93..191d916faff6 100755 --- a/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/core/mac/inc/qwlan_version.h +++ b/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/core/mac/inc/qwlan_version.h @@ -34,27 +34,27 @@ #define QWLAN_VERSION_PATCH 022 #if defined(CONFIG_LITHIUM) #if defined(QCA_WIFI_QCA6390) //Hastings -#define QWLAN_VERSION_EXTRA "Q-HS210304A" +#define QWLAN_VERSION_EXTRA "Q-HS210811A" #elif defined(QCA_WIFI_QCA6490) // Hastings Prime -#define QWLAN_VERSION_EXTRA "Q-HP210304A" +#define QWLAN_VERSION_EXTRA "Q-HP210811A" #else #define QWLAN_VERSION_EXTRA "Q-QCOM" #endif #else -#define QWLAN_VERSION_EXTRA "Q-HL210304A" +#define QWLAN_VERSION_EXTRA "Q-HL210811A" #endif #define QWLAN_VERSION_BUILD 3 #if defined(CONFIG_LITHIUM) #if defined(QCA_WIFI_QCA6390) //Hastings -#define QWLAN_VERSIONSTR "5.2.022.3Q-HS210304A" +#define QWLAN_VERSIONSTR "5.2.022.3Q-HS210811A" #elif defined(QCA_WIFI_QCA6490) // Hastings Prime -#define QWLAN_VERSIONSTR "5.2.022.3Q-HP210304A" +#define QWLAN_VERSIONSTR "5.2.022.3Q-HP210811A" #else #define QWLAN_VERSIONSTR "5.2.022.3Q-QCOM" #endif #else -#define QWLAN_VERSIONSTR "5.2.022.3Q-HL210304A" +#define QWLAN_VERSIONSTR "5.2.022.3Q-HL210811A" #endif #endif /* QWLAN_VERSION_H */ diff --git a/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/core/mac/inc/sir_api.h b/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/core/mac/inc/sir_api.h index 758864107301..bfd48e9cddf8 100755 --- a/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/core/mac/inc/sir_api.h +++ b/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/core/mac/inc/sir_api.h @@ -2538,6 +2538,7 @@ typedef struct sSirScanOffloadEvent { * @dfsSet: is dfs supported or not * @half_rate: is the channel operating at 10MHz * @quarter_rate: is the channel operating at 5MHz + * @nan_disabled: is NAN disabled on @freq */ typedef struct sSirUpdateChanParam { uint32_t freq; @@ -2545,6 +2546,7 @@ typedef struct sSirUpdateChanParam { bool dfsSet; bool half_rate; bool quarter_rate; + bool nan_disabled; } tSirUpdateChanParam, *tpSirUpdateChanParam; typedef struct sSirUpdateChan { diff --git a/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/core/sap/src/sap_fsm.c b/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/core/sap/src/sap_fsm.c index a67ec741d950..28d48143fb24 100755 --- a/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/core/sap/src/sap_fsm.c +++ b/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/core/sap/src/sap_fsm.c @@ -3294,6 +3294,8 @@ static QDF_STATUS sap_get_freq_list(struct sap_context *sap_ctx, struct acs_weight_range *range_list; bool freq_present_in_list = false; uint8_t i; + bool srd_chan_enabled; + enum QDF_OPMODE vdev_opmode; mac_ctx = sap_get_mac_context(); if (!mac_ctx) { @@ -3412,15 +3414,19 @@ static QDF_STATUS sap_get_freq_list(struct sap_context *sap_ctx, mac_ctx->mlme_cfg->acs.np_chan_weightage); freq_present_in_list = true; } - /* Dont scan ETSI13 SRD channels if the ETSI13 SRD channels - * are not enabled in master mode - */ - if (!wlan_reg_is_etsi13_srd_chan_allowed_master_mode(mac_ctx-> - pdev) && - wlan_reg_is_etsi13_srd_chan_for_freq( - mac_ctx->pdev, - WLAN_REG_CH_TO_FREQ(loop_count))) + + vdev_opmode = wlan_vdev_mlme_get_opmode(sap_ctx->vdev); + wlan_mlme_get_srd_master_mode_for_vdev(mac_ctx->psoc, + vdev_opmode, + &srd_chan_enabled); + + if (!srd_chan_enabled && + wlan_reg_is_etsi13_srd_chan_for_freq(mac_ctx->pdev, + WLAN_REG_CH_TO_FREQ(loop_count))) { + sap_debug("vdev opmode %d not allowed on SRD freq %d", + vdev_opmode, WLAN_REG_CH_TO_FREQ(loop_count)); continue; + } /* Check if the freq is present in range list */ for (i = 0; i < mac_ctx->mlme_cfg->acs.num_weight_range; i++) { diff --git a/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/core/sap/src/sap_module.c b/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/core/sap/src/sap_module.c index a0b3b6cb0e3d..283eedef30ef 100755 --- a/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/core/sap/src/sap_module.c +++ b/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/core/sap/src/sap_module.c @@ -2995,14 +2995,14 @@ qdf_freq_t wlansap_get_chan_band_restrict(struct sap_context *sap_ctx) return 0; } - if (ucfg_reg_get_curr_band(mac->pdev, &band) != QDF_STATUS_SUCCESS) { + if (ucfg_reg_get_band(mac->pdev, &band) != QDF_STATUS_SUCCESS) { sap_err("Failed to get current band config"); return 0; } sap_band = wlan_reg_freq_to_band(sap_ctx->chan_freq); sap_debug("SAP/Go current band: %d, pdev band capability: %d", sap_band, band); - if (sap_band == REG_BAND_5G && band == BAND_2G) { + if (sap_band == REG_BAND_5G && band == BIT(REG_BAND_2G)) { sap_ctx->chan_freq_before_switch_band = sap_ctx->chan_freq; sap_ctx->chan_width_before_switch_band = sap_ctx->ch_params.ch_width; @@ -3018,8 +3018,7 @@ qdf_freq_t wlansap_get_chan_band_restrict(struct sap_context *sap_ctx) sap_debug("set 40M when switch SAP to 2G"); restart_ch_width = CH_WIDTH_40MHZ; } - } else if (sap_band == REG_BAND_2G && - (band == BAND_ALL || band == BAND_5G)) { + } else if (sap_band == REG_BAND_2G && (band & BIT(REG_BAND_5G))) { if (sap_ctx->chan_freq_before_switch_band == 0) return 0; restart_freq = sap_ctx->chan_freq_before_switch_band; diff --git a/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/core/sme/src/common/sme_api.c b/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/core/sme/src/common/sme_api.c index bf17f248ce37..c73828ce3606 100755 --- a/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/core/sme/src/common/sme_api.c +++ b/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/core/sme/src/common/sme_api.c @@ -1784,6 +1784,7 @@ QDF_STATUS sme_set_ese_roam_scan_channel_list(mac_handle_t mac_handle, uint8_t newChannelList[CFG_VALID_CHANNEL_LIST_LEN * 5] = { 0 }; uint8_t i = 0, j = 0; enum band_info band = -1; + uint32_t band_bitmap; if (sessionId >= WLAN_MAX_VDEVS) { QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, @@ -1806,7 +1807,8 @@ QDF_STATUS sme_set_ese_roam_scan_channel_list(mac_handle_t mac_handle, curchnl_list_info->freq_list[i]); } } - ucfg_reg_get_band(mac->pdev, &band); + ucfg_reg_get_band(mac->pdev, &band_bitmap); + band = wlan_reg_band_bitmap_to_band_info(band_bitmap); status = csr_create_roam_scan_channel_list(mac, sessionId, chan_freq_list, numChannels, band); diff --git a/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/core/sme/src/csr/csr_api_roam.c b/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/core/sme/src/csr/csr_api_roam.c index 904257c784dd..95d431b6c20b 100755 --- a/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/core/sme/src/csr/csr_api_roam.c +++ b/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/core/sme/src/csr/csr_api_roam.c @@ -67,6 +67,7 @@ #include "wlan_scan_utils_api.h" #include "wlan_p2p_cfg_api.h" #include "cfg_nan_api.h" +#include "nan_ucfg_api.h" #include @@ -1547,11 +1548,12 @@ QDF_STATUS csr_update_channel_list(struct mac_context *mac) } } + if (!ucfg_is_nan_allowed_on_freq(mac->pdev, + pChanList->chanParam[num_channel].freq)) + pChanList->chanParam[num_channel].nan_disabled = + true; - if (CHANNEL_STATE_ENABLE == channel_state) - pChanList->chanParam[num_channel].dfsSet = - false; - else + if (CHANNEL_STATE_ENABLE != channel_state) pChanList->chanParam[num_channel].dfsSet = true; diff --git a/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/core/wma/src/wma_scan_roam.c b/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/core/wma/src/wma_scan_roam.c index 6e3aa319e5c4..723253f5af57 100755 --- a/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/core/wma/src/wma_scan_roam.c +++ b/drivers/net/wireless/qualcomm/wcn39xx/qcacld-3.0/core/wma/src/wma_scan_roam.c @@ -168,6 +168,9 @@ QDF_STATUS wma_update_channel_list(WMA_HANDLE handle, chan_p->dfs_set = 1; } + if (chan_list->chanParam[i].nan_disabled) + chan_p->nan_disabled = 1; + if (chan_p->mhz < WMA_2_4_GHZ_MAX_FREQ) { chan_p->phy_mode = MODE_11G; if (chan_list->vht_en && chan_list->vht_24_en) diff --git a/drivers/samsung/debug/Kconfig b/drivers/samsung/debug/Kconfig index 9999735ffbf2..b426c84bf4e1 100755 --- a/drivers/samsung/debug/Kconfig +++ b/drivers/samsung/debug/Kconfig @@ -82,6 +82,13 @@ config SEC_DEBUG_SCHED_LOG_PER_CPU help Samsung Scheduler Logging using per_cpu Feature for Debug use. +config SEC_DEBUG_SCHED_LOG_IRQ_V2 + bool "Samsung Scheduler IRQ Logging V2" + default n + depends on SEC_DEBUG_SCHED_LOG + help + Samsung Scheduler IRQ Logging V2. + config SEC_DEBUG_MSG_LOG bool "Message Log for ram dump debug (DEPRECATED)" default n diff --git a/drivers/samsung/debug/sec_debug.c b/drivers/samsung/debug/sec_debug.c index 0f91e8596b8e..04357a031882 100755 --- a/drivers/samsung/debug/sec_debug.c +++ b/drivers/samsung/debug/sec_debug.c @@ -392,6 +392,9 @@ void sec_debug_update_restart_reason(const char *cmd, const int in_panic, { "from_fastboot", PON_RESTART_REASON_NORMALBOOT, RESTART_REASON_NOT_HANDLE, NULL}, + { "disallow,fastboot", + PON_RESTART_REASON_NORMALBOOT, + RESTART_REASON_NOT_HANDLE, NULL}, #ifdef CONFIG_MUIC_SUPPORT_RUSTPROOF { "swsel", PON_RESTART_REASON_UNKNOWN, @@ -788,15 +791,17 @@ static int __init __sec_debug_dt_addr_init(void) return -ENODEV; } - watchdog_base = of_iomap(np, 0); - if (unlikely(!watchdog_base)) { - pr_err("unable to map watchdog_base offset\n"); - return -ENODEV; - } + if (of_device_is_available(np)) { + watchdog_base = of_iomap(np, 0); + if (unlikely(!watchdog_base)) { + pr_err("unable to map watchdog_base offset\n"); + return -ENODEV; + } - /* check upload_cause here */ - pr_emerg("watchdog_base addr : 0x%p(0x%llx)\n", watchdog_base, - (unsigned long long)virt_to_phys(watchdog_base)); + /* check upload_cause here */ + pr_emerg("watchdog_base addr : 0x%p(0x%llx)\n", watchdog_base, + (unsigned long long)virt_to_phys(watchdog_base)); + } #endif return 0; @@ -841,7 +846,7 @@ static int __init sec_debug_init(void) case ANDROID_DEBUG_LEVEL_MID: #endif -#if defined(CONFIG_SEC_A52Q_PROJECT) || defined(CONFIG_SEC_A72Q_PROJECT) +#if defined(CONFIG_ARCH_ATOLL) || defined(CONFIG_ARCH_SEC_SM7150) if (!force_upload) qcom_scm_disable_sdi(); #endif diff --git a/drivers/samsung/debug/sec_debug_partition.c b/drivers/samsung/debug/sec_debug_partition.c index 3b355b0a198c..249a1b7bd9c1 100755 --- a/drivers/samsung/debug/sec_debug_partition.c +++ b/drivers/samsung/debug/sec_debug_partition.c @@ -248,6 +248,7 @@ static void init_debug_partition(void) /*++ add here need init data ++*/ init_ap_health_data(); + init_lcd_debug_data(); /*-- add here need init data --*/ while (1) { diff --git a/drivers/samsung/debug/sec_debug_sched_log.c b/drivers/samsung/debug/sec_debug_sched_log.c index 6847c1332fee..6d9db573bee8 100755 --- a/drivers/samsung/debug/sec_debug_sched_log.c +++ b/drivers/samsung/debug/sec_debug_sched_log.c @@ -20,6 +20,8 @@ #include #include #include +#include +#include #include @@ -123,7 +125,7 @@ void sec_debug_task_sched_log(int cpu, bool preempt, sched_buf->prev_prio = prev->prio; } -void sec_debug_irq_sched_log(unsigned int irq, void *fn, +void sec_debug_softirq_sched_log(unsigned int irq, void *fn, char *name, unsigned int en) { struct irq_buf *irq_buf; @@ -148,11 +150,55 @@ void sec_debug_irq_sched_log(unsigned int irq, void *fn, irq_buf->time = cpu_clock(cpu); irq_buf->irq = irq; - irq_buf->fn = (void *)fn; + irq_buf->fn = fn; irq_buf->name = name; + irq_buf->context = &cpu; irq_buf->en = irqs_disabled(); irq_buf->preempt_count = preempt_count(); + irq_buf->pid = current->pid; + irq_buf->entry_exit = en; +} + +void sec_debug_irq_sched_log(unsigned int irq, void *desc_or_fn, + void *action_or_name, unsigned int en) +{ + struct irq_buf *irq_buf; + int cpu = smp_processor_id(); + int i; +#if defined(CONFIG_SEC_DEBUG_SCHED_LOG_IRQ_V2) + struct irq_desc *desc = (struct irq_desc *)desc_or_fn; + struct irqaction *action = (struct irqaction *)action_or_name; +#endif + +#if defined(CONFIG_SEC_DEBUG_SCHED_LOG_PER_CPU) + struct sec_debug_log *sec_dbg_log; + sec_dbg_log = &per_cpu(sec_debug_log_cpu, cpu); + if (unlikely(!sec_dbg_log)) + return; + + i = ++(sec_dbg_log->irq.idx) & (SCHED_LOG_MAX - 1); + irq_buf = &sec_dbg_log->irq.buf[i]; +#else + if (unlikely(!secdbg_log)) + return; + + i = ++(secdbg_log->irq[cpu].idx) & (SCHED_LOG_MAX - 1); + irq_buf = &secdbg_log->irq[cpu].buf[i]; +#endif + + irq_buf->time = cpu_clock(cpu); + irq_buf->irq = irq; +#if defined(CONFIG_SEC_DEBUG_SCHED_LOG_IRQ_V2) + irq_buf->fn = action->handler; + irq_buf->name = (char *)action->name; + irq_buf->hwirq = desc->irq_data.hwirq; +#else + irq_buf->fn = (void *)desc_or_fn; + irq_buf->name = (char *)action_or_name; irq_buf->context = &cpu; +#endif + irq_buf->en = irqs_disabled(); + irq_buf->preempt_count = preempt_count(); irq_buf->pid = current->pid; irq_buf->entry_exit = en; } diff --git a/drivers/samsung/debug/sec_debug_summary.c b/drivers/samsung/debug/sec_debug_summary.c index 9017f2a8193f..25471579a2fb 100755 --- a/drivers/samsung/debug/sec_debug_summary.c +++ b/drivers/samsung/debug/sec_debug_summary.c @@ -112,13 +112,12 @@ int sec_debug_summary_save_die_info(const char *str, struct pt_regs *regs) #ifndef CONFIG_SAMSUNG_PRODUCT_SHIP sec_delay_check = 0; #endif - if (!secdbg_apss) - return -ENOMEM; - - snprintf(secdbg_apss->excp.pc_sym, sizeof(secdbg_apss->excp.pc_sym), - "%pS", (void *)regs->PT_REGS_PC); - snprintf(secdbg_apss->excp.lr_sym, sizeof(secdbg_apss->excp.lr_sym), - "%pS", (void *)regs->PT_REGS_LR); + if (secdbg_apss) { + snprintf(secdbg_apss->excp.pc_sym, sizeof(secdbg_apss->excp.pc_sym), + "%pS", (void *)regs->PT_REGS_PC); + snprintf(secdbg_apss->excp.lr_sym, sizeof(secdbg_apss->excp.lr_sym), + "%pS", (void *)regs->PT_REGS_LR); + } __summary_save_dying_msg_for_user_reset_debug(str, (void *)regs->PT_REGS_PC, (void *)regs->PT_REGS_LR); @@ -131,16 +130,15 @@ int sec_debug_summary_save_panic_info(const char *str, unsigned long caller) #ifndef CONFIG_SAMSUNG_PRODUCT_SHIP sec_delay_check = 0; #endif - if (!secdbg_apss) - return -ENOMEM; - - snprintf(secdbg_apss->excp.panic_caller, - sizeof(secdbg_apss->excp.panic_caller), "%pS", (void *)caller); - snprintf(secdbg_apss->excp.panic_msg, - sizeof(secdbg_apss->excp.panic_msg), "%s", str); - snprintf(secdbg_apss->excp.thread, - sizeof(secdbg_apss->excp.thread), "%s:%d", current->comm, - task_pid_nr(current)); + if (secdbg_apss) { + snprintf(secdbg_apss->excp.panic_caller, + sizeof(secdbg_apss->excp.panic_caller), "%pS", (void *)(caller - ARCH_INSTR_SIZE)); + snprintf(secdbg_apss->excp.panic_msg, + sizeof(secdbg_apss->excp.panic_msg), "%s", str); + snprintf(secdbg_apss->excp.thread, + sizeof(secdbg_apss->excp.thread), "%s:%d", current->comm, + task_pid_nr(current)); + } __summary_save_dying_msg_for_user_reset_debug(str, (void *)(caller - ARCH_INSTR_SIZE), (void *)caller); diff --git a/drivers/samsung/debug/sec_log_buf.c b/drivers/samsung/debug/sec_log_buf.c index 0153e6bf39bd..c2fb136a519e 100755 --- a/drivers/samsung/debug/sec_log_buf.c +++ b/drivers/samsung/debug/sec_log_buf.c @@ -323,8 +323,9 @@ static int sec_log_store(struct notifier_block *nb, switch (action) { case SYS_RESTART: case SYS_POWER_OFF: - pr_info("%s, %s, %ptR(TZ:%02d)\n", - action == SYS_RESTART ? "reboot" : "power off", cmd, &local_tm, -sys_tz.tz_minuteswest / 60); + pr_info("%ptR(TZ:%02d), %s, %s\n", + &local_tm, -sys_tz.tz_minuteswest / 60, + action == SYS_RESTART ? "reboot" : "power off", cmd); write_debug_partition(debug_index_reset_klog, s_log_buf); break; } diff --git a/drivers/samsung/misc/sec_argos.c b/drivers/samsung/misc/sec_argos.c index 32a5a2e81f64..de1d01b538bb 100755 --- a/drivers/samsung/misc/sec_argos.c +++ b/drivers/samsung/misc/sec_argos.c @@ -585,10 +585,14 @@ static int argos_pm_qos_notify(struct notifier_block *nfb, prev_level = cnode->prev_level; - pr_debug("name:%s, speed:%ldMbps\n", cnode->desc, speed); - argos_blocked = cnode->argos_block; + if (cnode->tables[0].items[THRESHOLD] == 0) { + pr_debug("skip not used name:%s, speed:%ldMbps\n",\ + cnode->desc, speed); + goto out; + } + /* Find proper level */ for (level = 0; level < cnode->ntables; level++) { struct boost_table *t = &cnode->tables[level]; diff --git a/drivers/security/samsung/icdrv/oemflag.c b/drivers/security/samsung/icdrv/oemflag.c index 4a5596d0c184..8182b0913af6 100755 --- a/drivers/security/samsung/icdrv/oemflag.c +++ b/drivers/security/samsung/icdrv/oemflag.c @@ -39,24 +39,27 @@ int oem_flags_set(enum oemflag_id index) if (name > OEMFLAG_MIN_FLAG && name < OEMFLAG_NUM_OF_FLAG) { if (check_flags(name)) { pr_info("[oemflag]flag is already set. %u\n", name); - return 0; + return OEMFLAG_SUCCESS; } pr_info("[oemflag]set_fuse_name : %u\n", name); ret = set_tamper_fuse(name); - if (ret) + if (ret) { pr_err("set_tamper_fuse error: ret=%d\n", ret); + return OEMFLAG_FAIL; + } ret = get_tamper_fuse(name); - if (!ret) + if (!ret) { pr_err("get_tamper_fuse error: ret=%d\n", ret); + return OEMFLAG_FAIL; + } oem_flags_check[name] = 1; } else { pr_info("[oemflag]param name is wrong\n"); - ret = -EINVAL; + return -EINVAL; } - - return ret; + return OEMFLAG_SUCCESS; } int oem_flags_get(enum oemflag_id index) diff --git a/drivers/security/samsung/icdrv/oemflag.h b/drivers/security/samsung/icdrv/oemflag.h index c68988e7c56c..1c18f311a5b9 100755 --- a/drivers/security/samsung/icdrv/oemflag.h +++ b/drivers/security/samsung/icdrv/oemflag.h @@ -17,6 +17,9 @@ #ifndef __OEM_FLAG_H #define __OEM_FLAG_H +#define OEMFLAG_SUCCESS 0 +#define OEMFLAG_FAIL -1 + enum oemflag_id { OEMFLAG_NONE = 0, OEMFLAG_MIN_FLAG = 2, diff --git a/drivers/tty/serial/msm_geni_serial.c b/drivers/tty/serial/msm_geni_serial.c index 88ead1a3a0ef..e1f034b18c9d 100755 --- a/drivers/tty/serial/msm_geni_serial.c +++ b/drivers/tty/serial/msm_geni_serial.c @@ -1502,21 +1502,13 @@ static void start_rx_sequencer(struct uart_port *uport) spin_unlock_irqrestore(&uport->lock, flags); } -#if !defined(CONFIG_ARCH_ATOLL) - /* Start RX with the RFR_OPEN to keep RFR in always ready state */ - msm_geni_serial_enable_interrupts(uport); - geni_setup_s_cmd(uport->membase, UART_START_READ, geni_se_param); -#endif - if (port->xfer_mode == SE_DMA) geni_se_rx_dma_start(uport->membase, DMA_RX_BUF_SIZE, &port->rx_dma); -#if defined(CONFIG_ARCH_ATOLL) /* Start RX with the RFR_OPEN to keep RFR in always ready state */ geni_setup_s_cmd(uport->membase, UART_START_READ, geni_se_param); msm_geni_serial_enable_interrupts(uport); -#endif /* Ensure that the above writes go through */ mb(); diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index dba4f53a7fff..d7e56de19c58 100755 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -2739,10 +2739,14 @@ void __do_SAK(struct tty_struct *tty) struct task_struct *g, *p; struct pid *session; int i; + unsigned long flags; if (!tty) return; - session = tty->session; + + spin_lock_irqsave(&tty->ctrl_lock, flags); + session = get_pid(tty->session); + spin_unlock_irqrestore(&tty->ctrl_lock, flags); tty_ldisc_flush(tty); @@ -2774,6 +2778,7 @@ void __do_SAK(struct tty_struct *tty) task_unlock(p); } while_each_thread(g, p); read_unlock(&tasklist_lock); + put_pid(session); #endif } diff --git a/drivers/tty/tty_jobctrl.c b/drivers/tty/tty_jobctrl.c index 33dcd4eb92da..b71e61e79c5a 100755 --- a/drivers/tty/tty_jobctrl.c +++ b/drivers/tty/tty_jobctrl.c @@ -102,8 +102,8 @@ static void __proc_set_tty(struct tty_struct *tty) put_pid(tty->session); put_pid(tty->pgrp); tty->pgrp = get_pid(task_pgrp(current)); - spin_unlock_irqrestore(&tty->ctrl_lock, flags); tty->session = get_pid(task_session(current)); + spin_unlock_irqrestore(&tty->ctrl_lock, flags); if (current->signal->tty) { tty_debug(tty, "current tty %s not NULL!!\n", current->signal->tty->name); @@ -292,20 +292,23 @@ void disassociate_ctty(int on_exit) spin_lock_irq(¤t->sighand->siglock); put_pid(current->signal->tty_old_pgrp); current->signal->tty_old_pgrp = NULL; - tty = tty_kref_get(current->signal->tty); + spin_unlock_irq(¤t->sighand->siglock); + if (tty) { unsigned long flags; + + tty_lock(tty); spin_lock_irqsave(&tty->ctrl_lock, flags); put_pid(tty->session); put_pid(tty->pgrp); tty->session = NULL; tty->pgrp = NULL; spin_unlock_irqrestore(&tty->ctrl_lock, flags); + tty_unlock(tty); tty_kref_put(tty); } - spin_unlock_irq(¤t->sighand->siglock); /* Now clear signal->tty under the lock */ read_lock(&tasklist_lock); session_clear_tty(task_session(current)); @@ -476,14 +479,19 @@ static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t return -ENOTTY; if (retval) return retval; - if (!current->signal->tty || - (current->signal->tty != real_tty) || - (real_tty->session != task_session(current))) - return -ENOTTY; + if (get_user(pgrp_nr, p)) return -EFAULT; if (pgrp_nr < 0) return -EINVAL; + + spin_lock_irq(&real_tty->ctrl_lock); + if (!current->signal->tty || + (current->signal->tty != real_tty) || + (real_tty->session != task_session(current))) { + retval = -ENOTTY; + goto out_unlock_ctrl; + } rcu_read_lock(); pgrp = find_vpid(pgrp_nr); retval = -ESRCH; @@ -493,12 +501,12 @@ static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t if (session_of_pgrp(pgrp) != task_session(current)) goto out_unlock; retval = 0; - spin_lock_irq(&real_tty->ctrl_lock); put_pid(real_tty->pgrp); real_tty->pgrp = get_pid(pgrp); - spin_unlock_irq(&real_tty->ctrl_lock); out_unlock: rcu_read_unlock(); +out_unlock_ctrl: + spin_unlock_irq(&real_tty->ctrl_lock); return retval; } @@ -510,20 +518,30 @@ out_unlock: * * Obtain the session id of the tty. If there is no session * return an error. - * - * Locking: none. Reference to current->signal->tty is safe. */ static int tiocgsid(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p) { + unsigned long flags; + pid_t sid; + /* * (tty == real_tty) is a cheap way of * testing if the tty is NOT a master pty. */ if (tty == real_tty && current->signal->tty != real_tty) return -ENOTTY; + + spin_lock_irqsave(&real_tty->ctrl_lock, flags); if (!real_tty->session) - return -ENOTTY; - return put_user(pid_vnr(real_tty->session), p); + goto err; + sid = pid_vnr(real_tty->session); + spin_unlock_irqrestore(&real_tty->ctrl_lock, flags); + + return put_user(sid, p); + +err: + spin_unlock_irqrestore(&real_tty->ctrl_lock, flags); + return -ENOTTY; } /* diff --git a/drivers/usb/gadget/function/f_cdev.c b/drivers/usb/gadget/function/f_cdev.c index b0faafca4b1b..f22018f74e32 100755 --- a/drivers/usb/gadget/function/f_cdev.c +++ b/drivers/usb/gadget/function/f_cdev.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2013-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2011, 2013-2021, The Linux Foundation. All rights reserved. * Linux Foundation chooses to take subject only to the GPLv2 license terms, * and distributes only under these terms. * @@ -94,7 +94,7 @@ struct cserial { struct f_cdev { struct cdev fcdev_cdev; - struct device *dev; + struct device dev; unsigned int port_num; char name[sizeof(DEVICE_NAME) + 2]; int minor; @@ -953,13 +953,16 @@ static void cser_free_inst(struct usb_function_instance *fi) opts = container_of(fi, struct f_cdev_opts, func_inst); if (opts->port) { - device_destroy(fcdev_classp, MKDEV(major, opts->port->minor)); - cdev_del(&opts->port->fcdev_cdev); + cdev_device_del(&opts->port->fcdev_cdev, &opts->port->dev); + mutex_lock(&chardev_ida_lock); + ida_simple_remove(&chardev_ida, opts->port->minor); + mutex_unlock(&chardev_ida_lock); usb_cser_debugfs_exit(opts->port); + put_device(&opts->port->dev); } + usb_cser_chardev_deinit(); kfree(opts->func_name); - kfree(opts->port); kfree(opts); } @@ -1181,13 +1184,10 @@ int f_cdev_open(struct inode *inode, struct file *file) struct f_cdev *port; port = container_of(inode->i_cdev, struct f_cdev, fcdev_cdev); - if (!port) { - pr_err("Port is NULL.\n"); - return -EINVAL; - } - - if (port && port->port_open) { + get_device(&port->dev); + if (port->port_open) { pr_err("port is already opened.\n"); + put_device(&port->dev); return -EBUSY; } @@ -1197,6 +1197,7 @@ int f_cdev_open(struct inode *inode, struct file *file) port->is_connected); if (ret) { pr_debug("open interrupted.\n"); + put_device(&port->dev); return ret; } @@ -1216,16 +1217,12 @@ int f_cdev_release(struct inode *inode, struct file *file) struct f_cdev *port; port = file->private_data; - if (!port) { - pr_err("port is NULL.\n"); - return -EINVAL; - } - spin_lock_irqsave(&port->port_lock, flags); port->port_open = false; port->cbits_updated = false; spin_unlock_irqrestore(&port->port_lock, flags); pr_debug("port(%s)(%pK) is closed.\n", port->name, port); + put_device(&port->dev); return 0; } @@ -1830,11 +1827,17 @@ static void usb_cser_debugfs_exit(struct f_cdev *port) debugfs_remove_recursive(port->debugfs_root); } +static void cdev_device_release(struct device *dev) +{ + struct f_cdev *port = container_of(dev, struct f_cdev, dev); + + pr_debug("Free cdev port(%d)\n", port->port_num); + kfree(port); +} + static struct f_cdev *f_cdev_alloc(char *func_name, int portno) { int ret; - dev_t dev; - struct device *device; struct f_cdev *port; port = kzalloc(sizeof(struct f_cdev), GFP_KERNEL); @@ -1885,27 +1888,24 @@ static struct f_cdev *f_cdev_alloc(char *func_name, int portno) /* create char device */ cdev_init(&port->fcdev_cdev, &f_cdev_fops); - dev = MKDEV(major, port->minor); - ret = cdev_add(&port->fcdev_cdev, dev, 1); + device_initialize(&port->dev); + port->dev.class = fcdev_classp; + port->dev.parent = NULL; + port->dev.release = cdev_device_release; + port->dev.devt = MKDEV(major, port->minor); + dev_set_name(&port->dev, "%s", port->name); + ret = cdev_device_add(&port->fcdev_cdev, &port->dev); if (ret) { pr_err("Failed to add cdev for port(%s)\n", port->name); goto err_cdev_add; } - device = device_create(fcdev_classp, NULL, dev, NULL, port->name); - if (IS_ERR(device)) { - ret = PTR_ERR(device); - goto err_create_dev; - } - usb_cser_debugfs_init(port); pr_info("port_name:%s (%pK) portno:(%d)\n", port->name, port, port->port_num); return port; -err_create_dev: - cdev_del(&port->fcdev_cdev); err_cdev_add: destroy_workqueue(port->fcdev_wq); err_get_ida: diff --git a/drivers/usb/gadget/function/f_conn_gadget.c b/drivers/usb/gadget/function/f_conn_gadget.c index 9361a76a9873..3368f2d2cc0d 100755 --- a/drivers/usb/gadget/function/f_conn_gadget.c +++ b/drivers/usb/gadget/function/f_conn_gadget.c @@ -59,6 +59,7 @@ #include #include #include +#include /* platform specific definitions */ /* ex) #define __ANDROID__ */ @@ -124,6 +125,8 @@ struct conn_gadget_dev { /* flag variable that save flush call status * to check wakeup reason */ atomic_t flush; + + struct kref kref; }; static struct usb_interface_descriptor conn_gadget_interface_desc = { @@ -231,6 +234,7 @@ struct conn_gadget_instance { const char *name; }; +static void conn_gadget_cleanup(struct kref *kref); static inline struct conn_gadget_dev *func_to_conn_gadget(struct usb_function *f) { @@ -711,6 +715,11 @@ static int conn_gadget_open(struct inode *ip, struct file *fp) return -EBUSY; } + if (!kref_get_unless_zero(&_conn_gadget_dev->kref)) { + CONN_GADGET_ERR("already device removed\n"); + return -ENODEV; + } + fp->private_data = _conn_gadget_dev; /* clear the error latch */ @@ -757,6 +766,8 @@ static int conn_gadget_release(struct inode *ip, struct file *fp) atomic_set(&_conn_gadget_dev->flush, 0); conn_gadget_unlock(&_conn_gadget_dev->open_excl); + + kref_put(&_conn_gadget_dev->kref, conn_gadget_cleanup); return 0; } @@ -1245,6 +1256,8 @@ static int conn_gadget_setup(struct conn_gadget_instance *fi_conn_gadget) atomic_set(&dev->flush, 0); atomic_set(&dev->ep_out_excl, 0); + kref_init(&dev->kref); + INIT_LIST_HEAD(&dev->tx_idle); INIT_LIST_HEAD(&dev->rx_idle); INIT_LIST_HEAD(&dev->rx_busy); @@ -1294,7 +1307,7 @@ err_: return ret; } -static void conn_gadget_cleanup(void) +static void conn_gadget_cleanup(struct kref *kref) { printk(KERN_INFO "conn_gadget_cleanup\n"); @@ -1370,8 +1383,8 @@ static void conn_gadget_free_inst(struct usb_function_instance *fi) fi_conn_gadget = to_fi_conn_gadget(fi); kfree(fi_conn_gadget->name); - conn_gadget_cleanup(); kfree(fi_conn_gadget); + kref_put(&_conn_gadget_dev->kref, conn_gadget_cleanup); } struct usb_function_instance *alloc_inst_conn_gadget(void) diff --git a/firmware/tsp_stm/fts5cu56a_a52.bin b/firmware/tsp_stm/fts5cu56a_a52.bin index 106bf3ac36d7..74f9ffa8e4d9 100755 Binary files a/firmware/tsp_stm/fts5cu56a_a52.bin and b/firmware/tsp_stm/fts5cu56a_a52.bin differ diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index 5d1f63936dfe..17f6e8217b65 100755 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -2818,6 +2818,9 @@ static int f2fs_move_file_range(struct file *file_in, loff_t pos_in, if (IS_ENCRYPTED(src) || IS_ENCRYPTED(dst)) return -EOPNOTSUPP; + if (pos_out < 0 || pos_in < 0) + return -EINVAL; + if (src == dst) { if (pos_in == pos_out) return 0; diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index 0f6b40bcd07c..762137868823 100755 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -27,6 +28,11 @@ #include #include "internal.h" +#ifdef CONFIG_ZRAM_LRU_WRITEBACK +#include +#include "../../drivers/block/zram/zram_drv.h" +#endif + void task_mem(struct seq_file *m, struct mm_struct *mm) { unsigned long text, lib, swap, ptes, pmds, anon, file, shmem; @@ -531,6 +537,9 @@ struct mem_size_stats { unsigned long anonymous_thp; unsigned long shmem_thp; unsigned long swap; +#ifdef CONFIG_ZRAM_LRU_WRITEBACK + unsigned long writeback; +#endif unsigned long shared_hugetlb; unsigned long private_hugetlb; unsigned long first_vma_start; @@ -627,6 +636,10 @@ static void smaps_pte_entry(pte_t *pte, unsigned long addr, int mapcount; mss->swap += PAGE_SIZE; +#ifdef CONFIG_ZRAM_LRU_WRITEBACK + if (is_writeback_entry(swpent)) + mss->writeback += PAGE_SIZE; +#endif mapcount = swp_swapcount(swpent); if (mapcount >= 2) { u64 pss_delta = (u64)PAGE_SIZE << PSS_SHIFT; @@ -935,6 +948,9 @@ static int show_smap(struct seq_file *m, void *v, int is_pid) "Private_Hugetlb: %7lu kB\n" "Swap: %8lu kB\n" "SwapPss: %8lu kB\n" +#ifdef CONFIG_ZRAM_LRU_WRITEBACK + "Writeback: %8lu kB\n" +#endif "Locked: %8lu kB\n", mss->resident >> 10, (unsigned long)(mss->pss >> (10 + PSS_SHIFT)), @@ -951,6 +967,9 @@ static int show_smap(struct seq_file *m, void *v, int is_pid) mss->private_hugetlb >> 10, mss->swap >> 10, (unsigned long)(mss->swap_pss >> (10 + PSS_SHIFT)), +#ifdef CONFIG_ZRAM_LRU_WRITEBACK + mss->writeback >> 10, +#endif (unsigned long)(mss->pss_locked >> (10 + PSS_SHIFT))); if (!rollup_mode) { @@ -1703,6 +1722,18 @@ const struct file_operations proc_pagemap_operations = { }; #endif /* CONFIG_PROC_PAGE_MONITOR */ +#ifdef CONFIG_FREEZING +static inline bool is_pm_freezing(void) +{ + return pm_freezing; +} +#else +static inline bool is_pm_freezing(void) +{ + return false; +} +#endif /* CONFIG_FREEZING */ + #ifdef CONFIG_PROCESS_RECLAIM static int reclaim_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end, struct mm_walk *walk) @@ -1716,12 +1747,21 @@ static int reclaim_pte_range(pmd_t *pmd, unsigned long addr, int isolated; int reclaimed; +#ifdef CONFIG_ZRAM_LRU_WRITEBACK + bool is_lru_wb = false; + + if (!strcmp("PerProcessNands", current->comm)) + is_lru_wb = true; +#endif + split_huge_pmd(vma, addr, pmd); if (pmd_trans_unstable(pmd) || !rp->nr_to_reclaim) return 0; cont: if (rwsem_is_contended(&walk->mm->mmap_sem)) return -1; + if (is_pm_freezing()) + return -1; isolated = 0; pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl); @@ -1740,6 +1780,11 @@ cont: if (!PageLRU(page)) continue; +#ifdef CONFIG_ZRAM_LRU_WRITEBACK + if (is_lru_wb && ptep_test_and_clear_young(vma, addr, pte)) + continue; +#endif + if (isolate_lru_page(page)) continue; @@ -1777,11 +1822,53 @@ cont: return 0; } +#ifdef CONFIG_ZRAM_LRU_WRITEBACK +static int writeback_pte_range(pmd_t *pmd, unsigned long addr, + unsigned long end, struct mm_walk *walk) +{ + struct mm_struct *mm = walk->mm; + struct zwbs **zwbs = walk->private; + pte_t *pte, ptent; + spinlock_t *ptl; + LIST_HEAD(swp_entry_list); + + if (pmd_trans_huge(*pmd)) + return 0; + if (rwsem_is_contended(&mm->mmap_sem)) + return -1; + if (is_pm_freezing()) + return -1; + if (zram_is_app_launch()) + return -1; + + pte = pte_offset_map_lock(mm, pmd, addr, &ptl); + for (; addr != end; pte++, addr += PAGE_SIZE) { + ptent = *pte; + if (is_swap_pte(ptent)) { + swp_entry_t entry = pte_to_swp_entry(ptent); + if (unlikely(non_swap_entry(entry))) + continue; + if (swp_swapcount(entry) > 1) + continue; + swap_add_to_list(&swp_entry_list, entry); + } + } + pte_unmap_unlock(pte - 1, ptl); + swap_writeback_list(zwbs, &swp_entry_list); + + cond_resched(); + return 0; +} +#endif + enum reclaim_type { RECLAIM_FILE, RECLAIM_ANON, RECLAIM_ALL, RECLAIM_RANGE, +#ifdef CONFIG_ZRAM_LRU_WRITEBACK + RECLAIM_WRITEBACK, +#endif }; struct reclaim_param reclaim_task_anon(struct task_struct *task, @@ -1842,6 +1929,10 @@ static ssize_t reclaim_write(struct file *file, const char __user *buf, unsigned long start = 0; unsigned long end = 0; struct reclaim_param rp; +#ifdef CONFIG_ZRAM_LRU_WRITEBACK + struct zwbs *zwbs[NR_ZWBS]; + int sleep_count = 0; +#endif memset(buffer, 0, sizeof(buffer)); if (count > sizeof(buffer) - 1) @@ -1859,6 +1950,10 @@ static ssize_t reclaim_write(struct file *file, const char __user *buf, type = RECLAIM_ALL; else if (isdigit(*type_buf)) type = RECLAIM_RANGE; +#ifdef CONFIG_ZRAM_LRU_WRITEBACK + else if (!strcmp(type_buf, "writeback")) + type = RECLAIM_WRITEBACK; +#endif else goto out_err; @@ -1896,6 +1991,19 @@ static ssize_t reclaim_write(struct file *file, const char __user *buf, task = get_proc_task(file->f_path.dentry->d_inode); if (!task) return -ESRCH; +#ifdef CONFIG_ZRAM_LRU_WRITEBACK + if (type == RECLAIM_WRITEBACK) { + if (alloc_zwbs(zwbs)) { + pr_info("%s alloc_zwbs failed", __func__); + return -ENOMEM; + } + while (zram_is_app_launch()) { + if (is_pm_freezing() || sleep_count++ >= 10) + goto out; + msleep(1000); + } + } +#endif mm = get_task_mm(task); if (!mm) @@ -1908,6 +2016,13 @@ static ssize_t reclaim_write(struct file *file, const char __user *buf, rp.nr_reclaimed = 0; reclaim_walk.private = &rp; +#ifdef CONFIG_ZRAM_LRU_WRITEBACK + if (type == RECLAIM_WRITEBACK) { + reclaim_walk.pmd_entry = writeback_pte_range; + reclaim_walk.private = (void *)zwbs; + } +#endif + down_read(&mm->mmap_sem); if (type == RECLAIM_RANGE) { vma = find_vma(mm, start); @@ -1935,6 +2050,11 @@ static ssize_t reclaim_write(struct file *file, const char __user *buf, if (type == RECLAIM_FILE && !vma->vm_file) continue; +#ifdef CONFIG_ZRAM_LRU_WRITEBACK + if (type == RECLAIM_WRITEBACK && vma->vm_file) + continue; +#endif + rp.vma = vma; if (walk_page_range(vma->vm_start, vma->vm_end, &reclaim_walk)) @@ -1947,6 +2067,12 @@ static ssize_t reclaim_write(struct file *file, const char __user *buf, mmput(mm); out: put_task_struct(task); +#ifdef CONFIG_ZRAM_LRU_WRITEBACK + if (type == RECLAIM_WRITEBACK) { + swap_writeback_list(zwbs, NULL); + free_zwbs(zwbs); + } +#endif return count; out_err: diff --git a/include/linux/samsung/debug/sec_debug.h b/include/linux/samsung/debug/sec_debug.h index 5ceb0683c7d1..8b1a61a29b61 100755 --- a/include/linux/samsung/debug/sec_debug.h +++ b/include/linux/samsung/debug/sec_debug.h @@ -10,8 +10,13 @@ #include +#if defined(CONFIG_SEC_DEBUG_SCHED_LOG_IRQ_V2) +#define IRQ_ENTRY_V2 0x76324945 +#define IRQ_EXIT_V2 0x76324958 +#else #define IRQ_ENTRY 0x4945 #define IRQ_EXIT 0x4958 +#endif #define SOFTIRQ_ENTRY 0x5345 #define SOFTIRQ_EXIT 0x5358 diff --git a/include/linux/samsung/debug/sec_debug_sched_log.h b/include/linux/samsung/debug/sec_debug_sched_log.h index 10493f7d1548..289812e6740a 100755 --- a/include/linux/samsung/debug/sec_debug_sched_log.h +++ b/include/linux/samsung/debug/sec_debug_sched_log.h @@ -20,8 +20,10 @@ extern void sec_debug_task_sched_log(int cpu, bool preempt, struct task_struct * /* called @ kernel/irq/chip.c */ /* called @ kernel/irq/handle.c */ +extern void sec_debug_irq_sched_log(unsigned int irq, void *desc_or_fn, void *action_or_name, unsigned int en); + /* called @ kernel/softirq.c */ -extern void sec_debug_irq_sched_log(unsigned int irq, void *fn, char *name, unsigned int en); +extern void sec_debug_softirq_sched_log(unsigned int irq, void *fn, char *name, unsigned int en); /* called @ arch/arm64/kernel/traps.c */ /* called @ drivers/cpuidle/lpm-levels.c */ @@ -44,7 +46,8 @@ static inline int sec_debug_sched_msg(char *fmt, ...) { return 0; } static inline void sec_debug_secure_log(u32 svc_id, u32 cmd_id) {} static inline void sec_debug_task_sched_log(int cpu, bool preempt, struct task_struct *task, struct task_struct *prev) {} static inline void sec_debug_timer_log(unsigned int type, int int_lock, void *fn) {} -static inline void sec_debug_irq_sched_log(unsigned int irq, void *fn, char *name, unsigned int en) {} +static inline void sec_debug_irq_sched_log(unsigned int irq, void *desc_or_fn, void *action_or_name, unsigned int en) {} +static inline void sec_debug_softirq_sched_log(unsigned int irq, void *fn, char *name, unsigned int en) {} #endif /* CONFIG_SEC_DEBUG_SCHED_LOG */ diff --git a/include/linux/samsung/debug/sec_debug_sched_log_type.h b/include/linux/samsung/debug/sec_debug_sched_log_type.h index 8bc1970dd82e..af7de926dab6 100755 --- a/include/linux/samsung/debug/sec_debug_sched_log_type.h +++ b/include/linux/samsung/debug/sec_debug_sched_log_type.h @@ -12,7 +12,10 @@ struct irq_buf { char *name; int en; int preempt_count; - void *context; + union { + void *context; + irq_hw_number_t hwirq; + }; pid_t pid; unsigned int entry_exit; }; diff --git a/include/linux/samsung/debug/sec_debug_user_reset_type.h b/include/linux/samsung/debug/sec_debug_user_reset_type.h index c27c88c60b01..283baa75170f 100755 --- a/include/linux/samsung/debug/sec_debug_user_reset_type.h +++ b/include/linux/samsung/debug/sec_debug_user_reset_type.h @@ -285,7 +285,7 @@ struct tzdbg_t { struct { uint8_t reserve[512]; - uint8_t num_interrupts; + uint32_t num_interrupts; uint8_t reserve2[3648]; diff --git a/include/linux/tty.h b/include/linux/tty.h index 470c8c0c6a43..7fa56710a4f0 100755 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -305,6 +305,10 @@ struct tty_struct { struct termiox *termiox; /* May be NULL for unsupported */ char name[64]; struct pid *pgrp; /* Protected by ctrl lock */ + /* + * Writes protected by both ctrl lock and legacy mutex, readers must use + * at least one of them. + */ struct pid *session; unsigned long flags; int count; diff --git a/include/trace/events/ext4.h b/include/trace/events/ext4.h index 58f08e82690a..3902b6960db2 100755 --- a/include/trace/events/ext4.h +++ b/include/trace/events/ext4.h @@ -879,7 +879,6 @@ TRACE_EVENT(ext4_free_blocks, show_free_flags(__entry->flags)) ); -/* @fs.sec -- 84802e246d0781e97b5b13c60ae460dc346ba707 -- */ TRACE_EVENT(ext4_sync_file_enter, TP_PROTO(struct file *file, int datasync), @@ -890,7 +889,6 @@ TRACE_EVENT(ext4_sync_file_enter, __field( ino_t, ino ) __field( ino_t, parent ) __field( int, datasync ) - __array(unsigned char, d_name, EXT4_NAME_LEN) ), TP_fast_assign( @@ -900,14 +898,12 @@ TRACE_EVENT(ext4_sync_file_enter, __entry->ino = d_inode(dentry)->i_ino; __entry->datasync = datasync; __entry->parent = d_inode(dentry->d_parent)->i_ino; - memcpy(__entry->d_name, dentry->d_name.name, EXT4_NAME_LEN); ), - TP_printk("dev %d,%d ino %lu parent %lu datasync %d d_name %s", + TP_printk("dev %d,%d ino %lu parent %lu datasync %d ", MAJOR(__entry->dev), MINOR(__entry->dev), (unsigned long) __entry->ino, - (unsigned long) __entry->parent, __entry->datasync, - __entry->d_name) + (unsigned long) __entry->parent, __entry->datasync) ); TRACE_EVENT(ext4_sync_file_exit, @@ -1455,7 +1451,6 @@ TRACE_EVENT(ext4_unlink_enter, __field( ino_t, ino ) __field( ino_t, parent ) __field( loff_t, size ) - __array(unsigned char, d_name, EXT4_NAME_LEN) ), TP_fast_assign( @@ -1463,13 +1458,12 @@ TRACE_EVENT(ext4_unlink_enter, __entry->ino = d_inode(dentry)->i_ino; __entry->parent = parent->i_ino; __entry->size = d_inode(dentry)->i_size; - memcpy(__entry->d_name, dentry->d_name.name, EXT4_NAME_LEN); ), - TP_printk("dev %d,%d ino %lu size %lld parent %lu d_name %s", + TP_printk("dev %d,%d ino %lu size %lld parent %lu", MAJOR(__entry->dev), MINOR(__entry->dev), (unsigned long) __entry->ino, __entry->size, - (unsigned long) __entry->parent, __entry->d_name) + (unsigned long) __entry->parent) ); TRACE_EVENT(ext4_unlink_exit, @@ -1481,20 +1475,18 @@ TRACE_EVENT(ext4_unlink_exit, __field( dev_t, dev ) __field( ino_t, ino ) __field( int, ret ) - __array(unsigned char, d_name, EXT4_NAME_LEN) ), TP_fast_assign( __entry->dev = dentry->d_sb->s_dev; __entry->ino = d_inode(dentry)->i_ino; __entry->ret = ret; - memcpy(__entry->d_name, dentry->d_name.name, EXT4_NAME_LEN); ), - TP_printk("dev %d,%d ino %lu ret %d d_name %s", + TP_printk("dev %d,%d ino %lu ret %d", MAJOR(__entry->dev), MINOR(__entry->dev), (unsigned long) __entry->ino, - __entry->ret, __entry->d_name) + __entry->ret) ); DECLARE_EVENT_CLASS(ext4__truncate, diff --git a/kernel/cred.c b/kernel/cred.c index db2b0929821d..424f4580a909 100755 --- a/kernel/cred.c +++ b/kernel/cred.c @@ -843,7 +843,7 @@ const struct cred *override_creds(const struct cred *new) rcu_assign_pointer(current->cred, new_ro); } else #endif /* CONFIG_RKP_KDP */ - rcu_assign_pointer(current->cred, new); + rcu_assign_pointer(current->cred, new); alter_cred_subscribers(old, -1); kdebug("override_creds() = %p{%d,%d}", old, @@ -878,8 +878,8 @@ void revert_creds(const struct cred *old) if (rkp_ro_page((unsigned long)override)) { if (get_rocred_rcu(override)->reflected_cred) put_cred((struct cred *)(get_rocred_rcu(override)->reflected_cred)); - put_cred(override); -} + put_cred(override); + } } #endif put_cred(override); diff --git a/net/core/dev_monitor.c b/net/core/dev_monitor.c index ca5377273750..a76e08b6a4fd 100755 --- a/net/core/dev_monitor.c +++ b/net/core/dev_monitor.c @@ -20,7 +20,8 @@ struct dev_addr_info { static struct list_head dev_info; static struct list_head cleanup_dev_info; -static struct work_struct cleanup_work; +static void dev_monitor_deferred_cleanup(struct work_struct *work); +static DECLARE_DELAYED_WORK(cleanup_work, dev_monitor_deferred_cleanup); static struct dev_addr_info *get_dev_info(struct list_head *head, struct net_device *dev, int family) @@ -256,8 +257,9 @@ static int dev_monitor_inetaddr_event(struct notifier_block *this, addr_info = get_dev_info(&dev_info, dev, AF_INET); if (addr_info) { - if ((addr_info->addr.addr4 == ifa->ifa_local) && - (addr_info->prefixlen != ifa->ifa_prefixlen)) { + __be32 mask = inet_make_mask(addr_info->prefixlen); + + if (!((addr_info->addr.addr4 ^ ifa->ifa_local) & mask)) { pr_err("%s %s: %pI4/%d, updated:%pI4/%d\n", __func__, dev->name, &addr_info->addr.addr4, addr_info->prefixlen, &ifa->ifa_local, ifa->ifa_prefixlen); @@ -272,8 +274,8 @@ static int dev_monitor_inetaddr_event(struct notifier_block *this, // tcp_disconnect calls might_sleep function // so it crashes when this routine calls // dev_monitor_cleanup_sock directly - if (!work_pending(&cleanup_work)) - schedule_work(&cleanup_work); + if (!delayed_work_pending(&cleanup_work)) + schedule_delayed_work(&cleanup_work, msecs_to_jiffies(1000)); } } @@ -331,8 +333,7 @@ static int dev_monitor_inet6addr_event(struct notifier_block *this, addr_info = get_dev_info(&dev_info, dev, AF_INET6); if (addr_info) { - if (ipv6_addr_equal(&addr_info->addr.addr6, &ifa->addr) && - !ipv6_prefix_equal(&addr_info->addr.addr6, &ifa->addr, ifa->prefix_len)) { + if (ipv6_prefix_equal(&addr_info->addr.addr6, &ifa->addr, ifa->prefix_len)) { pr_err("%s %s: %pI6/%d, updated:%pI6/%d\n", __func__, dev->name, &addr_info->addr.addr6, addr_info->prefixlen, &ifa->addr, ifa->prefix_len); @@ -347,8 +348,8 @@ static int dev_monitor_inet6addr_event(struct notifier_block *this, // tcp_disconnect calls might_sleep function // so it crashes when this routine calls // dev_monitor_cleanup_sock directly - if (!work_pending(&cleanup_work)) - schedule_work(&cleanup_work); + if (!delayed_work_pending(&cleanup_work)) + schedule_delayed_work(&cleanup_work, msecs_to_jiffies(1000)); } } @@ -386,7 +387,6 @@ static int __init dev_monitor_init(void) INIT_LIST_HEAD(&dev_info); INIT_LIST_HEAD(&cleanup_dev_info); - INIT_WORK(&cleanup_work, dev_monitor_deferred_cleanup); ret = register_netdevice_notifier(&dev_monitor_nb); if (ret) { pr_err("%s: registering notifier error %d\n", __func__, ret); diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index bd7b97ec193c..dc8286114233 100755 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -4037,6 +4037,15 @@ static void addrconf_dad_work(struct work_struct *w) } ifp->dad_probes--; + if (!strcmp(ifp->idev->dev->name, "aware_data0")) { + pr_info("Reduce waing time from %lu to %lu (HZ=%lu) to send NS for quick transmission for %s\n", + NEIGH_VAR(ifp->idev->nd_parms, RETRANS_TIME), + NEIGH_VAR(ifp->idev->nd_parms, RETRANS_TIME)/10, + HZ, + ifp->idev->dev->name); + addrconf_mod_dad_work(ifp, + NEIGH_VAR(ifp->idev->nd_parms, RETRANS_TIME)/10); + } else addrconf_mod_dad_work(ifp, NEIGH_VAR(ifp->idev->nd_parms, RETRANS_TIME)); spin_unlock(&ifp->lock); diff --git a/net/qrtr/qrtr.c b/net/qrtr/qrtr.c index 9aa54a2aa513..fd9070bf2bf4 100755 --- a/net/qrtr/qrtr.c +++ b/net/qrtr/qrtr.c @@ -1749,6 +1749,11 @@ static int qrtr_recvmsg(struct socket *sock, struct msghdr *msg, rc = copied; if (addr) { + /* There is an anonymous 2-byte hole after sq_family, + * make sure to clear it. + */ + memset(addr, 0, sizeof(*addr)); + addr->sq_family = AF_QIPCRTR; addr->sq_node = cb->src_node; addr->sq_port = cb->src_port; diff --git a/security/defex_lsm/Kconfig b/security/defex_lsm/Kconfig index 997e05ea287a..f2638458f598 100755 --- a/security/defex_lsm/Kconfig +++ b/security/defex_lsm/Kconfig @@ -1,6 +1,13 @@ config SECURITY_DEFEX bool "Defex Support" - depends on SECURITY + depends on SECURITY && (!KCOV || SAMSUNG_PRODUCT_SHIP) + select CRYPTO + select CRYPTO_RSA + select CRYPTO_SHA1 + select CRYPTO_SHA256 + select CRYPTO_HASH_INFO + select INTEGRITY_SIGNATURE + select INTEGRITY_ASYMMETRIC_KEYS default n help This selects the Defex support. @@ -8,7 +15,7 @@ config SECURITY_DEFEX config DEFEX_KERNEL_ONLY bool "Defex Kernel Only" - depends on SECURITY + depends on SECURITY_DEFEX default y help This lets defex know whether kernel-only build or not. diff --git a/security/defex_lsm/Makefile b/security/defex_lsm/Makefile index e783ea111fb6..2a077ba8ba8f 100755 --- a/security/defex_lsm/Makefile +++ b/security/defex_lsm/Makefile @@ -5,75 +5,158 @@ # Features to Enable PED_ENABLE=true SAFEPLACE_ENABLE=true -INTEGRITY_ENABLE=true +IMMUTABLE_ENABLE=true +LP_ENABLE=true +UMH_RESTRICTION_ENABLE=true + +ifneq ($(wildcard $(srctree)/include/crypto/internal/rsa.h),) + $(warning [DEFEX] INTEGRITY_ENABLE) + INTEGRITY_ENABLE=true +endif # caches to enable CACHES_ENABLE=true -obj-y := defex_lsm.o -obj-y += defex_catch_list.o -obj-y += defex_ht.o -obj-y += defex_config.o -obj-y += defex_sysfs.o -obj-y += defex_procs.o -obj-y += defex_catch_list_compat.o -obj-y += defex_rules.o +# OEM Unlock dependency +OEM_UNLOCK_DEPENDENCY=true + +# use the ramdisk or system_root to store rules file +RAMDISK_ENABLE=true + +# do signing for rules +SIGN_ENABLE=true + +defex-y := core/defex_common.o +defex-y += core/defex_lsm.o +defex-y += core/defex_main.o +defex-y += core/defex_get_mode.o +defex-y += core/defex_sysfs.o +defex-y += catch_engine/defex_catch_list.o +defex-y += catch_engine/defex_ht.o +defex-y += defex_rules.o +defex-$(CONFIG_COMPAT) += catch_engine/defex_catch_list_compat.o + +# Immutable Feature is applied with permissive mode first. +DEFEX_DEFINES := -DDEFEX_PERMISSIVE_IM ifeq ($(CONFIG_DEFEX_KERNEL_ONLY), y) -EXTRA_CFLAGS += -DDEFEX_KERNEL_ONLY + DEFEX_DEFINES += -DDEFEX_KERNEL_ONLY + ifeq ($(CONFIG_SAMSUNG_PRODUCT_SHIP), y) + $(warning [DEFEX] Kernel_only & Ship) + else + $(warning [DEFEX] Kernel_only & Noship) + DEFEX_DEFINES += -DDEFEX_PERMISSIVE_SP + DEFEX_DEFINES += -DDEFEX_PERMISSIVE_IM + DEFEX_DEFINES += -DDEFEX_PERMISSIVE_LP + DEFEX_DEFINES += -DDEFEX_DEBUG_ENABLE + endif +endif + +ifeq ($(CONFIG_SEC_FACTORY), y) + DEFEX_DEFINES += -DDEFEX_FACTORY_ENABLE +endif + +# kunit tests options: +ifeq ($(CONFIG_KUNIT), y) + GCOV_PROFILE := y + DEFEX_DEFINES += -DDEFEX_KUNIT_ENABLED +else + DEFEX_DEFINES += -D__visible_for_testing=static endif ifeq ($(PED_ENABLE), true) - obj-y += defex_priv.o - EXTRA_CFLAGS += -DDEFEX_PED_ENABLE + defex-y += feature_privilege_escalation_detection/defex_priv.o + DEFEX_DEFINES += -DDEFEX_PED_ENABLE endif ifeq ($(SAFEPLACE_ENABLE), true) - obj-y += defex_safeplace.o - EXTRA_CFLAGS += -DDEFEX_SAFEPLACE_ENABLE + defex-y += feature_safeplace/defex_safeplace.o + DEFEX_DEFINES += -DDEFEX_SAFEPLACE_ENABLE endif ifeq ($(INTEGRITY_ENABLE), true) - EXTRA_CFLAGS += -DDEFEX_INTEGRITY_ENABLE + DEFEX_DEFINES += -DDEFEX_INTEGRITY_ENABLE +endif + +ifeq ($(IMMUTABLE_ENABLE), true) + defex-y += feature_immutable/defex_immutable.o + DEFEX_DEFINES += -DDEFEX_IMMUTABLE_ENABLE +endif + +ifeq ($(LP_ENABLE), true) + DEFEX_DEFINES += -DDEFEX_LP_ENABLE +endif + +ifeq ($(UMH_RESTRICTION_ENABLE), true) + DEFEX_DEFINES += -DDEFEX_UMH_RESTRICTION_ENABLE endif ifeq ($(CACHES_ENABLE), true) - obj-y += defex_caches.o - EXTRA_CFLAGS += -DDEFEX_CACHES_ENABLE + defex-y += catch_engine/defex_caches.o + DEFEX_DEFINES += -DDEFEX_CACHES_ENABLE endif -ifneq (,$(filter userdebug eng, $(TARGET_BUILD_VARIANT))) - obj-y += defex_debug.o - EXTRA_CFLAGS += -DDEFEX_PERMISSIVE_SP - EXTRA_CFLAGS += -DDEFEX_DEBUG_ENABLE - EXTRA_CFLAGS += -DDEFEX_SYSFS_ENABLE +ifeq ($(OEM_UNLOCK_DEPENDENCY), true) + DEFEX_DEFINES += -DDEFEX_DEPENDING_ON_OEMUNLOCK endif -ifeq ($(SEC_BUILD_OPTION_VTS), true) -$(warning [DEFEX] VTS true $(SEC_BUILD_OPTION_VTS)) -EXTRA_CFLAGS += -DDEFEX_PERMISSIVE_SP -EXTRA_CFLAGS += -DDEFEX_PERMISSIVE_PED -else -$(warning [DEFEX] VTS false $(SEC_BUILD_OPTION_VTS)) +ifeq ($(RAMDISK_ENABLE), true) + DEFEX_DEFINES += -DDEFEX_RAMDISK_ENABLE +ifeq ($(SIGN_ENABLE), true) + defex-y += cert/defex_cert.o + defex-y += cert/defex_sign.o + DEFEX_DEFINES += -DDEFEX_SIGN_ENABLE +endif endif -ifeq ($(CONFIG_SEC_FACTORY), y) -EXTRA_CFLAGS += -DDEFEX_PERMISSIVE_SP -EXTRA_CFLAGS += -DDEFEX_PERMISSIVE_PED +ifneq (,$(filter userdebug eng, $(TARGET_BUILD_VARIANT))) + defex-y += debug/defex_debug.o + DEFEX_DEFINES += -DDEFEX_PERMISSIVE_SP + DEFEX_DEFINES += -DDEFEX_PERMISSIVE_IM + DEFEX_DEFINES += -DDEFEX_PERMISSIVE_LP + DEFEX_DEFINES += -DDEFEX_DEBUG_ENABLE + DEFEX_DEFINES += -DDEFEX_SYSFS_ENABLE +else + ifeq ($(CONFIG_SECURITY_DSMS), y) + DEFEX_DEFINES += -DDEFEX_DSMS_ENABLE + endif endif +ccflags-y := -Wformat + +EXTRA_CFLAGS += -I$(srctree)/$(src) +EXTRA_AFLAGS += -Isecurity/samsung/defex_lsm +EXTRA_CFLAGS += -I$(srctree)/$(src)/cert +EXTRA_AFLAGS += -Isecurity/samsung/defex_lsm/cert + ifneq ($(wildcard $(srctree)/$(src)/pack_rules.c),) - EXTRA_CFLAGS += -DDEFEX_USE_PACKED_RULES + DEFEX_DEFINES += -DDEFEX_USE_PACKED_RULES + EXTRA_CFLAGS += $(DEFEX_DEFINES) + EXTRA_AFLAGS += $(DEFEX_DEFINES) hostprogs-y := pack_rules - HOST_EXTRACFLAGS += $(EXTRA_CFLAGS) + HOST_EXTRACFLAGS += $(DEFEX_DEFINES) clean-files := $(srctree)/$(src)/defex_packed_rules.inc DEPEND_LIST := $(obj)/pack_rules - $(obj)/defex_sysfs.o: $(obj)/pack_rules $(srctree)/$(src)/defex_packed_rules.inc + quiet_cmd_copy = COPY $(obj)/pack_rules + cmd_copy = cp -n $(obj)/pack_rules $(srctree)/$(src)/pack_rules 2>/dev/null || true quiet_cmd_pack = PACK $< cmd_pack = $(obj)/pack_rules -p $< $@ $(srctree)/$(src)/defex_packed_rules.bin + quiet_cmd_mkey = MAKEKEY $< + cmd_mkey = cp -n $< $@ 2>/dev/null || true + + $(obj)/core/defex_sysfs.o: $(obj)/pack_rules $(srctree)/$(src)/defex_packed_rules.inc + + $(obj)/cert/defex_cert.o: $(obj)/cert/pubkey_eng.der $(obj)/cert/pubkey_user.der + + $(obj)/cert/pubkey_eng.der: $(srctree)/$(src)/cert/x509_five_eng.der + $(call cmd,mkey) + + $(obj)/cert/pubkey_user.der: $(srctree)/$(src)/cert/x509_five_user.der + $(call cmd,mkey) + SOURCE_RULES := $(srctree)/$(src)/defex_rules.c ifneq ($(wildcard $(srctree)/$(src)/file_list),) $(warning '[DEFEX] file_list found') @@ -91,6 +174,11 @@ ifneq ($(wildcard $(srctree)/$(src)/pack_rules.c),) $(srctree)/$(src)/defex_packed_rules.inc: $(SOURCE_RULES) $(DEPEND_LIST) $(call cmd,pack) + $(call cmd,copy) +else + EXTRA_CFLAGS += $(DEFEX_DEFINES) + EXTRA_AFLAGS += $(DEFEX_DEFINES) endif +obj-$(CONFIG_SECURITY_DEFEX) := $(defex-y) diff --git a/security/defex_lsm/defex_caches.c b/security/defex_lsm/catch_engine/defex_caches.c similarity index 100% rename from security/defex_lsm/defex_caches.c rename to security/defex_lsm/catch_engine/defex_caches.c diff --git a/security/defex_lsm/defex_catch_list.c b/security/defex_lsm/catch_engine/defex_catch_list.c similarity index 86% rename from security/defex_lsm/defex_catch_list.c rename to security/defex_lsm/catch_engine/defex_catch_list.c index 10efc19d48c0..935374761ecf 100755 --- a/security/defex_lsm/defex_catch_list.c +++ b/security/defex_lsm/catch_engine/defex_catch_list.c @@ -6,7 +6,7 @@ * as published by the Free Software Foundation. */ -#include +#include #include #include #include @@ -16,6 +16,12 @@ #include #include "include/defex_catch_list.h" +#ifdef DEFEX_KUNIT_ENABLED +#ifndef __NR_syscalls +#define __NR_syscalls 436 +#endif +#endif + #define DEFEX_CATCH_COUNT __NR_syscalls const int defex_nr_syscalls = DEFEX_CATCH_COUNT; @@ -23,7 +29,7 @@ const int defex_nr_syscalls = DEFEX_CATCH_COUNT; const struct local_syscall_struct *get_local_syscall(int syscall_no) { - if (syscall_no >= __NR_syscalls) + if ((unsigned int)syscall_no >= __NR_syscalls) return NULL; if (!syscall_catch_arr[syscall_no].local_syscall && !syscall_catch_arr[syscall_no].err_code && syscall_no) { diff --git a/security/defex_lsm/defex_catch_list.inc b/security/defex_lsm/catch_engine/defex_catch_list.inc similarity index 100% rename from security/defex_lsm/defex_catch_list.inc rename to security/defex_lsm/catch_engine/defex_catch_list.inc diff --git a/security/defex_lsm/defex_catch_list_compat.c b/security/defex_lsm/catch_engine/defex_catch_list_compat.c similarity index 65% rename from security/defex_lsm/defex_catch_list_compat.c rename to security/defex_lsm/catch_engine/defex_catch_list_compat.c index 7528048cf783..df9ee085a290 100755 --- a/security/defex_lsm/defex_catch_list_compat.c +++ b/security/defex_lsm/catch_engine/defex_catch_list_compat.c @@ -9,13 +9,23 @@ #include #include #include +#include #include "include/defex_catch_list.h" -#ifdef __NR_seccomp -#define __NR_compat_syscalls (__NR_seccomp + 1) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0) +#define __COMPAT_SYSCALL_NR +#include +#else +#ifdef __NR_clone3 +#define __NR_compat_syscalls (__NR_clone3 + 10) +#elif defined(__NR_rseq) +#define __NR_compat_syscalls (__NR_rseq + 10) +#elif defined(__NR_seccomp) +#define __NR_compat_syscalls (__NR_seccomp + 10) #else #define __NR_compat_syscalls 400 -#endif /* __NR_seccomp */ +#endif +#endif /* < KERNEL_VERSION(4, 0, 0) */ #define DEFEX_CATCH_COUNT __NR_compat_syscalls const int defex_nr_syscalls_compat = DEFEX_CATCH_COUNT; @@ -24,7 +34,7 @@ const int defex_nr_syscalls_compat = DEFEX_CATCH_COUNT; const struct local_syscall_struct *get_local_syscall_compat(int syscall_no) { - if (syscall_no >= __NR_compat_syscalls) + if ((unsigned int)syscall_no >= __NR_compat_syscalls) return NULL; if (!syscall_catch_arr[syscall_no].local_syscall && !syscall_catch_arr[syscall_no].err_code && syscall_no) { diff --git a/security/defex_lsm/catch_engine/defex_ht.c b/security/defex_lsm/catch_engine/defex_ht.c new file mode 100755 index 000000000000..34e5675e2a04 --- /dev/null +++ b/security/defex_lsm/catch_engine/defex_ht.c @@ -0,0 +1,384 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include "include/defex_catch_list.h" +#include "include/defex_internal.h" + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0) +#include +#include +#endif + +#define MAX_PID_32 32768 +#define DEFEX_MEM_CACHE_SIZE 32 +#define DEFEX_MEM_CACHE_COUNT 3 +#define CACHE_CRED_DATA 0 +#define CACHE_CRED_DATA_ID 1 +#define CACHE_HTABLE_ITEM 2 + +struct id_set { + unsigned int uid, fsuid, egid; +}; + +struct proc_cred_data { + unsigned short cred_flags; + unsigned short tcnt; + struct id_set default_ids; + struct id_set main_ids[]; +}; + +struct hash_item_struct { + struct hlist_node node; + struct proc_cred_data *cred_data; + int id; +}; + +struct mem_cache_list { + atomic_t count; + char name[8]; + struct kmem_cache *allocator; + void *mem_cache_array[DEFEX_MEM_CACHE_SIZE]; +}; + +#ifdef DEFEX_PED_ENABLE +DECLARE_HASHTABLE(creds_hash, 15); +static DEFINE_SPINLOCK(creds_hash_update_lock); +static struct proc_cred_data *creds_fast_hash[MAX_PID_32 + 1]; +static struct mem_cache_list mem_cache[DEFEX_MEM_CACHE_COUNT]; +static int creds_fast_hash_ready __ro_after_init; +__visible_for_testing void mem_cache_alloc(void); + + +void __init creds_fast_hash_init(void) +{ + unsigned int i; + static const int sizes[DEFEX_MEM_CACHE_COUNT] __initdata = { + sizeof(struct proc_cred_data), + sizeof(struct proc_cred_data) + sizeof(struct id_set), + sizeof(struct hash_item_struct) + }; + + hash_init(creds_hash); + for (i = 0; i <= MAX_PID_32; i++) + creds_fast_hash[i] = NULL; + + for(i = 0; i < ARRAY_SIZE(sizes); i++) { + snprintf(mem_cache[i].name, sizeof(mem_cache[i].name), "defex%d", i); + mem_cache[i].allocator = kmem_cache_create(mem_cache[i].name, sizes[i], 0, 0, NULL); + } + + for(i = 0; i < (DEFEX_MEM_CACHE_SIZE / 2); i++) + mem_cache_alloc(); + + creds_fast_hash_ready = 1; +} + +int is_task_creds_ready(void) +{ + return creds_fast_hash_ready; +} + +__visible_for_testing inline void *mem_cache_get(int cache_number) +{ + int n; + n = atomic_read(&mem_cache[cache_number].count); + if (n) { + atomic_dec(&mem_cache[cache_number].count); + return mem_cache[cache_number].mem_cache_array[n - 1]; + } + return NULL; +} + +__visible_for_testing inline void *mem_cache_reclaim(int cache_number, void *ptr) +{ + int n; + n = atomic_read(&mem_cache[cache_number].count); + if (n < DEFEX_MEM_CACHE_SIZE) { + atomic_inc(&mem_cache[cache_number].count); + mem_cache[cache_number].mem_cache_array[n] = ptr; + ptr = NULL; + } + return ptr; +} + +__visible_for_testing void mem_cache_alloc(void) +{ + int mem_allocated = 0; + int i, n; + unsigned long flags; + void *mem_block[DEFEX_MEM_CACHE_COUNT]; + + for(i = 0; i < DEFEX_MEM_CACHE_COUNT; i++) { + mem_block[i] = NULL; + n = atomic_read(&mem_cache[i].count); + if (n < (DEFEX_MEM_CACHE_SIZE / 2)) { + mem_block[i] = kmem_cache_alloc(mem_cache[i].allocator, in_atomic() ? GFP_ATOMIC:GFP_KERNEL); + mem_allocated++; + } + } + + if (!mem_allocated) + return; + + spin_lock_irqsave(&creds_hash_update_lock, flags); + for(i = 0; i < DEFEX_MEM_CACHE_COUNT; i++) { + n = atomic_read(&mem_cache[i].count); + if (mem_block[i] && n < DEFEX_MEM_CACHE_SIZE) { + mem_cache[i].mem_cache_array[n] = mem_block[i]; + mem_block[i] = NULL; + atomic_inc(&mem_cache[i].count); + mem_allocated--; + } + } + spin_unlock_irqrestore(&creds_hash_update_lock, flags); + + if (!mem_allocated) + return; + + for(i = 0; i < DEFEX_MEM_CACHE_COUNT; i++) { + if (mem_block[i]) { + kmem_cache_free(mem_cache[i].allocator, mem_block[i]); + } + } +} + +__visible_for_testing struct proc_cred_data *get_cred_data(int id) +{ + struct proc_cred_data *cred_data = NULL; + struct hash_item_struct *obj; + + if (id < 0) + return NULL; + if (id <= MAX_PID_32) { + cred_data = creds_fast_hash[id]; + } else { + hash_for_each_possible(creds_hash, obj, node, id) { + if (obj->id == id) { + cred_data = obj->cred_data; + break; + } + } + } + return cred_data; +} + +__visible_for_testing struct proc_cred_data **get_cred_ptr(int id) +{ + struct proc_cred_data **cred_ptr = NULL; + struct hash_item_struct *obj; + + if (id < 0) + return NULL; + if (id <= MAX_PID_32) { + cred_ptr = &creds_fast_hash[id]; + } else { + hash_for_each_possible(creds_hash, obj, node, id) { + if (obj->id == id) { + cred_ptr = &obj->cred_data; + break; + } + } + } + return cred_ptr; +} + +__visible_for_testing void set_cred_data(int id, struct proc_cred_data **cred_ptr, struct proc_cred_data *cred_data) +{ + struct hash_item_struct *obj; + + if (id < 0) + return; + if (cred_ptr) { + *cred_ptr = cred_data; + } else { + if (id > MAX_PID_32) { + obj = mem_cache_get(CACHE_HTABLE_ITEM); + if (!obj) + return; + obj->id = id; + obj->cred_data = cred_data; + hash_add(creds_hash, &obj->node, id); + } + } +} + +void get_task_creds(struct task_struct *p, unsigned int *uid_ptr, unsigned int *fsuid_ptr, unsigned int *egid_ptr, unsigned short *cred_flags_ptr) +{ + struct proc_cred_data *cred_data, *thread_cred_data; + struct id_set *ids_ptr; + unsigned int uid = 0, fsuid = 0, egid = 0; + unsigned short cred_flags = CRED_FLAGS_PROOT; + unsigned long flags; + int tgid = p->tgid, pid = p->pid; + + spin_lock_irqsave(&creds_hash_update_lock, flags); + cred_data = get_cred_data(tgid); + if (cred_data) { + if (tgid == pid) { + ids_ptr = (cred_data->cred_flags & CRED_FLAGS_MAIN_UPDATED) ? \ + (&cred_data->main_ids[0]) : (&cred_data->default_ids); + } else { + if (cred_data->cred_flags & CRED_FLAGS_SUB_UPDATED) { + thread_cred_data = get_cred_data(pid); + if (thread_cred_data) + cred_data = thread_cred_data; + } + ids_ptr = &cred_data->default_ids; + } + GET_CREDS(ids_ptr, cred_data); + } + spin_unlock_irqrestore(&creds_hash_update_lock, flags); + *uid_ptr = uid; + *fsuid_ptr = fsuid; + *egid_ptr = egid; + *cred_flags_ptr = cred_flags; +} + +int set_task_creds(struct task_struct *p, unsigned int uid, unsigned int fsuid, unsigned int egid, unsigned short cred_flags) +{ + struct proc_cred_data *cred_data = NULL, *tmp_data, **cred_ptr; + struct id_set *ids_ptr; + unsigned long flags; + int err = -1, tgid = p->tgid, pid = p->pid; + void *free_buff = NULL; + + + mem_cache_alloc(); + spin_lock_irqsave(&creds_hash_update_lock, flags); + + /* Search for main proces's data */ + cred_ptr = get_cred_ptr(tgid); + cred_data = (cred_ptr) ? (*cred_ptr) : NULL; + if (!cred_data) { + /* Not found? Allocate a new data */ + cred_data = mem_cache_get(CACHE_CRED_DATA); + if (!cred_data) + goto set_finish; + cred_data->cred_flags = 0; + cred_data->tcnt = 1; + set_cred_data(tgid, cred_ptr, cred_data); + } + ids_ptr = &cred_data->default_ids; + + if (cred_data->tcnt >= 2) { + if (tgid == pid) { + /* Allocate extended data for main process, copy and remove old data */ + if (!(cred_data->cred_flags & CRED_FLAGS_MAIN_UPDATED)) { + cred_data->cred_flags |= CRED_FLAGS_MAIN_UPDATED; + tmp_data = mem_cache_get(CACHE_CRED_DATA_ID); + if (!tmp_data) + goto set_finish; + *tmp_data = *cred_data; + free_buff = mem_cache_reclaim(CACHE_CRED_DATA, cred_data); + cred_data = tmp_data; + set_cred_data(tgid, cred_ptr, cred_data); + } + ids_ptr = &cred_data->main_ids[0]; + } else { + cred_data->cred_flags |= CRED_FLAGS_SUB_UPDATED; + /* Search for thread's data. Allocate, if not found */ + cred_ptr = get_cred_ptr(pid); + cred_data = (cred_ptr) ? (*cred_ptr) : NULL; + if (!cred_data) { + cred_data = mem_cache_get(CACHE_CRED_DATA); + if (!cred_data) + goto set_finish; + set_cred_data(pid, cred_ptr, cred_data); + } + cred_data->cred_flags = 0; + ids_ptr = &cred_data->default_ids; + } + } + SET_CREDS(ids_ptr, cred_data); + err = 0; + +set_finish: + spin_unlock_irqrestore(&creds_hash_update_lock, flags); + /* Free the pending pointer */ + if (free_buff) + kmem_cache_free(mem_cache[CACHE_CRED_DATA].allocator, free_buff); + mem_cache_alloc(); + return err; +} + +void set_task_creds_tcnt(struct task_struct *p, int addition) +{ + struct hash_item_struct *tgid_obj = NULL, *pid_obj = NULL; + struct proc_cred_data **cred_ptr, *tgid_cred_data = NULL, *pid_cred_data = NULL; + struct proc_cred_data *free_buff1 = NULL, *free_buff2 = NULL; + int tgid = p->tgid, pid = p->pid; + unsigned long flags; + + spin_lock_irqsave(&creds_hash_update_lock, flags); + /* Remove the thread's data, if found */ + if (tgid != pid && addition == -1) { + cred_ptr = get_cred_ptr(pid); + pid_cred_data = (cred_ptr) ? (*cred_ptr) : NULL; + if (pid_cred_data) { + *cred_ptr = NULL; + /* Return to pre-allocated pool, if possible */ + free_buff1 = mem_cache_reclaim(CACHE_CRED_DATA, pid_cred_data); + } + /* Remove the thread's hash container */ + if (cred_ptr && pid > MAX_PID_32) { + pid_obj = container_of(cred_ptr, struct hash_item_struct, cred_data); + hash_del(&pid_obj->node); + /* Return to pre-allocated pool, if possible */ + pid_obj = mem_cache_reclaim(CACHE_HTABLE_ITEM, pid_obj); + } + } + /* Search for the main process's data */ + cred_ptr = get_cred_ptr(tgid); + tgid_cred_data = (cred_ptr) ? (*cred_ptr) : NULL; + if (tgid_cred_data) { + tgid_cred_data->tcnt += addition; + /* No threads, remove process data */ + if (!tgid_cred_data->tcnt) { + *cred_ptr = NULL; + /* Return to pre-allocated pool, if possible */ + free_buff2 = mem_cache_reclaim((tgid_cred_data->cred_flags & CRED_FLAGS_MAIN_UPDATED) ? \ + CACHE_CRED_DATA_ID : CACHE_CRED_DATA, tgid_cred_data); + /* Remove the process's hash container */ + if (tgid > MAX_PID_32) { + tgid_obj = container_of(cred_ptr, struct hash_item_struct, cred_data); + hash_del(&tgid_obj->node); + /* Return to pre-allocated pool, if possible */ + tgid_obj = mem_cache_reclaim(CACHE_HTABLE_ITEM, tgid_obj); + } + } + } + spin_unlock_irqrestore(&creds_hash_update_lock, flags); + /* Free all pending pointers */ + if (free_buff1) + kmem_cache_free(mem_cache[CACHE_CRED_DATA].allocator, free_buff1); + if (free_buff2) + kmem_cache_free(mem_cache[(free_buff2->cred_flags & CRED_FLAGS_MAIN_UPDATED) ? \ + CACHE_CRED_DATA_ID : CACHE_CRED_DATA].allocator, free_buff2); + if (pid_obj) + kmem_cache_free(mem_cache[CACHE_HTABLE_ITEM].allocator, pid_obj); + if (tgid_obj) + kmem_cache_free(mem_cache[CACHE_HTABLE_ITEM].allocator, tgid_obj); + return; +} + +#else + +void set_task_creds_tcnt(struct task_struct *p, int addition) +{ + (void)p; + (void)addition; +} + +#endif /* DEFEX_PED_ENABLE */ diff --git a/security/defex_lsm/cert/defex_cert.S b/security/defex_lsm/cert/defex_cert.S new file mode 100755 index 000000000000..309bf2d3759b --- /dev/null +++ b/security/defex_lsm/cert/defex_cert.S @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + */ + +#include +#include +#include + + __INITRODATA + +.align 8 + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0) || !defined(VMLINUX_SYMBOL)) +#define VMLINUX_SYMBOL(name) name +#endif + +#define GLOBAL(name) \ + .globl VMLINUX_SYMBOL(name); \ + VMLINUX_SYMBOL(name): + + .section ".init.data","aw" + +GLOBAL(defex_public_key_start) +#ifdef DEFEX_DEBUG_ENABLE + .incbin "security/samsung/defex_lsm/cert/pubkey_eng.der" +#else + .incbin "security/samsung/defex_lsm/cert/pubkey_user.der" +#endif +GLOBAL(defex_public_key_end) diff --git a/security/defex_lsm/cert/defex_sign.c b/security/defex_lsm/cert/defex_sign.c new file mode 100755 index 000000000000..7d5c01f7cc04 --- /dev/null +++ b/security/defex_lsm/cert/defex_sign.c @@ -0,0 +1,275 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "include/defex_debug.h" +#include "include/defex_sign.h" + +#ifdef DEFEX_KUNIT_ENABLED +#include +#endif + +#define SIGN_SIZE 256 +#define SHA256_DIGEST_SIZE 32 +#define MAX_DATA_LEN 300 + +extern char defex_public_key_start[]; +extern char defex_public_key_end[]; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0) + +__visible_for_testing int __init defex_public_key_verify_signature(unsigned char *pub_key, + int pub_key_size, + unsigned char *signature, + unsigned char *hash_sha256) +{ + (void)pub_key; + (void)pub_key_size; + (void)signature; + (void)hash_sha256; + /* Skip signarue check at kernel version < 3.7.0 */ + printk("[DEFEX] Skip signature check in current kernel version\n"); + return 0; +} + +#else + +#include + +static struct key *defex_keyring; + +__visible_for_testing struct key* __init defex_keyring_alloc(const char *description, + kuid_t uid, kgid_t gid, + const struct cred *cred, + unsigned long flags) +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0) + return keyring_alloc(description, uid, gid, cred, flags, NULL) +#elif LINUX_VERSION_CODE < KERNEL_VERSION(4, 7, 0) + key_perm_t perm = ((KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_VIEW | KEY_USR_READ | KEY_USR_SEARCH); + return keyring_alloc(description, uid, gid, cred, perm, flags, NULL); +#else + key_perm_t perm = ((KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_VIEW | KEY_USR_READ | KEY_USR_SEARCH); + return keyring_alloc(description, uid, gid, cred, perm, flags, NULL, NULL); +#endif +} + +__visible_for_testing int __init defex_keyring_init(void) +{ + int err = 0; + const struct cred *cred = current_cred(); + static const char keyring_name[] = "defex_keyring"; + + defex_keyring = defex_keyring_alloc(keyring_name, KUIDT_INIT(0), KGIDT_INIT(0), + cred, KEY_ALLOC_NOT_IN_QUOTA); + if (!defex_keyring) { + err = -1; + pr_info("Can't allocate %s keyring (NULL)\n", keyring_name); + } else if (IS_ERR(defex_keyring)) { + err = PTR_ERR(defex_keyring); + pr_info("Can't allocate %s keyring, err=%d\n", keyring_name, err); + defex_keyring = NULL; + } + return err; +} + +__visible_for_testing int __init defex_public_key_verify_signature(unsigned char *pub_key, + int pub_key_size, + unsigned char *signature, + unsigned char *hash_sha256) +{ + int ret = -1; + key_ref_t key_ref; + struct key *key; + struct public_key_signature pks; + + if (defex_keyring_init() != 0) + return ret; + + key_ref = key_create_or_update(make_key_ref(defex_keyring, 1), + "asymmetric", + NULL, + pub_key, + pub_key_size, + ((KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_VIEW | KEY_USR_READ), + KEY_ALLOC_NOT_IN_QUOTA); + + if (IS_ERR(key_ref)) { + printk(KERN_INFO "Invalid key reference\n"); + return ret; + } + + key = key_ref_to_ptr(key_ref); + + memset(&pks, 0, sizeof(pks)); + pks.digest = hash_sha256; + pks.digest_size = SHA256_DIGEST_SIZE; +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 6, 0) + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0) + pks.pkey_algo = PKEY_ALGO_RSA; +#endif + pks.pkey_hash_algo = HASH_ALGO_SHA256; + pks.nr_mpi = 1; + pks.rsa.s = mpi_read_raw_data(signature, SIGN_SIZE); + if (pks.rsa.s) + ret = verify_signature(key, &pks); + mpi_free(pks.rsa.s); +#else + pks.pkey_algo = "rsa"; + pks.hash_algo = "sha256"; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0) + pks.encoding = "pkcs1"; +#endif + pks.s = signature; + pks.s_size = SIGN_SIZE; + ret = verify_signature(key, &pks); +#endif + key_ref_put(key_ref); + keyring_clear(defex_keyring); + return ret; +} +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0) */ + +#ifdef DEFEX_DEBUG_ENABLE +void __init blob(const char *buffer, const size_t bufLen, const int lineSize) +{ + size_t i = 0, line; + size_t j = 0, len = bufLen; + int offset = 0; + char c, stringToPrint[MAX_DATA_LEN]; + + do { + line = (len > lineSize)?lineSize:len; + offset = 0; + offset += snprintf(stringToPrint + offset, MAX_DATA_LEN - offset, "| 0x%0*zx | ", PR_HEX(i)); + + for(j = 0; j < line; j++) + offset += snprintf(stringToPrint + offset, MAX_DATA_LEN - offset, "%02X ", (unsigned char)buffer[i + j]); + if (line < lineSize) { + for(j = 0; j < lineSize - line; j++) + offset += snprintf(stringToPrint + offset, MAX_DATA_LEN - offset, " "); + } + offset += snprintf(stringToPrint + offset, MAX_DATA_LEN - offset, "| "); + + for(j = 0; j < line; j++) { + c = buffer[i + j]; + c = (c < 0x20)||(c >= 0x7F)?'.':c; + offset += snprintf(stringToPrint + offset, MAX_DATA_LEN - offset, "%c", c); + } + if (line < lineSize) { + for(j = 0; j < lineSize - line; j++) + offset += snprintf(stringToPrint + offset, MAX_DATA_LEN - offset, " "); + } + + offset += snprintf(stringToPrint + offset, MAX_DATA_LEN - offset, " |"); + printk(KERN_INFO "%s\n", stringToPrint); + memset(stringToPrint, 0, MAX_DATA_LEN); + i += line; + len -= line; + } while(len); +} +#endif + +int __init defex_calc_hash(const char *data, unsigned int size, unsigned char *hash) +{ + struct crypto_shash *handle; + struct shash_desc* shash; + int err = -1; + + handle = crypto_alloc_shash("sha256", 0, 0); + if (IS_ERR_OR_NULL(handle)) { + pr_err("[DEFEX] Can't alloc sha256"); + return err; + } + + shash = kzalloc(sizeof(struct shash_desc) + crypto_shash_descsize(handle), GFP_KERNEL); + if (!shash) + goto clean_handle; + + shash->tfm = handle; + + do { + err = crypto_shash_init(shash); + if (err < 0) + break; + + err = crypto_shash_update(shash, data, size); + if (err < 0) + break; + + err = crypto_shash_final(shash, hash); + if (err < 0) + break; + } while(0); + + kfree(shash); +clean_handle: + crypto_free_shash(handle); + return err; +} + +int __init defex_rules_signature_check(const char *rules_buffer, unsigned int rules_data_size, unsigned int *rules_size) +{ + int res = -1; + unsigned int defex_public_key_size = (unsigned int)((defex_public_key_end - defex_public_key_start) & 0xffffffff); + unsigned char *hash_sha256; + unsigned char *hash_sha256_first; + unsigned char *signature; + unsigned char *pub_key; + + if (rules_data_size < SIGN_SIZE) + return res; + hash_sha256_first = kmalloc(SHA256_DIGEST_SIZE, GFP_KERNEL); + if (!hash_sha256_first) + return res; + hash_sha256 = kmalloc(SHA256_DIGEST_SIZE, GFP_KERNEL); + if (!hash_sha256) + goto clean_hash_sha256_first; + signature = kmalloc(SIGN_SIZE, GFP_KERNEL); + if (!signature) + goto clean_hash_sha256; + pub_key = kmalloc(defex_public_key_size, GFP_KERNEL); + if (!pub_key) + goto clean_signature; + + memcpy(pub_key, defex_public_key_start, defex_public_key_size); + memcpy(signature, (u8*)(rules_buffer + rules_data_size - SIGN_SIZE), SIGN_SIZE); + + defex_calc_hash(rules_buffer, rules_data_size - SIGN_SIZE, hash_sha256_first); + defex_calc_hash(hash_sha256_first, SHA256_DIGEST_SIZE, hash_sha256); + +#ifdef DEFEX_DEBUG_ENABLE + printk("[DEFEX] Rules signature size = %d\n", SIGN_SIZE); + blob(signature, SIGN_SIZE, 16); + printk("[DEFEX] Key size = %d\n", defex_public_key_size); + blob(pub_key, defex_public_key_size, 16); + printk("[DEFEX] Final Hash:\n"); + blob(hash_sha256, SHA256_DIGEST_SIZE, 16); +#endif + + res = defex_public_key_verify_signature(pub_key, defex_public_key_size, signature, hash_sha256); + if (rules_size && !res) + *rules_size = rules_data_size - SIGN_SIZE; + kfree(pub_key); +clean_signature: + kfree(signature); +clean_hash_sha256: + kfree(hash_sha256); +clean_hash_sha256_first: + kfree(hash_sha256_first); + return res; +} diff --git a/security/defex_lsm/cert/x509_five_eng.der b/security/defex_lsm/cert/x509_five_eng.der new file mode 100755 index 000000000000..2dfd0ad73583 Binary files /dev/null and b/security/defex_lsm/cert/x509_five_eng.der differ diff --git a/security/defex_lsm/cert/x509_five_user.der b/security/defex_lsm/cert/x509_five_user.der new file mode 100755 index 000000000000..7c15ba096276 Binary files /dev/null and b/security/defex_lsm/cert/x509_five_user.der differ diff --git a/security/defex_lsm/core/defex_common.c b/security/defex_lsm/core/defex_common.c new file mode 100755 index 000000000000..a05b36a31b9c --- /dev/null +++ b/security/defex_lsm/core/defex_common.c @@ -0,0 +1,327 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "include/defex_caches.h" +#include "include/defex_catch_list.h" +#include "include/defex_config.h" +#include "include/defex_internal.h" +#include "include/defex_rules.h" + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0) +#include +#include +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 19, 0) + +inline ssize_t __vfs_read(struct file *file, char __user *buf, + size_t count, loff_t *pos) +{ + ssize_t ret; + + if (file->f_op->read) + ret = file->f_op->read(file, buf, count, pos); + else if (file->f_op->aio_read) + ret = do_sync_read(file, buf, count, pos); + else if (file->f_op->read_iter) + ret = new_sync_read(file, buf, count, pos); + else + ret = -EINVAL; + + return ret; +} +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0) +#define GET_KERNEL_DS KERNEL_DS +#else +#define GET_KERNEL_DS get_ds() +#endif + +struct file *local_fopen(const char *fname, int flags, umode_t mode) +{ + struct file *f; + mm_segment_t old_fs; + + old_fs = get_fs(); + set_fs(GET_KERNEL_DS); + f = filp_open(fname, flags, mode); + set_fs(old_fs); + return f; +} + +int local_fread(struct file *f, loff_t offset, void *ptr, unsigned long bytes) +{ + mm_segment_t old_fs; + char __user *buf = (char __user *)ptr; + ssize_t ret; + + if (!(f->f_mode & FMODE_READ)) + return -EBADF; + + old_fs = get_fs(); + set_fs(GET_KERNEL_DS); + ret = __vfs_read(f, buf, bytes, &offset); + set_fs(old_fs); + return (int)ret; +} + +const char unknown_file[] = ""; + +void init_defex_context(struct defex_context *dc, int syscall, struct task_struct *p, struct file *f) +{ + const struct cred *cred_ptr; + + memset(dc, 0, sizeof(struct defex_context) - sizeof(struct cred)); + if (!IS_ERR_OR_NULL(f)) { + get_file(f); + dc->target_file = f; + } + dc->syscall_no = syscall; + dc->task = p; + if (p == current) + cred_ptr = get_current_cred(); + else + cred_ptr = get_task_cred(p); + memcpy(&dc->cred, cred_ptr, sizeof(struct cred)); + put_cred(cred_ptr); +} + +void release_defex_context(struct defex_context *dc) +{ + kfree(dc->process_name_buff); + kfree(dc->target_name_buff); + if (dc->target_file) + fput(dc->target_file); +#ifndef DEFEX_CACHES_ENABLE + if (dc->process_file) + fput(dc->process_file); +#endif /* DEFEX_CACHES_ENABLE */ +} + +struct file *get_dc_process_file(struct defex_context *dc) +{ + if (!dc->process_file) + dc->process_file = defex_get_source_file(dc->task); + return dc->process_file; +} + +const struct path *get_dc_process_dpath(struct defex_context *dc) +{ + const struct path *dpath; + struct file *exe_file = NULL; + + if (dc->process_dpath) + return dc->process_dpath; + + exe_file = get_dc_process_file(dc); + if (!IS_ERR_OR_NULL(exe_file)) { + dpath = &exe_file->f_path; + if (dpath->dentry && dpath->dentry->d_inode) { + dc->process_dpath = dpath; + return dpath; + } + } + return NULL; +} + +char *get_dc_process_name(struct defex_context *dc) +{ + const struct path *dpath; + char *path = NULL; + + if (!dc->process_name) { + dpath = get_dc_process_dpath(dc); + if (dpath) { + dc->process_name_buff = kmalloc(PATH_MAX, GFP_KERNEL); + if (dc->process_name_buff) + path = d_path(dpath, dc->process_name_buff, PATH_MAX); + } + dc->process_name = (IS_ERR_OR_NULL(path)) ? (char *)unknown_file : path; + } + return dc->process_name; +} + +const struct path *get_dc_target_dpath(struct defex_context *dc) +{ + const struct path *dpath; + + if (dc->target_dpath) + return dc->target_dpath; + + if (dc->target_file) { + dpath = &(dc->target_file->f_path); + if (dpath->dentry && dpath->dentry->d_inode) { + dc->target_dpath = dpath; + return dpath; + } + } + return NULL; +} + +char *get_dc_target_name(struct defex_context *dc) +{ + const struct path *dpath; + char *path = NULL; + + if (!dc->target_name) { + dpath = get_dc_target_dpath(dc); + if (dpath) { + dc->target_name_buff = kmalloc(PATH_MAX, GFP_KERNEL); + if (dc->target_name_buff) + path = d_path(dpath, dc->target_name_buff, PATH_MAX); + } + dc->target_name = (IS_ERR_OR_NULL(path)) ? (char *)unknown_file : path; + } + return dc->target_name; +} + +struct file *defex_get_source_file(struct task_struct *p) +{ + struct file *file_addr = NULL; + struct mm_struct *proc_mm; + +#ifdef DEFEX_CACHES_ENABLE + bool self; + file_addr = defex_file_cache_find(p->pid); + + if (!file_addr) { + proc_mm = get_task_mm(p); + if (!proc_mm) + return NULL; + file_addr = get_mm_exe_file(proc_mm); + mmput(proc_mm); + if (!file_addr) + return NULL; + defex_file_cache_add(p->pid, file_addr); + } else { + self = (p == current); + proc_mm = (self)?p->mm:get_task_mm(p); + if (!proc_mm) + return NULL; + if (self) + down_read(&proc_mm->mmap_sem); + if (file_addr != proc_mm->exe_file) { + file_addr = proc_mm->exe_file; + if (!file_addr) + goto clean_mm; + get_file(file_addr); + defex_file_cache_update(file_addr); + } +clean_mm: + if (self) + up_read(&proc_mm->mmap_sem); + else + mmput(proc_mm); + } +#else + + proc_mm = get_task_mm(p); + if (!proc_mm) + return NULL; + file_addr = get_mm_exe_file(proc_mm); + mmput(proc_mm); +#endif /* DEFEX_CACHES_ENABLE */ + return file_addr; +} + +char *defex_get_filename(struct task_struct *p) +{ + struct file *exe_file = NULL; + const struct path *dpath = NULL; + char *path = NULL, *buff = NULL; + char *filename = NULL; + + exe_file = defex_get_source_file(p); + if (!exe_file) + goto out_filename; + + dpath = &exe_file->f_path; + + buff = kmalloc(PATH_MAX, GFP_KERNEL); + if (buff) + path = d_path(dpath, buff, PATH_MAX); + +#ifndef DEFEX_CACHES_ENABLE + fput(exe_file); +#endif /* DEFEX_CACHES_ENABLE */ + +out_filename: + if (path && !IS_ERR(path)) + filename = kstrdup(path, GFP_KERNEL); + + if (!filename) + filename = (char *)unknown_file; + + if (buff) + kfree(buff); + return filename; +} + +/* Resolve the filename to absolute path, follow the links + name - input file name + out_buff - output pointer to the allocated buffer (should be freed) + Returns: pointer to resolved filename or NULL + */ +char* defex_resolve_filename(const char *name, char **out_buff) +{ + char *target_file = NULL, *buff = NULL; + struct path path; + + if (*out_buff) + buff = *out_buff; + else + buff = kmalloc(PATH_MAX, GFP_KERNEL); + if (buff) { + if (!kern_path(name, LOOKUP_FOLLOW, &path)) { + target_file = d_path(&path, buff, PATH_MAX); + path_put(&path); + } + if (IS_ERR_OR_NULL(target_file)) { + kfree(buff); + buff = NULL; + target_file = NULL; + } + } + *out_buff = buff; + return target_file; +} + +int defex_files_identical(const struct file *f1, const struct file *f2) +{ + const struct path *dpath1, *dpath2; + const struct inode *inode1, *inode2; + + if (f1 && f2) { + dpath1 = &f1->f_path; + dpath2 = &f2->f_path; + if (dpath1->dentry && dpath2->dentry) { + inode1 = dpath1->dentry->d_inode; + inode2 = dpath2->dentry->d_inode; + return (inode1 == inode2); + } + } + return 0; +} diff --git a/security/defex_lsm/defex_config.c b/security/defex_lsm/core/defex_get_mode.c similarity index 78% rename from security/defex_lsm/defex_config.c rename to security/defex_lsm/core/defex_get_mode.c index 17103b4f0d06..ca62067502c7 100755 --- a/security/defex_lsm/defex_config.c +++ b/security/defex_lsm/core/defex_get_mode.c @@ -40,5 +40,16 @@ int defex_get_features(void) features |= FEATURE_SAFEPLACE_SOFT; #endif /* DEFEX_PERMISSIVE_SP */ #endif /* DEFEX_SAFEPLACE_ENABLE */ + +#ifdef DEFEX_IMMUTABLE_ENABLE +#if !defined(DEFEX_PERMISSIVE_IM) + features |= GLOBAL_IMMUTABLE_STATUS; +#else + if (global_immutable_obj->status != 0) + features |= FEATURE_IMMUTABLE; + if (global_immutable_obj->status == 2) + features |= FEATURE_IMMUTABLE_SOFT; +#endif /* DEFEX_PERMISSIVE_IM */ +#endif /* DEFEX_IMMUTABLE_ENABLE */ return features; } diff --git a/security/defex_lsm/defex_lsm.c b/security/defex_lsm/core/defex_lsm.c similarity index 90% rename from security/defex_lsm/defex_lsm.c rename to security/defex_lsm/core/defex_lsm.c index facc7d36ba31..e807e7ca1afd 100755 --- a/security/defex_lsm/defex_lsm.c +++ b/security/defex_lsm/core/defex_lsm.c @@ -6,7 +6,7 @@ * as published by the Free Software Foundation. */ -#include +#include #include #include #include @@ -50,17 +50,16 @@ asmlinkage int defex_syscall_enter(long int syscallno, struct pt_regs *regs) } //INIT///////////////////////////////////////////////////////////////////////// -static __init int defex_lsm_init(void) +__visible_for_testing int __init defex_lsm_init(void) { int ret; #ifdef DEFEX_CACHES_ENABLE defex_file_cache_init(); #endif /* DEFEX_CACHES_ENABLE */ - creds_fast_hash_init(); #ifdef DEFEX_PED_ENABLE - hash_init(creds_hash); + creds_fast_hash_init(); #endif /* DEFEX_PED_ENABLE */ ret = defex_init_sysfs(); @@ -70,6 +69,10 @@ static __init int defex_lsm_init(void) } printk(KERN_INFO "DEFEX_LSM started"); +#ifdef DEFEX_LP_ENABLE + printk(KERN_INFO "[DEFEX] ADB LP Enabled"); +#endif /* DEFEX_LP_ENABLE */ + return 0; } diff --git a/security/defex_lsm/core/defex_main.c b/security/defex_lsm/core/defex_main.c new file mode 100755 index 000000000000..1afe55fd845c --- /dev/null +++ b/security/defex_lsm/core/defex_main.c @@ -0,0 +1,640 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + */ + +#include +#include +#include +#ifdef DEFEX_DSMS_ENABLE +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef DEFEX_DSMS_ENABLE +#include +#endif +#include +#include +#include +#include +#include "include/defex_caches.h" +#include "include/defex_catch_list.h" +#include "include/defex_config.h" +#include "include/defex_internal.h" +#include "include/defex_rules.h" + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0) +#include +#include +#endif + +#ifdef DEFEX_DEPENDING_ON_OEMUNLOCK +bool boot_state_unlocked __ro_after_init; +__visible_for_testing int __init verifiedboot_state_setup(char *str) +{ + static const char unlocked[] = "orange"; + + boot_state_unlocked = !strncmp(str, unlocked, sizeof(unlocked)); + + if(boot_state_unlocked) + pr_crit("Device is unlocked and DEFEX will be disabled."); + + return 0; +} + +__setup("androidboot.verifiedbootstate=", verifiedboot_state_setup); + +int warranty_bit __ro_after_init; +__visible_for_testing int __init get_warranty_bit(char *str) +{ + get_option(&str, &warranty_bit); + + return 0; +} + +__setup("androidboot.warranty_bit=", get_warranty_bit); +#endif /* DEFEX_DEPENDING_ON_OEMUNLOCK */ + +__visible_for_testing struct task_struct *get_parent_task(const struct task_struct *p) +{ + struct task_struct *parent = NULL; + + read_lock(&tasklist_lock); + parent = p->parent; + if (parent) + get_task_struct(parent); + read_unlock(&tasklist_lock); + return parent; +} + +#ifdef DEFEX_DSMS_ENABLE + +# define PED_VIOLATION "DFX1" +# define SAFEPLACE_VIOLATION "DFX2" +# define INTEGRITY_VIOLATION "DFX3" +# define IMMUTABLE_VIOLATION "DFX4" +# define MESSAGE_BUFFER_SIZE 200 +# define STORED_CREDS_SIZE 100 + +__visible_for_testing void defex_report_violation(const char *violation, uint64_t counter, struct defex_context *dc, + uid_t stored_uid, uid_t stored_fsuid, uid_t stored_egid, int case_num) +{ + int usermode_result; + char message[MESSAGE_BUFFER_SIZE + 1]; + + struct task_struct *parent = NULL, *p = dc->task; + const uid_t uid = uid_get_value(dc->cred.uid); + const uid_t euid = uid_get_value(dc->cred.euid); + const uid_t fsuid = uid_get_value(dc->cred.fsuid); + const uid_t egid = uid_get_value(dc->cred.egid); + const char *process_name = p->comm; + const char *prt_process_name = NULL; + const char *program_path = get_dc_process_name(dc); + char *prt_program_path = NULL; + char *file_path = NULL; + char stored_creds[STORED_CREDS_SIZE + 1]; + + parent = get_parent_task(p); + if (!parent) + return; + + prt_process_name = parent->comm; + prt_program_path = defex_get_filename(parent); + + if (dc->target_file && !case_num) { + file_path = get_dc_target_name(dc); + } else { + snprintf(stored_creds, sizeof(stored_creds), "[%ld, %ld, %ld]", (long)stored_uid, (long)stored_fsuid, (long)stored_egid); + stored_creds[sizeof(stored_creds) - 1] = 0; + } +#ifdef DEFEX_DEPENDING_ON_OEMUNLOCK + snprintf(message, sizeof(message), "%d, %d, sc=%d, tsk=%s(%s), %s(%s), [%ld %ld %ld %ld], %s%s, %d", warranty_bit, boot_state_unlocked, dc->syscall_no, process_name, program_path, prt_process_name, + prt_program_path, (long)uid, (long)euid, (long)fsuid, (long)egid, + (file_path ? "file=" : "stored "), (file_path ? file_path : stored_creds), case_num); +#else + snprintf(message, sizeof(message), "sc=%d, tsk=%s(%s), %s(%s), [%ld %ld %ld %ld], %s%s, %d", + dc->syscall_no, process_name, program_path, prt_process_name, + prt_program_path, (long)uid, (long)euid, (long)fsuid, (long)egid, + (file_path ? "file=" : "stored "), (file_path ? file_path : stored_creds), case_num); +#endif + message[sizeof(message) - 1] = 0; + + usermode_result = dsms_send_message(violation, message, counter); +#ifdef DEFEX_DEBUG_ENABLE + printk(KERN_ERR "DEFEX Violation : feature=%s value=%ld, detail=[%s]", violation, (long)counter, message); + printk(KERN_ERR "DEFEX Result : %d\n", usermode_result); +#endif /* DEFEX_DEBUG_ENABLE */ + + safe_str_free(prt_program_path); + put_task_struct(parent); +} +#endif /* DEFEX_DSMS_ENABLE */ + +#ifdef DEFEX_SAFEPLACE_ENABLE +__visible_for_testing long kill_process(struct task_struct *p) +{ + read_lock(&tasklist_lock); + send_sig(SIGKILL, p, 0); + read_unlock(&tasklist_lock); + return 0; +} +#endif /* DEFEX_SAFEPLACE_ENABLE */ + +#ifdef DEFEX_PED_ENABLE +__visible_for_testing long kill_process_group(struct task_struct *p, int tgid, int pid) +{ + read_lock(&tasklist_lock); + for_each_process(p) { + if (p->tgid == tgid) + send_sig(SIGKILL, p, 0); + } + send_sig(SIGKILL, current, 0); + read_unlock(&tasklist_lock); + return 0; +} + +__visible_for_testing int task_defex_is_secured(struct defex_context *dc) +{ + struct file *exe_file = get_dc_process_file(dc); + struct task_struct *p = dc->task->group_leader; + char *proc_name = get_dc_process_name(dc); + int is_secured = 1; + + if (!get_dc_process_dpath(dc)) + return is_secured; + + if (!strncmp(p->comm, "system_server", strlen(p->comm))) { + return DEFEX_ALLOW; + } + + if (!strncmp(p->comm, "ding:background", strlen(p->comm))) { + return DEFEX_ALLOW; + } + + is_secured = !rules_lookup2(proc_name, feature_ped_exception, exe_file); + return is_secured; +} + +__visible_for_testing int at_same_group(unsigned int uid1, unsigned int uid2) +{ + static const unsigned int lod_base = 0x61A8; + + /* allow the weaken privilege */ + if (uid1 >= 10000 && uid2 < 10000) return 1; + /* allow traverse in the same class */ + if ((uid1 / 1000) == (uid2 / 1000)) return 1; + /* allow traverse to isolated ranges */ + if (uid1 >= 90000) return 1; + /* allow LoD process */ + return ((uid1 >> 16) == lod_base) && ((uid2 >> 16) == lod_base); +} + +__visible_for_testing int at_same_group_gid(unsigned int gid1, unsigned int gid2) +{ + static const unsigned int lod_base = 0x61A8, inet = 3003; + + /* allow the weaken privilege */ + if (gid1 >= 10000 && gid2 < 10000) return 1; + /* allow traverse in the same class */ + if ((gid1 / 1000) == (gid2 / 1000)) return 1; + /* allow traverse to isolated ranges */ + if (gid1 >= 90000) return 1; + /* allow LoD process */ + return (((gid1 >> 16) == lod_base) || (gid1 == inet)) && ((gid2 >> 16) == lod_base); +} + +#ifdef DEFEX_LP_ENABLE +/* Lower Permission feature decision function */ +__visible_for_testing int lower_adb_permission(struct defex_context *dc, unsigned short cred_flags) +{ + char *parent_file; + struct task_struct *parent = NULL, *p = dc->task; +#ifndef DEFEX_PERMISSIVE_LP + struct cred *shellcred; + static const char adbd_str[] = "/system/bin/adbd"; +#endif /* DEFEX_PERMISSIVE_LP */ + int ret = 0; + + parent = get_parent_task(p); + if (!parent || p->pid == 1 || parent->pid == 1) + goto out; + + parent_file = defex_get_filename(parent); + +#ifndef DEFEX_PERMISSIVE_LP + if (!strncmp(parent_file, adbd_str, sizeof(adbd_str))) { + shellcred = prepare_creds(); + pr_crit("[DEFEX] adb with root"); + if (!shellcred) { + pr_crit("[DEFEX] prepare_creds fail"); + ret = 0; + goto out; + } + + uid_set_value(shellcred->uid, 2000); + uid_set_value(shellcred->suid, 2000); + uid_set_value(shellcred->euid, 2000); + uid_set_value(shellcred->fsuid, 2000); + uid_set_value(shellcred->gid, 2000); + uid_set_value(shellcred->sgid, 2000); + uid_set_value(shellcred->egid, 2000); + uid_set_value(shellcred->fsgid, 2000); + commit_creds(shellcred); + memcpy(&dc->cred, shellcred, sizeof(struct cred)); + set_task_creds(p, 2000, 2000, 2000, cred_flags); + + ret = 1; + } +#endif /* DEFEX_PERMISSIVE_LP */ + + safe_str_free(parent_file); +out: + if (parent) + put_task_struct(parent); + return ret; +} +#endif /* DEFEX_LP_ENABLE */ + +/* Cred. violation feature decision function */ +#define AID_MEDIA_RW 1023 +#define AID_MEDIA_OBB 1059 +#define AID_SYSTEM 1000 + +__visible_for_testing int task_defex_check_creds(struct defex_context *dc) +{ + char *path = NULL; + int check_deeper, case_num; + unsigned int cur_uid, cur_euid, cur_fsuid, cur_egid; + unsigned int ref_uid, ref_fsuid, ref_egid; + struct task_struct *parent, *p = dc->task; + unsigned short cred_flags; + const struct cred *parent_cred; + static const unsigned int dead_uid = 0xDEADBEAF; + + if (!is_task_creds_ready() || !p->cred) + goto out; + + get_task_creds(p, &ref_uid, &ref_fsuid, &ref_egid, &cred_flags); + + cur_uid = uid_get_value(dc->cred.uid); + cur_euid = uid_get_value(dc->cred.euid); + cur_fsuid = uid_get_value(dc->cred.fsuid); + cur_egid = uid_get_value(dc->cred.egid); + + if (!ref_uid) { + if (p->tgid != p->pid && p->tgid != 1) { + path = get_dc_process_name(dc); + pr_crit("defex[6]: cred wasn't stored [task=%s, filename=%s, uid=%d, tgid=%u, pid=%u, ppid=%u]\n", + p->comm, path, cur_uid, p->tgid, p->pid, p->real_parent->pid); + pr_crit("defex[6]: stored [euid=%d fsuid=%d egid=%d] current [uid=%d euid=%d fsuid=%d egid=%d]\n", + ref_uid, ref_fsuid, ref_egid, cur_uid, cur_euid, cur_fsuid, cur_egid); + goto exit; + } + + parent = get_parent_task(p); + if (parent) { + parent_cred = get_task_cred(parent); + if (CHECK_ROOT_CREDS(parent_cred)) + cred_flags |= CRED_FLAGS_PROOT; + put_cred(parent_cred); + put_task_struct(parent); + } + + if (CHECK_ROOT_CREDS(&dc->cred)) { +#ifdef DEFEX_LP_ENABLE + if (!lower_adb_permission(dc, cred_flags)) +#endif /* DEFEX_LP_ENABLE */ + { + set_task_creds(p, 1, 1, 1, cred_flags); + } + } + else + set_task_creds(p, cur_euid, cur_fsuid, cur_egid, cred_flags); + } else if (ref_uid == 1) { + if (!CHECK_ROOT_CREDS(&dc->cred)) + set_task_creds(p, cur_euid, cur_fsuid, cur_egid, cred_flags); + } else if (ref_uid == dead_uid) { + path = get_dc_process_name(dc); + pr_crit("defex[5]: process wasn't killed [task=%s, filename=%s, uid=%d, tgid=%u, pid=%u, ppid=%u]\n", + p->comm, path, cur_uid, p->tgid, p->pid, p->real_parent->pid); + pr_crit("defex[5]: stored [euid=%d fsuid=%d egid=%d] current [uid=%d euid=%d fsuid=%d egid=%d]\n", + ref_uid, ref_fsuid, ref_egid, cur_uid, cur_euid, cur_fsuid, cur_egid); + goto exit; + } else { + check_deeper = 0; + /* temporary allow fsuid changes to "media_rw" */ + if ( (cur_uid != ref_uid) || + (cur_euid != ref_uid) || + (cur_egid != ref_egid) || + !((cur_fsuid == ref_fsuid) || + (cur_fsuid == ref_uid) || + (cur_fsuid%100000 == AID_SYSTEM) || + (cur_fsuid%100000 == AID_MEDIA_RW) || + (cur_fsuid%100000 == AID_MEDIA_OBB)) ) { + check_deeper = 1; + if (CHECK_ROOT_CREDS(&dc->cred)) + set_task_creds(p, 1, 1, 1, cred_flags); + else + set_task_creds(p, cur_euid, cur_fsuid, cur_egid, cred_flags); + } + if (check_deeper && + (!at_same_group(cur_uid, ref_uid) || + !at_same_group(cur_euid, ref_uid) || + !at_same_group_gid(cur_egid, ref_egid) || + !at_same_group(cur_fsuid, ref_fsuid)) && + task_defex_is_secured(dc)) { + case_num = ((p->tgid == p->pid) ? 1 : 2); + goto trigger_violation; + } + } + + if (CHECK_ROOT_CREDS(&dc->cred) && !(cred_flags & CRED_FLAGS_PROOT) && task_defex_is_secured(dc)) { + if (p->tgid != p->pid) { + case_num = 3; + goto trigger_violation; + } + case_num = 4; + goto trigger_violation; + } + +out: + return DEFEX_ALLOW; + +trigger_violation: + set_task_creds(p, dead_uid, dead_uid, dead_uid, cred_flags); + path = get_dc_process_name(dc); + pr_crit("defex[%d]: credential violation [task=%s, filename=%s, uid=%d, tgid=%u, pid=%u, ppid=%u]\n", + case_num, p->comm, path, cur_uid, p->tgid, p->pid, p->real_parent->pid); + pr_crit("defex[%d]: stored [euid=%d fsuid=%d egid=%d] current [uid=%d euid=%d fsuid=%d egid=%d]\n", + case_num, ref_uid, ref_fsuid, ref_egid, cur_uid, cur_euid, cur_fsuid, cur_egid); + +#ifdef DEFEX_DSMS_ENABLE + defex_report_violation(PED_VIOLATION, 0, dc, ref_uid, ref_fsuid, ref_egid, case_num); +#endif /* DEFEX_DSMS_ENABLE */ + +exit: + return -DEFEX_DENY; +} +#endif /* DEFEX_PED_ENABLE */ + +#ifdef DEFEX_SAFEPLACE_ENABLE +/* Safeplace feature decision function */ +__visible_for_testing int task_defex_safeplace(struct defex_context *dc) +{ + int ret = DEFEX_ALLOW, is_violation = 0; + char *proc_file, *new_file; + struct task_struct *p = dc->task; + + if (!CHECK_ROOT_CREDS(&dc->cred)) + goto out; + + if (!get_dc_target_dpath(dc)) + goto out; + + new_file = get_dc_target_name(dc); + is_violation = rules_lookup2(new_file, feature_safeplace_path, dc->target_file); +#ifdef DEFEX_INTEGRITY_ENABLE + if (is_violation != DEFEX_INTEGRITY_FAIL) +#endif /* DEFEX_INTEGRITY_ENABLE */ + is_violation = !is_violation; + + if (is_violation) { + ret = -DEFEX_DENY; + proc_file = get_dc_process_name(dc); + +#ifdef DEFEX_INTEGRITY_ENABLE + if (is_violation == DEFEX_INTEGRITY_FAIL) { + pr_crit("defex: integrity violation [task=%s (%s), child=%s, uid=%d]\n", + p->comm, proc_file, new_file, uid_get_value(dc->cred.uid)); +#ifdef DEFEX_DSMS_ENABLE + defex_report_violation(INTEGRITY_VIOLATION, 0, dc, 0, 0, 0, 0); +#endif /* DEFEX_DSMS_ENABLE */ + + /* Temporary make permissive mode for tereble + * system image is changed as google's and defex might not work + */ + ret = DEFEX_ALLOW; + } + else +#endif /* DEFEX_INTEGRITY_ENABLE */ + { + pr_crit("defex: safeplace violation [task=%s (%s), child=%s, uid=%d]\n", + p->comm, proc_file, new_file, uid_get_value(dc->cred.uid)); +#ifdef DEFEX_DSMS_ENABLE + defex_report_violation(SAFEPLACE_VIOLATION, 0, dc, 0, 0, 0, 0); +#endif /* DEFEX_DSMS_ENABLE */ + } + } +out: + return ret; +} +#endif /* DEFEX_SAFEPLACE_ENABLE */ + +#ifdef DEFEX_IMMUTABLE_ENABLE + +/* Immutable feature decision function */ +__visible_for_testing int task_defex_src_exception(struct defex_context *dc) +{ + struct file *exe_file = get_dc_process_file(dc); + char *proc_name = get_dc_process_name(dc); + int allow = 1; + + if (!get_dc_process_dpath(dc)) + return allow; + + exe_file = get_dc_process_file(dc); + allow = rules_lookup2(proc_name, feature_immutable_src_exception, exe_file); + return allow; +} + +/* Immutable feature decision function */ +__visible_for_testing int task_defex_immutable(struct defex_context *dc, int attribute) +{ + int ret = DEFEX_ALLOW, is_violation = 0; + char *proc_file, *new_file; + struct task_struct *p = dc->task; + + if (!get_dc_target_dpath(dc)) + goto out; + + new_file = get_dc_target_name(dc); + is_violation = rules_lookup2(new_file, attribute, dc->target_file); + + if (is_violation) { + /* Check the Source exception and self-access */ + if (attribute == feature_immutable_path_open && + (task_defex_src_exception(dc) || + defex_files_identical(get_dc_process_file(dc), dc->target_file))) + goto out; + + ret = -DEFEX_DENY; + proc_file = get_dc_process_name(dc); + pr_crit("defex: immutable %s violation [task=%s (%s), access to:%s]\n", + (attribute==feature_immutable_path_open)?"open":"write", p->comm, proc_file, new_file); +#ifdef DEFEX_DSMS_ENABLE + defex_report_violation(IMMUTABLE_VIOLATION, 0, dc, 0, 0, 0, 0); +#endif /* DEFEX_DSMS_ENABLE */ + } +out: + return ret; +} +#endif /* DEFEX_IMMUTABLE_ENABLE */ + +/* Main decision function */ +int task_defex_enforce(struct task_struct *p, struct file *f, int syscall) +{ + int ret = DEFEX_ALLOW; + int feature_flag; + const struct local_syscall_struct *item; + struct defex_context dc; + +#ifdef DEFEX_DEPENDING_ON_OEMUNLOCK + if(boot_state_unlocked) + return ret; +#endif /* DEFEX_DEPENDING_ON_OEMUNLOCK */ + + if (!p || p->pid == 1 || !p->mm) + return ret; + + if (syscall < 0) { + item = get_local_syscall(-syscall); + if (!item) + return ret; + syscall = item->local_syscall; + } + + feature_flag = defex_get_features(); + get_task_struct(p); + init_defex_context(&dc, syscall, p, f); + +#ifdef DEFEX_PED_ENABLE + /* Credential escalation feature */ + if (feature_flag & FEATURE_CHECK_CREDS) { + ret = task_defex_check_creds(&dc); + if (ret) { + if (!(feature_flag & FEATURE_CHECK_CREDS_SOFT)) { + kill_process_group(p, p->tgid, p->pid); + goto do_deny; + } + } + } +#endif /* DEFEX_PED_ENABLE */ + +#ifdef DEFEX_SAFEPLACE_ENABLE + /* Safeplace feature */ + if (feature_flag & FEATURE_SAFEPLACE) { + if (syscall == __DEFEX_execve) { + ret = task_defex_safeplace(&dc); + if (ret == -DEFEX_DENY) { + if (!(feature_flag & FEATURE_SAFEPLACE_SOFT)) { + kill_process(p); + goto do_deny; + } + } + } + } +#endif /* DEFEX_SAFEPLACE_ENABLE */ + +#ifdef DEFEX_IMMUTABLE_ENABLE + /* Immutable feature */ + if (feature_flag & FEATURE_IMMUTABLE) { + if (syscall == __DEFEX_openat || syscall == __DEFEX_write) { + ret = task_defex_immutable(&dc, + (syscall == __DEFEX_openat)?feature_immutable_path_open:feature_immutable_path_write); + if (ret == -DEFEX_DENY) { + if (!(feature_flag & FEATURE_IMMUTABLE_SOFT)) { + goto do_deny; + } + } + } + } +#endif /* DEFEX_IMMUTABLE_ENABLE */ + release_defex_context(&dc); + put_task_struct(p); + return DEFEX_ALLOW; + +do_deny: + release_defex_context(&dc); + put_task_struct(p); + return -DEFEX_DENY; +} + +int task_defex_zero_creds(struct task_struct *tsk) +{ + int is_fork = -1; + get_task_struct(tsk); + if (tsk->flags & (PF_KTHREAD | PF_WQ_WORKER)) { + put_task_struct(tsk); + return 0; + } + if (is_task_creds_ready()) { + is_fork = ((tsk->flags & PF_FORKNOEXEC) && (!READ_ONCE(tsk->on_rq))); +#ifdef TASK_NEW + if (!is_fork && (tsk->state & TASK_NEW)) + is_fork = 1; +#endif /* TASK_NEW */ + set_task_creds_tcnt(tsk, is_fork?1:-1); + } + +#ifdef DEFEX_CACHES_ENABLE + defex_file_cache_delete(tsk->pid); +#endif /* DEFEX_CACHES_ENABLE */ + put_task_struct(tsk); + return 0; +} + +static unsigned int rules_load_cnt = 0; +int task_defex_user_exec(const char *new_file) +{ +#ifdef DEFEX_UMH_RESTRICTION_ENABLE + int res = DEFEX_DENY, is_violation = DEFEX_DENY; + struct file *fp = NULL; + +#ifdef DEFEX_DEPENDING_ON_OEMUNLOCK + if(boot_state_unlocked) + return DEFEX_ALLOW; +#endif /* DEFEX_DEPENDING_ON_OEMUNLOCK */ + + if (!check_rules_ready()) { + if (rules_load_cnt++%100 == 0) + printk("[DEFEX] Rules not ready\n"); + goto umh_out; + } + + if (current == NULL || current->fs == NULL) { + goto umh_out; + } + + fp = local_fopen(new_file, O_RDONLY, 0); + if (IS_ERR(fp) || (fp == NULL)) { + goto umh_out; + } else { + filp_close(fp, NULL); + } + + is_violation = !rules_lookup2(new_file, feature_umhbin_path, NULL); + if (is_violation) { + printk("[DEFEX] UMH Exec Denied: %s\n", new_file); + goto umh_out; + } + + res = DEFEX_ALLOW; +umh_out: + return res; +#else + return DEFEX_ALLOW; +#endif /* DEFEX_UMH_RESTRICTION_ENABLE */ +} diff --git a/security/defex_lsm/core/defex_sysfs.c b/security/defex_lsm/core/defex_sysfs.c new file mode 100755 index 000000000000..7460ec0008c1 --- /dev/null +++ b/security/defex_lsm/core/defex_sysfs.c @@ -0,0 +1,591 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "include/defex_debug.h" +#include "include/defex_internal.h" +#include "include/defex_rules.h" + +#define DEFEX_RULES_FILE "/dpolicy" + +#ifndef DEFEX_USE_PACKED_RULES +/* + * Variant 1: Use the static, unpacked rules array + */ +#ifdef DEFEX_INTEGRITY_ENABLE +#error "Packed rules required for Integrity feature" +#endif + +#else + +/* + * Variant 2: Platform build, use static packed rules array + */ +#include "defex_packed_rules.inc" + +#ifdef DEFEX_RAMDISK_ENABLE +/* + * Variant 3: Platform build, load rules from kernel ramdisk or system partition + */ +#ifdef DEFEX_SIGN_ENABLE +#include "include/defex_sign.h" +#endif +#if (DEFEX_RULES_ARRAY_SIZE < 8) +#undef DEFEX_RULES_ARRAY_SIZE +#define DEFEX_RULES_ARRAY_SIZE sizeof(struct rule_item_struct) +#endif +#ifdef DEFEX_KERNEL_ONLY +#undef DEFEX_RULES_ARRAY_SIZE +#define DEFEX_RULES_ARRAY_SIZE (256 * 1024) +static unsigned char defex_packed_rules[DEFEX_RULES_ARRAY_SIZE] = {0}; +int load_rules_late(void); +#else +static unsigned char defex_packed_rules[DEFEX_RULES_ARRAY_SIZE] __ro_after_init = {0}; +#endif /* DEFEX_KERNEL_ONLY */ +#endif /* DEFEX_RAMDISK_ENABLE */ + +#endif /* DEFEX_USE_PACKED_RULES */ + +#ifdef DEFEX_INTEGRITY_ENABLE + +#include +#include +#include +#include +#include "../../integrity/integrity.h" +#define SHA256_DIGEST_SIZE 32 +#endif /* DEFEX_INTEGRITY_ENABLE */ + +static struct kset *defex_kset; +static int is_recovery = 0; + +__visible_for_testing int __init bootmode_setup(char *str) +{ + if (str && *str == '2') { + is_recovery = 1; + printk(KERN_ALERT "[DEFEX] recovery mode setup\n"); + } + return 0; +} +__setup("bootmode=", bootmode_setup); + +int check_rules_ready(void) +{ + struct rule_item_struct *base = (struct rule_item_struct *)defex_packed_rules; + return (!base || !base->data_size)?0:1; +} + +__visible_for_testing int check_system_mount(void) +{ + static int mount_system_root = -1; + struct file *fp; + + if (mount_system_root < 0) { + fp = local_fopen("/sbin/recovery", O_RDONLY, 0); + if (IS_ERR(fp)) + fp = local_fopen("/system/bin/recovery", O_RDONLY, 0); + + if (!IS_ERR(fp)) { + printk(KERN_ALERT "[DEFEX] recovery mode\n"); + filp_close(fp, NULL); + is_recovery = 1; + } else { + printk(KERN_ALERT "[DEFEX] normal mode\n"); + } + + mount_system_root = 0; + fp = local_fopen("/system_root", O_DIRECTORY | O_PATH, 0); + if (!IS_ERR(fp)) { + filp_close(fp, NULL); + mount_system_root = 1; + printk(KERN_ALERT "[DEFEX] system_root=TRUE\n"); + } else { + printk(KERN_ALERT "[DEFEX] system_root=FALSE\n"); + } + } + return (mount_system_root > 0); +} + +__visible_for_testing void parse_static_rules(const struct static_rule *rules, size_t max_len, int rules_number) +{ + int i; + size_t count; + const char *current_rule; +#if (defined(DEFEX_PERMISSIVE_PED) || defined(DEFEX_PERMISSIVE_SP) || defined(DEFEX_PERMISSIVE_IM)) + static const char permissive[2] = "2"; +#endif /* DEFEX_PERMISSIVE_**/ + + for (i = 0; i < rules_number; i++) { + count = strnlen(rules[i].rule, max_len); + current_rule = rules[i].rule; + switch (rules[i].feature_type) { +#ifdef DEFEX_PED_ENABLE + case feature_ped_status: +#ifdef DEFEX_PERMISSIVE_PED + current_rule = permissive; +#endif /* DEFEX_PERMISSIVE_PED */ + task_defex_privesc_store_status(global_privesc_obj, NULL, current_rule, count); + break; +#endif /* DEFEX_PED_ENABLE */ +#ifdef DEFEX_SAFEPLACE_ENABLE + case feature_safeplace_status: +#ifdef DEFEX_PERMISSIVE_SP + current_rule = permissive; +#endif /* DEFEX_PERMISSIVE_SP */ + safeplace_status_store(global_safeplace_obj, NULL, current_rule, count); + break; +#endif /* DEFEX_SAFEPLACE_ENABLE */ +#ifdef DEFEX_IMMUTABLE_ENABLE + case feature_immutable_status: +#ifdef DEFEX_PERMISSIVE_IM + current_rule = permissive; +#endif /* DEFEX_PERMISSIVE_IM */ + immutable_status_store(global_immutable_obj, NULL, current_rule, count); + break; +#endif /* DEFEX_IMMUTABLE_ENABLE */ + } + } +} + + +#ifdef DEFEX_INTEGRITY_ENABLE +__visible_for_testing int defex_check_integrity(struct file *f, unsigned char *hash) +{ + struct crypto_shash *handle = NULL; + struct shash_desc* shash = NULL; + static const unsigned char buff_zero[SHA256_DIGEST_SIZE] = {0}; + unsigned char hash_sha256[SHA256_DIGEST_SIZE]; + unsigned char *buff = NULL; + size_t buff_size = PAGE_SIZE; + loff_t file_size = 0; + int ret = 0, err = 0, read_size = 0; + + // A saved hash is zero, skip integrity check + if (!memcmp(buff_zero, hash, SHA256_DIGEST_SIZE)) + return ret; + + if (IS_ERR(f)) + goto hash_error; + + handle = crypto_alloc_shash("sha256", 0, 0); + if (IS_ERR(handle)) { + err = PTR_ERR(handle); + pr_err("[DEFEX] Can't alloc sha256, error : %d", err); + return -1; + } + + shash = kzalloc(sizeof(struct shash_desc) + crypto_shash_descsize(handle), GFP_KERNEL); + if (NULL == shash) + goto hash_error; + + shash->tfm = handle; + + buff = kmalloc(buff_size, GFP_KERNEL); + if (NULL == buff) + goto hash_error; + + err = crypto_shash_init(shash); + if (err < 0) + goto hash_error; + + + while(1) { + read_size = local_fread(f, file_size, (char*)buff, buff_size); + if (0 > read_size) + goto hash_error; + if (0 == read_size) + break; + file_size += read_size; + err = crypto_shash_update(shash, buff, read_size); + if (err < 0) + goto hash_error; + } + + err = crypto_shash_final(shash, hash_sha256); + if (err < 0) + goto hash_error; + + ret = memcmp(hash_sha256, hash, SHA256_DIGEST_SIZE); + + goto hash_exit; + + hash_error: + ret = -1; + hash_exit: + if (buff) + kfree(buff); + if (shash) + kfree(shash); + if (handle) + crypto_free_shash(handle); + return ret; + +} + +__visible_for_testing int defex_integrity_default(const char *file_path) +{ + static const char integrity_default[] = "/system/bin/install-recovery.sh"; + return strncmp(integrity_default, file_path, sizeof(integrity_default)); +} + +#endif /* DEFEX_INTEGRITY_ENABLE */ + +#ifdef DEFEX_USE_PACKED_RULES +__visible_for_testing struct rule_item_struct *lookup_dir(struct rule_item_struct *base, const char *name, int l, int for_recovery) +{ + struct rule_item_struct *item = NULL; + unsigned int offset; + + if (!base || !base->next_level) + return item; + item = GET_ITEM_PTR(base->next_level); + do { + if ((!(item->feature_type & feature_is_file) + || (!!(item->feature_type & feature_for_recovery)) == for_recovery) + && item->size == l + && !memcmp(name, item->name, l)) return item; + offset = item->next_file; + item = GET_ITEM_PTR(offset); + } while(offset); + return NULL; +} + +__visible_for_testing int lookup_tree(const char *file_path, int attribute, struct file *f) +{ + const char *ptr, *next_separator; + struct rule_item_struct *base, *cur_item = NULL; + int l; + + if (!file_path || *file_path != '/') + return 0; + +#ifdef DEFEX_KERNEL_ONLY +try_to_load: +#endif + base = (struct rule_item_struct *)defex_packed_rules; + if (!base || !base->data_size) { +#ifdef DEFEX_KERNEL_ONLY + /* allow all requests if rules were not loaded for Recovery mode */ + l = load_rules_late(); + if (l > 0) + goto try_to_load; + if (!l || is_recovery) + return (attribute == feature_ped_exception || attribute == feature_safeplace_path)?1:0; +#endif /* DEFEX_KERNEL_ONLY */ + /* block all requests if rules were not loaded instead */ + return 0; + } + + ptr = file_path + 1; + do { + next_separator = strchr(ptr, '/'); + if (!next_separator) + l = strlen(ptr); + else + l = next_separator - ptr; + if (!l) + return 0; + cur_item = lookup_dir(base, ptr, l, is_recovery); + if (!cur_item) + cur_item = lookup_dir(base, ptr, l, !is_recovery); + + if (!cur_item) + break; + if (cur_item->feature_type & attribute) { +#ifdef DEFEX_INTEGRITY_ENABLE + /* Integrity acceptable only for files */ + if ((cur_item->feature_type & feature_is_file) && f) { + if (defex_integrity_default(file_path) + && defex_check_integrity(f, cur_item->integrity)) + return DEFEX_INTEGRITY_FAIL; + } +#endif /* DEFEX_INTEGRITY_ENABLE */ + if (attribute & (feature_immutable_path_open | feature_immutable_path_write) + && !(cur_item->feature_type & feature_is_file)) { + /* Allow open the folder by default */ + if (!next_separator || *(ptr + l + 1) == 0) + return 0; + } + return 1; + } + base = cur_item; + ptr += l; + if (next_separator) + ptr++; + } while(*ptr); + return 0; +} +#endif /* DEFEX_USE_PACKED_RULES */ + +int rules_lookup2(const char *target_file, int attribute, struct file *f) +{ + int ret = 0; +#if (defined(DEFEX_SAFEPLACE_ENABLE) || defined(DEFEX_IMMUTABLE_ENABLE) || defined(DEFEX_PED_ENABLE)) + static const char system_root_txt[] = "/system_root"; +#ifndef DEFEX_USE_PACKED_RULES + int i, count, end; + const struct static_rule *current_rule; +#endif + if (check_system_mount() && + !strncmp(target_file, system_root_txt, sizeof(system_root_txt) - 1)) + target_file += (sizeof(system_root_txt) - 1); + +#ifdef DEFEX_USE_PACKED_RULES + ret = lookup_tree(target_file, attribute, f); +#else + for (i = 0; i < static_rule_count; i++) { + current_rule = &defex_static_rules[i]; + if (current_rule->feature_type == attribute) { + end = strnlen(current_rule->rule, STATIC_RULES_MAX_STR); + if (current_rule->rule[end - 1] == '/') { + count = end; + } else { + count = strnlen(target_file, STATIC_RULES_MAX_STR); + if (end > count) count = end; + } + if (!strncmp(current_rule->rule, target_file, count)) { + ret = 1; + break; + } + } + } +#endif /* DEFEX_USE_PACKED_RULES */ +#endif + return ret; +} + +int rules_lookup(const struct path *dpath, int attribute, struct file *f) +{ + int ret = 0; + char *target_file, *buff; + + buff = kmalloc(PATH_MAX, GFP_KERNEL); + if (!buff) + return ret; + target_file = d_path(dpath, buff, PATH_MAX); + if (!IS_ERR(target_file)) { + ret = rules_lookup2(target_file, attribute, f); + } + kfree(buff); + return ret; +} + + +int __init defex_init_sysfs(void) +{ + defex_kset = kset_create_and_add("defex", NULL, NULL); + if (!defex_kset) + return -ENOMEM; + +#if defined(DEFEX_DEBUG_ENABLE) && defined(DEFEX_SYSFS_ENABLE) + if (defex_create_debug(defex_kset) != DEFEX_OK) + goto kset_error; +#endif /* DEFEX_DEBUG_ENABLE && DEFEX_SYSFS_ENABLE */ + +#ifdef DEFEX_PED_ENABLE + global_privesc_obj = task_defex_create_privesc_obj(defex_kset); + if (!global_privesc_obj) + goto privesc_error; +#endif /* DEFEX_PED_ENABLE */ + +#ifdef DEFEX_SAFEPLACE_ENABLE + global_safeplace_obj = task_defex_create_safeplace_obj(defex_kset); + if (!global_safeplace_obj) + goto safeplace_error; +#endif /* DEFEX_SAFEPLACE_ENABLE */ + +#ifdef DEFEX_IMMUTABLE_ENABLE + global_immutable_obj = task_defex_create_immutable_obj(defex_kset); + if (!global_immutable_obj) + goto immutable_error; +#endif /* DEFEX_IMMUTABLE_ENABLE */ + + parse_static_rules(defex_static_rules, STATIC_RULES_MAX_STR, static_rule_count); + return 0; + +#ifdef DEFEX_IMMUTABLE_ENABLE +immutable_error: +#endif /* DEFEX_IMMUTABLE_ENABLE */ + +#ifdef DEFEX_SAFEPLACE_ENABLE + task_defex_destroy_safeplace_obj(global_safeplace_obj); + safeplace_error: +#endif /* DEFEX_SAFEPLACE_ENABLE */ + +#ifdef DEFEX_PED_ENABLE + task_defex_destroy_privesc_obj(global_privesc_obj); + privesc_error: +#endif /* DEFEX_PED_ENABLE */ + +#if defined(DEFEX_DEBUG_ENABLE) && defined(DEFEX_SYSFS_ENABLE) + kset_error: + kset_unregister(defex_kset); + defex_kset = NULL; +#endif /* DEFEX_DEBUG_ENABLE && DEFEX_SYSFS_ENABLE */ + return -ENOMEM; +} + + +#if defined(DEFEX_RAMDISK_ENABLE) + +#ifdef DEFEX_KERNEL_ONLY +int load_rules_late(void) +{ + struct file *f; + int data_size, rules_size, res = 0; + unsigned char *data_buff = NULL; + static unsigned long start_time = 0; + static unsigned long last_time = 0; + unsigned long cur_time = get_seconds(); + static DEFINE_SPINLOCK(load_lock); + static atomic_t in_progress = ATOMIC_INIT(0); + + if (!spin_trylock(&load_lock)) + return res; + + if (atomic_read(&in_progress) != 0) { + spin_unlock(&load_lock); + return res; + } + + atomic_set(&in_progress, 1); + spin_unlock(&load_lock); + + /* The first try to load, initialize time values */ + if (!start_time) + start_time = get_seconds(); + /* Skip this try, wait for next second */ + if (cur_time == last_time) + goto do_exit; + /* Load has been attempted for 30 seconds, give up. */ + if ((cur_time - start_time) > 30) { + res = -1; + goto do_exit; + } + last_time = cur_time; + + f = local_fopen(DEFEX_RULES_FILE, O_RDONLY, 0); + if (IS_ERR(f)) { + pr_err("[DEFEX] Failed to open rules file (%ld)\n", (long)PTR_ERR(f)); + goto do_exit; + } + data_size = i_size_read(file_inode(f)); + if (data_size <= 0 || data_size > (sizeof(defex_packed_rules) << 1)) + goto do_clean; + data_buff = kmalloc(data_size, GFP_KERNEL); + if (!data_buff) + goto do_clean; + + rules_size = local_fread(f, 0, data_buff, data_size); + if (rules_size <= 0) { + pr_err("[DEFEX] Failed to read rules file (%d)\n", rules_size); + goto do_clean; + } + printk(KERN_INFO "[DEFEX] Late load rules file: %s.\n", DEFEX_RULES_FILE); + printk(KERN_INFO "[DEFEX] Read %d bytes.\n", rules_size); + if (rules_size > sizeof(defex_packed_rules)) + rules_size = sizeof(defex_packed_rules); + memcpy(defex_packed_rules, data_buff, rules_size); + res = (rules_size > 0); +do_clean: + filp_close(f, NULL); + kfree(data_buff); +do_exit: + atomic_set(&in_progress, 0); + return res; +} +#endif /* DEFEX_KERNEL_ONLY */ + +__visible_for_testing int __init do_load_rules(void) +{ + struct file *f; + int res = -1, data_size, rules_size; + unsigned char *data_buff = NULL; + + memset(defex_packed_rules, 0, sizeof(defex_packed_rules)); + printk(KERN_INFO "[DEFEX] Load rules file: %s.\n", DEFEX_RULES_FILE); + f = local_fopen(DEFEX_RULES_FILE, O_RDONLY, 0); + if (IS_ERR(f)) { + pr_err("[DEFEX] Failed to open rules file (%ld)\n", (long)PTR_ERR(f)); +#ifdef DEFEX_KERNEL_ONLY + if (is_recovery) + res = 0; +#endif /* DEFEX_KERNEL_ONLY */ + return res; + } + data_size = i_size_read(file_inode(f)); + if (data_size <= 0 || data_size > (sizeof(defex_packed_rules) << 1)) + goto do_clean; + data_buff = kmalloc(data_size, GFP_KERNEL); + if (!data_buff) + goto do_clean; + + rules_size = local_fread(f, 0, data_buff, data_size); + if (rules_size <= 0) { + pr_err("[DEFEX] Failed to read rules file (%d)\n", rules_size); + goto do_clean; + } + printk(KERN_INFO "[DEFEX] Read %d bytes.\n", rules_size); + +#ifdef DEFEX_SIGN_ENABLE + res = defex_rules_signature_check(data_buff, rules_size, &rules_size); + if (!res && rules_size > sizeof(defex_packed_rules)) + res = -1; + + if (!res) + printk("[DEFEX] Rules signature verified successfully.\n"); + else + pr_err("[DEFEX] Rules signature incorrect!!!\n"); +#else + res = 0; +#endif + + if (!res) + memcpy(defex_packed_rules, data_buff, rules_size); +do_clean: + filp_close(f, NULL); + kfree(data_buff); + +#ifdef DEFEX_KERNEL_ONLY + if (is_recovery && res != 0) { + res = 0; + printk("[DEFEX] Kernel Only & recovery mode, rules loading is passed.\n"); + } +#endif + + return res; +} + +#endif /* DEFEX_RAMDISK_ENABLE */ + +void __init defex_load_rules(void) +{ +#if defined(DEFEX_RAMDISK_ENABLE) + if ( !boot_state_unlocked && do_load_rules() != 0) { +#if !(defined(DEFEX_DEBUG_ENABLE) || defined(DEFEX_KERNEL_ONLY)) + panic("[DEFEX] Signature mismatch.\n"); +#endif + } +#endif /* DEFEX_RAMDISK_ENABLE */ +} diff --git a/security/defex_lsm/defex_debug.c b/security/defex_lsm/debug/defex_debug.c similarity index 86% rename from security/defex_lsm/defex_debug.c rename to security/defex_lsm/debug/defex_debug.c index fcd4b1b3c39b..d18fcfd9f07c 100755 --- a/security/defex_lsm/defex_debug.c +++ b/security/defex_lsm/debug/defex_debug.c @@ -19,7 +19,7 @@ static int last_cmd; -static int set_user(struct cred *new_cred) +__visible_for_testing int set_user(struct cred *new_cred) { struct user_struct *new_user; @@ -35,7 +35,7 @@ static int set_user(struct cred *new_cred) /* * target_id = (0 - set all uids, 1 - set fsuid, 2 - set all gids) */ -static int set_cred(int target_id, int new_val) +__visible_for_testing int set_cred(int target_id, int new_val) { struct user_namespace *ns = current_user_ns(); const struct cred *old_cred; @@ -86,7 +86,7 @@ do_abort: return -EPERM; } -static ssize_t debug_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) +__visible_for_testing ssize_t debug_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) { struct task_struct *p = current; int i, l, new_val = -1; @@ -124,7 +124,7 @@ static ssize_t debug_store(struct kobject *kobj, struct kobj_attribute *attr, co return (!ret)?count:ret; } -static ssize_t debug_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) +__visible_for_testing ssize_t debug_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { struct task_struct *p = current; int res = 0; @@ -146,7 +146,7 @@ static ssize_t debug_show(struct kobject *kobj, struct kobj_attribute *attr, cha return res; } -static struct kobj_attribute debug_attribute = __ATTR(debug, 0660, debug_show, debug_store); +__visible_for_testing struct kobj_attribute debug_attribute = __ATTR(debug, 0660, debug_show, debug_store); int defex_create_debug(struct kset *defex_kset) { diff --git a/security/defex_lsm/defex_ht.c b/security/defex_lsm/defex_ht.c deleted file mode 100755 index 8b9ee13616aa..000000000000 --- a/security/defex_lsm/defex_ht.c +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include "include/defex_catch_list.h" -#include "include/defex_internal.h" - -#define MAX_PID_32 32768 - -#ifdef DEFEX_PED_ENABLE -DECLARE_HASHTABLE(creds_hash, 15); -#endif /* DEFEX_PED_ENABLE */ - -struct proc_cred_data { - unsigned int uid, fsuid, egid; -}; - -struct proc_cred_struct { - struct hlist_node node; - struct proc_cred_data cred_data; -}; - -static DEFINE_SPINLOCK(creds_hash_update_lock); -static struct proc_cred_data *creds_fast_hash[MAX_PID_32 + 1]; -static int creds_fast_hash_ready; - -void creds_fast_hash_init(void) -{ - unsigned int i; - - for (i = 0; i <= MAX_PID_32; i++) - creds_fast_hash[i] = NULL; - creds_fast_hash_ready = 1; -} - -int is_task_creds_ready(void) -{ - return creds_fast_hash_ready; -} - -#ifdef DEFEX_PED_ENABLE -void get_task_creds(int pid, unsigned int *uid_ptr, unsigned int *fsuid_ptr, unsigned int *egid_ptr) -{ - struct proc_cred_struct *obj; - struct proc_cred_data *cred_data; - unsigned int uid = 0, fsuid = 0, egid = 0; - unsigned long flags; - - if (pid <= MAX_PID_32) { - spin_lock_irqsave(&creds_hash_update_lock, flags); - cred_data = creds_fast_hash[pid]; - if (cred_data != NULL) { - uid = cred_data->uid; - fsuid = cred_data->fsuid; - egid = cred_data->egid; - } - spin_unlock_irqrestore(&creds_hash_update_lock, flags); - } else { - spin_lock_irqsave(&creds_hash_update_lock, flags); - hash_for_each_possible(creds_hash, obj, node, pid) { - uid = obj->cred_data.uid; - fsuid = obj->cred_data.fsuid; - egid = obj->cred_data.egid; - break; - } - spin_unlock_irqrestore(&creds_hash_update_lock, flags); - } - *uid_ptr = uid; - *fsuid_ptr = fsuid; - *egid_ptr = egid; -} - -int set_task_creds(int pid, unsigned int uid, unsigned int fsuid, unsigned int egid) -{ - struct proc_cred_struct *obj; - struct proc_cred_data *cred_data = NULL, *tmp_data = NULL; - unsigned long flags; - -alloc_obj:; - if (pid <= MAX_PID_32) { - if (!creds_fast_hash[pid]) { - tmp_data = kmalloc(sizeof(struct proc_cred_data), GFP_ATOMIC); - if (!tmp_data) - return -1; - } - spin_lock_irqsave(&creds_hash_update_lock, flags); - cred_data = creds_fast_hash[pid]; - if (!cred_data) { - if (!tmp_data) { - spin_unlock_irqrestore(&creds_hash_update_lock, flags); - goto alloc_obj; - } - cred_data = tmp_data; - creds_fast_hash[pid] = cred_data; - tmp_data = NULL; - } - cred_data->uid = uid; - cred_data->fsuid = fsuid; - cred_data->egid = egid; - spin_unlock_irqrestore(&creds_hash_update_lock, flags); - if (tmp_data) - kfree(tmp_data); - return 0; - } - - spin_lock_irqsave(&creds_hash_update_lock, flags); - hash_for_each_possible(creds_hash, obj, node, pid) { - obj->cred_data.uid = uid; - obj->cred_data.fsuid = fsuid; - obj->cred_data.egid = egid; - spin_unlock_irqrestore(&creds_hash_update_lock, flags); - return 0; - } - spin_unlock_irqrestore(&creds_hash_update_lock, flags); - obj = kmalloc(sizeof(struct proc_cred_struct), GFP_ATOMIC); - if (!obj) - return -1; - obj->cred_data.uid = uid; - obj->cred_data.fsuid = fsuid; - obj->cred_data.egid = egid; - spin_lock_irqsave(&creds_hash_update_lock, flags); - hash_add(creds_hash, &obj->node, pid); - spin_unlock_irqrestore(&creds_hash_update_lock, flags); - return 0; -} -#endif /* DEFEX_PED_ENABLE */ - -void delete_task_creds(int pid) -{ - struct proc_cred_struct *obj; - struct proc_cred_data *cred_data; - unsigned long flags; - - if (pid <= MAX_PID_32) { - spin_lock_irqsave(&creds_hash_update_lock, flags); - cred_data = creds_fast_hash[pid]; - creds_fast_hash[pid] = NULL; - spin_unlock_irqrestore(&creds_hash_update_lock, flags); - kfree(cred_data); - return; - } - - spin_lock_irqsave(&creds_hash_update_lock, flags); - hash_for_each_possible(creds_hash, obj, node, pid) { - hash_del(&obj->node); - spin_unlock_irqrestore(&creds_hash_update_lock, flags); - kfree(obj); - return; - } - spin_unlock_irqrestore(&creds_hash_update_lock, flags); -} - diff --git a/security/defex_lsm/defex_procs.c b/security/defex_lsm/defex_procs.c deleted file mode 100755 index e7712141bdcb..000000000000 --- a/security/defex_lsm/defex_procs.c +++ /dev/null @@ -1,475 +0,0 @@ -/* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. - */ - -#include -#include -#include -#ifdef CONFIG_SECURITY_DSMS -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef CONFIG_SECURITY_DSMS -#include -#endif -#include -#include -#include -#include -#include "include/defex_caches.h" -#include "include/defex_catch_list.h" -#include "include/defex_config.h" -#include "include/defex_internal.h" -#include "include/defex_rules.h" - -#ifdef CONFIG_SECURITY_DSMS - -# define PED_VIOLATION "DFX1" -# define SAFEPLACE_VIOLATION "DFX2" -# define INTEGRITY_VIOLATION "DFX3" -# define MESSAGE_BUFFER_SIZE 200 -# define STORED_CREDS_SIZE 100 - -static void defex_report_violation(const char *violation, uint64_t counter, - int syscall, struct task_struct *p, struct file *f, uid_t stored_uid, uid_t stored_fsuid, uid_t stored_egid) -{ - int usermode_result; - char message[MESSAGE_BUFFER_SIZE + 1]; - - const uid_t uid = uid_get_value(p->cred->uid); - const uid_t euid = uid_get_value(p->cred->euid); - const uid_t fsuid = uid_get_value(p->cred->fsuid); - const uid_t egid = uid_get_value(p->cred->egid); - const char *process_name = p->comm; - const char *program_path = defex_get_filename(p); - const pid_t pid = p->pid, tgid = p->tgid; - - char *file_path = NULL, *buff = NULL; - const struct path *dpath = NULL; - - char stored_creds[STORED_CREDS_SIZE + 1]; - - if (f != NULL) { - buff = kzalloc(PATH_MAX, GFP_KERNEL); - if (buff != NULL) { - dpath = &(f->f_path); - file_path = d_path(dpath, buff, PATH_MAX); - } - } - else { - snprintf(stored_creds, sizeof(stored_creds), "[euid=%ld fsuid=%ld egid=%ld]", (long)stored_uid, (long)stored_fsuid, (long)stored_egid); - stored_creds[sizeof(stored_creds) - 1] = 0; - } - - snprintf(message, sizeof(message), "sc=%d tsk=%s (%s) pid=%u tgid=%u uid=%ld euid=%ld fsuid=%ld egid=%ld%s%s", - syscall, process_name, (program_path ? program_path : ""), pid, tgid, (long)uid, (long)euid, (long)fsuid, (long)egid, - (file_path ? " file=" : " stored "), (file_path ? file_path : stored_creds)); - message[sizeof(message) - 1] = 0; - -#ifdef DEFEX_DEBUG_ENABLE - printk(KERN_ERR "DEFEX Violation : feature=%s value=%ld, detail=[%s]", - violation, (long)counter, message); -#endif /* DEFEX_DEBUG_ENABLE */ - usermode_result = dsms_send_message(violation, message, counter); -#ifdef DEFEX_DEBUG_ENABLE - printk(KERN_ERR "DEFEX Result : %d\n", usermode_result); -#endif /* DEFEX_DEBUG_ENABLE */ - - kfree(program_path); - kfree(buff); -} -#endif /* CONFIG_SECURITY_DSMS */ - -#ifdef DEFEX_SAFEPLACE_ENABLE -static long kill_process(struct task_struct *p) -{ - read_lock(&tasklist_lock); - force_sig(SIGKILL, p); - read_unlock(&tasklist_lock); - return 0; -} -#endif /* DEFEX_SAFEPLACE_ENABLE */ - -#ifdef DEFEX_PED_ENABLE -static long kill_process_group(struct task_struct *p, int tgid, int pid) -{ - read_lock(&tasklist_lock); - for_each_process(p) { - if (p->tgid == tgid) - send_sig(SIGKILL, p, 0); - } - send_sig(SIGKILL, current, 0); - read_unlock(&tasklist_lock); - return 0; -} -#endif /* DEFEX_PED_ENABLE */ - -struct file *defex_get_source_file(struct task_struct *p) -{ - struct file *file_addr = NULL; - -#ifdef DEFEX_CACHES_ENABLE - file_addr = defex_file_cache_find(p->pid); - - if (file_addr == NULL) { - file_addr = get_mm_exe_file(p->mm); - defex_file_cache_add(p->pid, file_addr); - } else { - down_read(&p->mm->mmap_sem); - if (file_addr != p->mm->exe_file) { - file_addr = p->mm->exe_file; - if (!file_addr) { - up_read(&p->mm->mmap_sem); - return NULL; - } - defex_file_cache_update(file_addr); - get_file(file_addr); - } - up_read(&p->mm->mmap_sem); - } -#else - file_addr = get_mm_exe_file(p->mm); -#endif /* DEFEX_CACHES_ENABLE */ - return file_addr; -} - -char *defex_get_filename(struct task_struct *p) -{ - struct file *exe_file = NULL; - const struct path *dpath = NULL; - char *path = NULL, *buff = NULL; - char *filename = NULL; - - exe_file = defex_get_source_file(p); - if (!exe_file) - goto out_filename; - - dpath = &exe_file->f_path; - - buff = kzalloc(PATH_MAX, GFP_ATOMIC); - if (buff) - path = d_path(dpath, buff, PATH_MAX); - -#ifndef DEFEX_CACHES_ENABLE - fput(exe_file); -#endif /* DEFEX_CACHES_ENABLE */ - -out_filename: - if (IS_ERR(path) || !path) - filename = kstrdup("", GFP_ATOMIC); - else - filename = kstrdup(path, GFP_ATOMIC); - - kfree(buff); - return filename; -} - -#ifdef DEFEX_PED_ENABLE -static int task_defex_is_secured(struct task_struct *p) -{ - struct file *exe_file = NULL; - const struct path *dpath = NULL; - int is_secured = 1; - - exe_file = defex_get_source_file(p); - if (!exe_file) - goto skip_secured; - - dpath = &exe_file->f_path; - if (!dpath->dentry || !dpath->dentry->d_inode) - goto out_secured; - - is_secured = !rules_lookup(dpath, feature_ped_exception, exe_file); - -out_secured: -#ifndef DEFEX_CACHES_ENABLE - fput(exe_file); -#endif /* DEFEX_CACHES_ENABLE */ -skip_secured: - return is_secured; -} -#endif /* DEFEX_PED_ENABLE */ - -#ifdef DEFEX_PED_ENABLE -static int at_same_group(unsigned int uid1, unsigned int uid2) -{ - static const unsigned int lod_base = 0x61A8; - - /* allow the weaken privilege */ - if (uid1 >= 10000 && uid2 < 10000) return 1; - /* allow traverse in the same class */ - if ((uid1 / 1000) == (uid2 / 1000)) return 1; - /* allow LoD process */ - return ((uid1 >> 16) == lod_base) && ((uid2 >> 16) == lod_base); -} - -static int at_same_group_gid(unsigned int gid1, unsigned int gid2) -{ - static const unsigned int lod_base = 0x61A8, inet = 3003; - - /* allow the weaken privilege */ - if (gid1 >= 10000 && gid2 < 10000) return 1; - /* allow traverse in the same class */ - if ((gid1 / 1000) == (gid2 / 1000)) return 1; - /* allow LoD process */ - return (((gid1 >> 16) == lod_base) || (gid1 == inet)) && ((gid2 >> 16) == lod_base); -} - -/* Cred. violation feature decision function */ -#ifndef CONFIG_SECURITY_DSMS -static int task_defex_check_creds(struct task_struct *p) -#else -static int task_defex_check_creds(struct task_struct *p, int syscall) -#endif /* CONFIG_SECURITY_DSMS */ -{ - char *path = NULL; - int check_deeper, case_num; - unsigned int cur_uid, cur_euid, cur_fsuid, cur_egid; - unsigned int uid, fsuid, egid; - unsigned int g_uid, g_fsuid, g_egid; - static const unsigned int dead_uid = 0xDEADBEAF; - - if (!is_task_creds_ready() || !p->cred) - goto out; - - get_task_creds(p->pid, &uid, &fsuid, &egid); - if (p->tgid != p->pid) { - get_task_creds(p->tgid, &g_uid, &g_fsuid, &g_egid); - } else { - g_uid = uid; - g_fsuid = fsuid; - g_egid = egid; - } - - cur_uid = uid_get_value(p->cred->uid); - cur_euid = uid_get_value(p->cred->euid); - cur_fsuid = uid_get_value(p->cred->fsuid); - cur_egid = uid_get_value(p->cred->egid); - - if (!uid) { - if (CHECK_ROOT_CREDS(p)) - set_task_creds(p->pid, 1, 1, 1); - else - set_task_creds(p->pid, cur_euid, cur_fsuid, cur_egid); - } else if (uid == 1) { - if (!CHECK_ROOT_CREDS(p)) - set_task_creds(p->pid, cur_euid, cur_fsuid, cur_egid); - } else if (uid == dead_uid || g_uid == dead_uid) { - path = defex_get_filename(p); - pr_crit("defex[5]: process wasn't killed [task=%s, filename=%s, uid=%d]\n", p->comm, path, cur_uid); - pr_crit("defex[5]: uid=%d euid=%d fsuid=%d egid=%d\n", - cur_uid, cur_euid, cur_fsuid, cur_egid); - goto exit; - } else { - check_deeper = 0; - if ((cur_uid != uid) || (cur_euid != uid) || !((cur_fsuid == fsuid) || (cur_fsuid == uid)) || (cur_egid != egid)) { - check_deeper = 1; - set_task_creds(p->pid, cur_euid, cur_fsuid, cur_egid); - } - if (check_deeper && (!at_same_group(cur_uid, uid) || - !at_same_group(cur_euid, uid) || - !at_same_group_gid(cur_egid, egid) || - !at_same_group(cur_fsuid, fsuid)) && - task_defex_is_secured(p)) { - set_task_creds(p->pid, dead_uid, dead_uid, dead_uid); - if (p->tgid != p->pid) - set_task_creds(p->tgid, dead_uid, dead_uid, dead_uid); - case_num = 1; - goto show_violation; - } - - if (p->tgid != p->pid) { - if ((g_uid > 1) && (!at_same_group(cur_uid, g_uid) || - !at_same_group(cur_euid, g_uid) || - !at_same_group_gid(cur_egid, g_egid)) && - task_defex_is_secured(p)) { - set_task_creds(p->tgid, dead_uid, dead_uid, dead_uid); - if (p->tgid != p->pid) - set_task_creds(p->pid, dead_uid, dead_uid, dead_uid); - case_num = 2; - goto show_violation; - } - } - } - - if ((p->tgid != p->pid) && CHECK_ROOT_CREDS(p) && !CHECK_ROOT_CREDS(p->real_parent)) { - if ((g_uid > 1) && task_defex_is_secured(p)) { - set_task_creds(p->tgid, dead_uid, dead_uid, dead_uid); - if (p->tgid != p->pid) - set_task_creds(p->pid, dead_uid, dead_uid, dead_uid); - case_num = 3; - goto show_violation; - } - } - - if (CHECK_ROOT_CREDS(p) && !CHECK_ROOT_CREDS(p->real_parent) && - task_defex_is_secured(p)) { - set_task_creds(p->pid, dead_uid, dead_uid, dead_uid); - if (p->tgid != p->pid) - set_task_creds(p->tgid, dead_uid, dead_uid, dead_uid); - case_num = 4; - goto show_violation; - } - -out: - return DEFEX_ALLOW; - -show_violation: - path = defex_get_filename(p); - pr_crit("defex[%d]: credential violation [task=%s, filename=%s, uid=%d]\n", - case_num, p->comm, (path ? path : ""), cur_uid); - pr_crit("defex[%d]: stored [euid=%d fsuid=%d egid=%d] uid=%d euid=%d fsuid=%d egid=%d\n", - case_num, uid, fsuid, egid, cur_uid, cur_euid, cur_fsuid, cur_egid); - -#ifdef CONFIG_SECURITY_DSMS - defex_report_violation(PED_VIOLATION, 0, syscall, p, NULL, uid, fsuid, egid); -#endif /* CONFIG_SECURITY_DSMS */ - -exit: - kfree(path); - return -DEFEX_DENY; -} -#endif /* DEFEX_PED_ENABLE */ - -#ifdef DEFEX_SAFEPLACE_ENABLE -/* Safeplace feature decision function */ -static int task_defex_safeplace(struct task_struct *p, struct file *f) -{ - static const char def[] = ""; - int ret = DEFEX_ALLOW, is_violation = 0; - char *proc_file, *new_file = (char *)def, *buff; - const struct path *dpath = NULL; - - if (!CHECK_ROOT_CREDS(p)) - goto out; - - if (IS_ERR(f)) - goto out; - - dpath = &f->f_path; - if (!dpath->dentry || !dpath->dentry->d_inode) - goto out; - - is_violation = rules_lookup(dpath, feature_safeplace_path, f); -#ifdef DEFEX_INTEGRITY_ENABLE - if (is_violation != DEFEX_INTEGRITY_FAIL) -#endif /* DEFEX_INTEGRITY_ENABLE */ - is_violation = !is_violation; - - if (is_violation) { - ret = -DEFEX_DENY; - proc_file = defex_get_filename(p); - buff = kzalloc(PATH_MAX, GFP_ATOMIC); - if (buff) - new_file = d_path(dpath, buff, PATH_MAX); - -#ifdef DEFEX_INTEGRITY_ENABLE - if (is_violation == DEFEX_INTEGRITY_FAIL) { - pr_crit("defex: integrity violation [task=%s (%s), child=%s, uid=%d]\n", - p->comm, (proc_file ? proc_file : ""), new_file, uid_get_value(p->cred->uid)); -#ifdef CONFIG_SECURITY_DSMS - defex_report_violation(INTEGRITY_VIOLATION, 0, __DEFEX_execve, p, f, 0, 0, 0); -#endif /* CONFIG_SECURITY_DSMS */ - - /* Temporary make permissive mode for tereble - * system image is changed as google's and defex might not work - */ - ret = DEFEX_ALLOW; - } - else -#endif /* DEFEX_INTEGRITY_ENABLE */ - { - pr_crit("defex: safeplace violation [task=%s (%s), child=%s, uid=%d]\n", - p->comm, (proc_file ? proc_file : ""), new_file, uid_get_value(p->cred->uid)); -#ifdef CONFIG_SECURITY_DSMS - defex_report_violation(SAFEPLACE_VIOLATION, 0, __DEFEX_execve, p, f, 0, 0, 0); -#endif /* CONFIG_SECURITY_DSMS */ - } - - kfree(proc_file); - kfree(buff); - } -out: - return ret; -} -#endif /* DEFEX_SAFEPLACE_ENABLE */ - -/* Main decision function */ -int task_defex_enforce(struct task_struct *p, struct file *f, int syscall) -{ - int ret = DEFEX_ALLOW; - int feature_flag; - const struct local_syscall_struct *item; - - if (!p || p->pid == 1 || !p->mm) - return ret; - - if (syscall < 0) { - item = get_local_syscall(-syscall); - if (!item) - return ret; - syscall = item->local_syscall; - } - - feature_flag = defex_get_features(); - -#ifdef DEFEX_PED_ENABLE - /* Credential escalation feature */ - if (feature_flag & FEATURE_CHECK_CREDS) { -#ifndef CONFIG_SECURITY_DSMS - ret = task_defex_check_creds(p); -#else - ret = task_defex_check_creds(p, syscall); -#endif /* CONFIG_SECURITY_DSMS */ - if (ret) { - if (!(feature_flag & FEATURE_CHECK_CREDS_SOFT)) { - kill_process_group(p, p->tgid, p->pid); - return -DEFEX_DENY; - } - } - } -#endif /* DEFEX_PED_ENABLE */ - -#ifdef DEFEX_SAFEPLACE_ENABLE - /* Safeplace feature */ - if (feature_flag & FEATURE_SAFEPLACE) { - if (syscall == __DEFEX_execve) { - ret = task_defex_safeplace(p, f); - if (ret == -DEFEX_DENY) { - if (!(feature_flag & FEATURE_SAFEPLACE_SOFT)) { - kill_process(p); - return -DEFEX_DENY; - } - } - } - } -#endif /* DEFEX_SAFEPLACE_ENABLE */ - - return DEFEX_ALLOW; -} - -int task_defex_zero_creds(struct task_struct *tsk) -{ - if (is_task_creds_ready()) - delete_task_creds(tsk->pid); - -#ifdef DEFEX_CACHES_ENABLE - defex_file_cache_delete(tsk->pid); -#endif /* DEFEX_CACHES_ENABLE */ - - return 0; -} - diff --git a/security/defex_lsm/defex_rules.c b/security/defex_lsm/defex_rules.c index b07faa5733b8..26ef95912f5f 100755 --- a/security/defex_lsm/defex_rules.c +++ b/security/defex_lsm/defex_rules.c @@ -11,6 +11,7 @@ const struct static_rule defex_static_rules[] = { {feature_ped_path,"/"}, {feature_safeplace_status,"1"}, + {feature_immutable_status,"1"}, {feature_ped_status,"1"}, #ifndef DEFEX_USE_PACKED_RULES /* Rules will be added here */ diff --git a/security/defex_lsm/defex_sysfs.c b/security/defex_lsm/defex_sysfs.c deleted file mode 100755 index 4d9cb319e672..000000000000 --- a/security/defex_lsm/defex_sysfs.c +++ /dev/null @@ -1,395 +0,0 @@ -/* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "include/defex_debug.h" -#include "include/defex_internal.h" -#include "include/defex_rules.h" - -#ifdef DEFEX_USE_PACKED_RULES -#if defined(DEFEX_KERNEL_ONLY) && defined(DEFEX_INTEGRITY_ENABLE) -#else -#include "defex_packed_rules.inc" -#endif -#endif - -#ifdef DEFEX_INTEGRITY_ENABLE -#include -#include -#include -#include -#include "../integrity/integrity.h" -#define SHA256_DIGEST_SIZE 32 -#ifdef DEFEX_KERNEL_ONLY -#define RULES "/system/etc/defex_packed_rules.bin" -unsigned char *defex_packed_rules; -#endif /* DEFEX_KERNEL_ONLY */ -#endif /* DEFEX_INTEGRITY_ENABLE */ - -static struct kset *defex_kset; - - -int check_system_mount(void) -{ - static int mount_system_root = -1; - struct file *fp; - - if (mount_system_root < 0) { - fp = filp_open("/sbin/recovery", O_RDONLY, 0); - if (IS_ERR(fp)) { - printk(KERN_ALERT "[DEFEX] normal mode\n"); - mount_system_root = 0; - } else { - printk(KERN_ALERT "[DEFEX] recovery mode\n"); - filp_close(fp, NULL); - fp = filp_open("/system_root", O_DIRECTORY | O_PATH, 0); - if (IS_ERR(fp)) { - printk(KERN_ALERT "[DEFEX] system_root=FALSE\n"); - mount_system_root = 0; - } else { - printk(KERN_ALERT "[DEFEX] system_root=TRUE\n"); - filp_close(fp, NULL); - mount_system_root = 1; - } - } - } - return (mount_system_root > 0); -} - -static void parse_static_rules(const struct static_rule *rules, size_t max_len, int rules_number) -{ - int i; - size_t count; - const char *current_rule; -#if (defined(DEFEX_PERMISSIVE_PED) || defined(DEFEX_PERMISSIVE_SP)) - static const char permissive[2] = "2"; -#endif /* DEFEX_PERMISSIVE_**/ - - for (i = 0; i < rules_number; i++) { - count = strnlen(rules[i].rule, max_len); - current_rule = rules[i].rule; - switch (rules[i].feature_type) { -#ifdef DEFEX_PED_ENABLE - case feature_ped_status: -#ifdef DEFEX_PERMISSIVE_PED - current_rule = permissive; -#endif /* DEFEX_PERMISSIVE_PED */ - task_defex_privesc_store_status(global_privesc_obj, NULL, current_rule, count); - break; -#endif /* DEFEX_PED_ENABLE */ -#ifdef DEFEX_SAFEPLACE_ENABLE - case feature_safeplace_status: -#ifdef DEFEX_PERMISSIVE_SP - current_rule = permissive; -#endif /* DEFEX_PERMISSIVE_SP */ - safeplace_status_store(global_safeplace_obj, NULL, current_rule, count); - break; -#endif /* DEFEX_SAFEPLACE_ENABLE */ - } - } - - printk(KERN_INFO "DEFEX_LSM started"); -} - -#ifdef DEFEX_USE_PACKED_RULES -struct rule_item_struct *lookup_dir(struct rule_item_struct *base, const char *name, int l) -{ - struct rule_item_struct *item = NULL; - unsigned int offset; - - if (!base || !base->next_level) - return item; - item = GET_ITEM_PTR(base->next_level); - do { - if (item->size == l && !memcmp(name, item->name, l)) return item; - offset = item->next_file; - item = GET_ITEM_PTR(offset); - } while(offset); - return NULL; -} - -#ifdef DEFEX_INTEGRITY_ENABLE -int defex_check_integrity(struct file *f, unsigned char *hash) -{ - struct crypto_shash *handle = NULL; - struct shash_desc* shash = NULL; - unsigned char hash_sha256[SHA256_DIGEST_SIZE]; - unsigned char *buff = NULL; - size_t buff_size = PAGE_SIZE; - loff_t file_size = 0; - int ret = 0, err = 0, read_size = 0; - int i = 0; //TEST - - if (IS_ERR(f)) - goto hash_error; - - handle = crypto_alloc_shash("sha256", 0, 0); - if (IS_ERR(handle)) - goto hash_error; - - shash = kzalloc(sizeof(struct shash_desc) + crypto_shash_descsize(handle), GFP_KERNEL); - if (NULL == shash) - goto hash_error; - - shash->flags = 0; - shash->tfm = handle; - - buff = kmalloc(buff_size, GFP_KERNEL); - if (NULL == buff) - goto hash_error; - - err = crypto_shash_init(shash); - if (err < 0) - goto hash_error; - - - while(1) { - read_size = integrity_kernel_read(f, file_size, (char*)buff, buff_size); - if (0 > read_size) - goto hash_error; - if (0 == read_size) - break; - file_size += read_size; - err = crypto_shash_update(shash, buff, read_size); - if (err < 0) - goto hash_error; - } - - err = crypto_shash_final(shash, hash_sha256); - if (err < 0) - goto hash_error; - - ret = memcmp(hash_sha256, hash, SHA256_DIGEST_SIZE); - - /* TEST */ - if (ret){ - for (i = 0; i < 32; i++){ - printk("%02x%02x : %d", hash_sha256[i], hash[i], ret); - } - } - goto hash_exit; - - hash_error: - ret = -1; - hash_exit: - if (buff) - kfree(buff); - if (shash) - kfree(shash); - if (handle) - crypto_free_shash(handle); - return ret; - -} - -int defex_integrity_default(const char *file_path) -{ - static const char integrity_default[] = "/system/bin/install-recovery.sh"; - return strncmp(integrity_default, file_path, sizeof(integrity_default)); -} - -#endif /* DEFEX_INTEGRITY_ENABLE */ - -#if defined DEFEX_INTEGRITY_ENABLE && defined DEFEX_KERNEL_ONLY -int defex_read_rules(const char *path, unsigned char **data) -{ - struct file *file; - loff_t size; - unsigned char *buf; - int rc = -EINVAL; - mm_segment_t old_fs; - - if (!path || !*path) - return -EINVAL; - - old_fs = get_fs(); - set_fs(get_ds()); - file = filp_open(path, O_RDONLY, 0); - set_fs(old_fs); - if (IS_ERR(file)) { - rc = PTR_ERR(file); - pr_err("[DEFEX] Unable to open file: %s (%d)", path, rc); - return rc; - } - - size = i_size_read(file_inode(file)); - if (size <= 0) - goto out; - - buf = kmalloc(size, GFP_KERNEL); - if (!buf) { - rc = -ENOMEM; - goto out; - } - - rc = integrity_kernel_read(file, 0, buf, size); - if (rc == size) { - *data = buf; - } else { - kfree(buf); - if (rc >= 0) - rc = -EIO; - } - out: - fput(file); - return rc; -} - -#endif /* defined DEFEX_INTEGRITY_ENABLE && defined DEFEX_KERNEL_ONLY */ - -int lookup_tree(const char *file_path, int attribute, struct file *f) -{ - const char *ptr, *next_separator; - struct rule_item_struct *base, *cur_item = NULL; - int l; - - if (!file_path || *file_path != '/') - return 0; - - - /* load packed binary rules during the first-time access */ -#if defined DEFEX_INTEGRITY_ENABLE && defined DEFEX_KERNEL_ONLY - if (!defex_packed_rules) { - defex_read_rules(RULES, &defex_packed_rules); - if (!defex_packed_rules) { - printk("[DEFEX] Rules loading Failed, process: %s\n", file_path); - /* allow all while filesystem is not ready */ - return 1; - } else { - printk("[DEFEX] Rules loading OK, process: %s\n", file_path); - } - } -#endif /* defined DEFEX_INTEGRITY_ENABLE && defined DEFEX_KERNEL_ONLY */ - - base = (struct rule_item_struct *)defex_packed_rules; - ptr = file_path + 1; - do { - next_separator = strchr(ptr, '/'); - if (!next_separator) - l = strlen(ptr); - else - l = next_separator - ptr; - if (!l) - return 0; - cur_item = lookup_dir(base, ptr, l); - if (!cur_item) - break; - if (cur_item->feature_type & attribute) { -#ifdef DEFEX_INTEGRITY_ENABLE - if (defex_integrity_default(file_path) - && defex_check_integrity(f, cur_item->integrity)) - return DEFEX_INTEGRITY_FAIL; -#endif /* DEFEX_INTEGRITY_ENABLE */ - return 1; - } - base = cur_item; - ptr += l; - if (next_separator) - ptr++; - } while(*ptr); - return 0; -} -#endif /* DEFEX_USE_PACKED_RULES */ - -int rules_lookup(const struct path *dpath, int attribute, struct file *f) -{ - int ret = 0; - static const char system_root_txt[] = "/system_root"; -#if (defined(DEFEX_SAFEPLACE_ENABLE) || defined(DEFEX_PED_ENABLE)) - char *target_file, *buff; -#ifndef DEFEX_USE_PACKED_RULES - int i, count, end; - const struct static_rule *current_rule; -#endif - buff = kzalloc(PATH_MAX, GFP_ATOMIC); - if (!buff) - return ret; - target_file = d_path(dpath, buff, PATH_MAX); - if (IS_ERR(target_file)) { - kfree(buff); - return ret; - } - if (check_system_mount() && - !strncmp(target_file, system_root_txt, sizeof(system_root_txt) - 1)) - target_file += (sizeof(system_root_txt) - 1); - -#ifdef DEFEX_USE_PACKED_RULES - ret = lookup_tree(target_file, attribute, f); -#else - for (i = 0; i < static_rule_count; i++) { - current_rule = &defex_static_rules[i]; - if (current_rule->feature_type == attribute) { - end = strnlen(current_rule->rule, STATIC_RULES_MAX_STR); - if (current_rule->rule[end - 1] == '/') { - count = end; - } else { - count = strnlen(target_file, STATIC_RULES_MAX_STR); - if (end > count) count = end; - } - if (!strncmp(current_rule->rule, target_file, count)) { - ret = 1; - break; - } - } - } -#endif /* DEFEX_USE_PACKED_RULES */ - kfree(buff); -#endif - return ret; -} - -int defex_init_sysfs(void) -{ - defex_kset = kset_create_and_add("defex", NULL, NULL); - if (!defex_kset) - return -ENOMEM; - -#if defined(DEFEX_DEBUG_ENABLE) && defined(DEFEX_SYSFS_ENABLE) - if (defex_create_debug(defex_kset) != DEFEX_OK) - goto kset_error; -#endif /* DEFEX_DEBUG_ENABLE && DEFEX_SYSFS_ENABLE */ - -#ifdef DEFEX_PED_ENABLE - global_privesc_obj = task_defex_create_privesc_obj(defex_kset); - if (!global_privesc_obj) - goto privesc_error; -#endif /* DEFEX_PED_ENABLE */ - -#ifdef DEFEX_SAFEPLACE_ENABLE - global_safeplace_obj = task_defex_create_safeplace_obj(defex_kset); - if (!global_safeplace_obj) - goto safeplace_error; -#endif /* DEFEX_SAFEPLACE_ENABLE */ - - parse_static_rules(defex_static_rules, STATIC_RULES_MAX_STR, static_rule_count); - return 0; - -#ifdef DEFEX_SAFEPLACE_ENABLE - safeplace_error: -#endif /* DEFEX_SAFEPLACE_ENABLE */ - -#ifdef DEFEX_PED_ENABLE - task_defex_destroy_privesc_obj(global_privesc_obj); - privesc_error: -#endif /* DEFEX_PED_ENABLE */ - -#if defined(DEFEX_DEBUG_ENABLE) && defined(DEFEX_SYSFS_ENABLE) - kset_error: - kset_unregister(defex_kset); - defex_kset = NULL; -#endif /* DEFEX_DEBUG_ENABLE && DEFEX_SYSFS_ENABLE */ - return -ENOMEM; -} diff --git a/security/defex_lsm/feature_immutable/defex_immutable.c b/security/defex_lsm/feature_immutable/defex_immutable.c new file mode 100755 index 000000000000..bade735d44e6 --- /dev/null +++ b/security/defex_lsm/feature_immutable/defex_immutable.c @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. +*/ + +#include +#include +#include +#include +#include +#include "include/defex_internal.h" + +struct defex_immutable *global_immutable_obj; + +#ifdef DEFEX_SYSFS_ENABLE +static struct kobj_type immutable_ktype; + +ssize_t task_defex_immutable_attr_show(struct kobject *kobj, + struct attribute *attr, char *buf) +{ + struct immutable_attribute *attribute; + struct defex_immutable *immutable; + + immutable = to_immutable_obj(kobj); + attribute = to_immutable_attr(attr); + + if (!attribute->show) + return -EIO; + + return attribute->show(immutable, attribute, buf); +} + +ssize_t immutable_status_show(struct defex_immutable *immutable_obj, + struct immutable_attribute *attr, char *buf) +{ + return snprintf(buf, MAX_LEN, "%u\n", immutable_obj->status); +} + + +ssize_t task_defex_immutable_attr_store(struct kobject *kobj, + struct attribute *attr, const char *buf, size_t len) +{ + struct immutable_attribute *attribute; + struct defex_immutable *immutable; + + immutable = to_immutable_obj(kobj); + attribute = to_immutable_attr(attr); + + if (!attribute->store) + return -EIO; + + return attribute->store(immutable, attribute, buf, len); +} + +__visible_for_testing void task_defex_immutable_release(struct kobject *kobj) +{ + struct defex_immutable *immutable_obj; + + immutable_obj = to_immutable_obj(kobj); + kfree(immutable_obj); +} +#endif /* DEFEX_SYSFS_ENABLE */ + +ssize_t immutable_status_store(struct defex_immutable *immutable_obj, + struct immutable_attribute *attr, const char *buf, size_t count) +{ + int ret; + unsigned int status; + + ret = kstrtouint(buf, 10, &status); + if (ret != 0 || status > 2) + return -EINVAL; + + immutable_obj->status = status; + return count; +} + +struct defex_immutable *task_defex_create_immutable_obj(struct kset *defex_kset) +{ + struct defex_immutable *immutable; + + immutable = kzalloc(sizeof(*immutable), GFP_KERNEL); + if (!immutable) + return NULL; + + immutable->kobj.kset = defex_kset; +#ifdef DEFEX_SYSFS_ENABLE + if (kobject_init_and_add(&immutable->kobj, &immutable_ktype, NULL, "%s", "immutable")) { + kobject_put(&immutable->kobj); + return NULL; + } + + kobject_uevent(&immutable->kobj, KOBJ_ADD); +#endif /* DEFEX_SYSFS_ENABLE */ + immutable->status = 0; + return immutable; +} + +void task_defex_destroy_immutable_obj(struct defex_immutable *immutable) +{ +#ifdef DEFEX_SYSFS_ENABLE + kobject_put(&immutable->kobj); +#endif /* DEFEX_SYSFS_ENABLE */ +} + +#ifdef DEFEX_SYSFS_ENABLE +static struct immutable_attribute immutable_status_attribute = + __ATTR(status, 0600, immutable_status_show, immutable_status_store); + + +static struct attribute *immutable_default_attrs[] = { + &immutable_status_attribute.attr, + NULL, +}; + +static const struct sysfs_ops immutable_sysfs_ops = { + .show = task_defex_immutable_attr_show, + .store = task_defex_immutable_attr_store, +}; + +static struct kobj_type immutable_ktype = { + .sysfs_ops = &immutable_sysfs_ops, + .release = task_defex_immutable_release, + .default_attrs = immutable_default_attrs, +}; +#endif /* DEFEX_SYSFS_ENABLE */ diff --git a/security/defex_lsm/defex_priv.c b/security/defex_lsm/feature_privilege_escalation_detection/defex_priv.c similarity index 99% rename from security/defex_lsm/defex_priv.c rename to security/defex_lsm/feature_privilege_escalation_detection/defex_priv.c index 8c2b13525bcf..f3213cb0b63b 100755 --- a/security/defex_lsm/defex_priv.c +++ b/security/defex_lsm/feature_privilege_escalation_detection/defex_priv.c @@ -6,7 +6,6 @@ * as published by the Free Software Foundation. */ -#include #include #include #include @@ -112,7 +111,6 @@ void task_defex_destroy_privesc_obj(struct defex_privesc *privesc) static struct privesc_attribute privesc_status_attribute = __ATTR(status, 0660, task_defex_privesc_show_status, task_defex_privesc_store_status); - static struct attribute *privesc_default_attrs[] = { &privesc_status_attribute.attr, NULL, diff --git a/security/defex_lsm/defex_safeplace.c b/security/defex_lsm/feature_safeplace/defex_safeplace.c similarity index 97% rename from security/defex_lsm/defex_safeplace.c rename to security/defex_lsm/feature_safeplace/defex_safeplace.c index 10e0189d3570..3f7a70296cbc 100755 --- a/security/defex_lsm/defex_safeplace.c +++ b/security/defex_lsm/feature_safeplace/defex_safeplace.c @@ -6,7 +6,6 @@ * as published by the Free Software Foundation. */ -#include #include #include #include @@ -56,7 +55,7 @@ ssize_t task_defex_safeplace_attr_store(struct kobject *kobj, return attribute->store(safeplace, attribute, buf, len); } -static void task_defex_safeplace_release(struct kobject *kobj) +__visible_for_testing void task_defex_safeplace_release(struct kobject *kobj) { struct defex_safeplace *safeplace_obj; diff --git a/security/defex_lsm/include/defex_config.h b/security/defex_lsm/include/defex_config.h index 6598cf9ad5d0..6731b9b2c4ed 100755 --- a/security/defex_lsm/include/defex_config.h +++ b/security/defex_lsm/include/defex_config.h @@ -26,12 +26,18 @@ #define GLOBAL_SAFEPLACE_STATUS FEATURE_SAFEPLACE #endif +#ifdef DEFEX_PERMISSIVE_IM +#define GLOBAL_IMMUTABLE_STATUS (FEATURE_IMMUTABLE | FEATURE_IMMUTABLE_SOFT) +#else +#define GLOBAL_IMMUTABLE_STATUS FEATURE_IMMUTABLE +#endif + /* Uncomment for Kernels, that require it */ #define STRICT_UID_TYPE_CHECKS 1 -#if defined(DEFEX_PED_ENABLE) || defined(DEFEX_SAFEPLACE_ENABLE) +#if defined(DEFEX_PED_ENABLE) || defined(DEFEX_SAFEPLACE_ENABLE) || defined(DEFEX_IMMUTABLE_ENABLE) #define DEFEX_FEATURE_ENABLE -#endif /* DEFEX_PED_ENABLE || DEFEX_SAFEPLACE_ENABLE */ +#endif /* DEFEX_PED_ENABLE || DEFEX_SAFEPLACE_ENABLE || DEFEX_IMMUTABLE_ENABLE */ int defex_get_features(void); diff --git a/security/defex_lsm/include/defex_internal.h b/security/defex_lsm/include/defex_internal.h index 729fee50f9ce..66183ab85763 100755 --- a/security/defex_lsm/include/defex_internal.h +++ b/security/defex_lsm/include/defex_internal.h @@ -9,17 +9,23 @@ #ifndef __CONFIG_SECURITY_DEFEX_INTERNAL_H #define __CONFIG_SECURITY_DEFEX_INTERNAL_H -#include +#include #include #include #include +#include #include #include +#include #include #include "defex_config.h" +#ifdef DEFEX_KUNIT_ENABLED +#include +#endif + #define DEFEX_MAJOR_VERSION 2 -#define DEFEX_MINOR_VERSION 0 +#define DEFEX_MINOR_VERSION 6 #define DEFEX_REVISION "rel" /* DEFEX Features */ @@ -30,11 +36,12 @@ #define FEATURE_JAILHOUSE_SOFT (1 << 3) /* reserved for future use */ #define FEATURE_RESTRICT_SYSCALL (1 << 4) /* reserved for future use */ #define FEATURE_RESTRICT_SYSCALL_SOFT (1 << 5) /* reserved for future use */ -#define FEATURE_IMMUTABLE (1 << 6) /* reserved for future use */ -#define FEATURE_SAFEPLACE (1 << 7) -#define FEATURE_SAFEPLACE_SOFT (1 << 8) -#define FEATURE_FIVE (1 << 9) /* reserved for future use */ -#define FEATURE_FIVE_SOFT (1 << 10) /* reserved for future use */ +#define FEATURE_IMMUTABLE (1 << 6) +#define FEATURE_IMMUTABLE_SOFT (1 << 7) +#define FEATURE_SAFEPLACE (1 << 8) +#define FEATURE_SAFEPLACE_SOFT (1 << 9) +#define FEATURE_FIVE (1 << 10) /* reserved for future use */ +#define FEATURE_FIVE_SOFT (1 << 11) /* reserved for future use */ #define FEATURE_CLEAR_ALL (0xFF0000) @@ -46,21 +53,6 @@ #define DEFEX_STARTED 1 -/* DEFEX FLAG ATTRs */ -#define DEFEX_ATTR_PRIVESC_DIR (1 << 0) -#define DEFEX_ATTR_PRIVESC_EXP (1 << 1) -#define DEFEX_ATTR_JAILHOUSE_DIR (1 << 2) /* reserved for future use */ -#define DEFEX_ATTR_JAILHOUSE_EXP (1 << 3) /* reserved for future use */ -#define DEFEX_ATTR_RESTRICT_EXP (1 << 4) /* reserved for future use */ -#define DEFEX_ATTR_RESTRICT_LV1_EXP (1 << 5) /* reserved for future use */ -#define DEFEX_ATTR_SAFEPLACE_DIR (1 << 6) -#define DEFEX_INSIDE_PRIVESC_DIR (1 << 8) -#define DEFEX_OUTSIDE_PRIVESC_DIR (1 << 9) -#define DEFEX_INSIDE_JAILHOUSE_DIR (1 << 10) /* reserved for future use */ -#define DEFEX_OUTSIDE_JAILHOUSE_DIR (1 << 11) /* reserved for future use */ -#define DEFEX_ATTR_IMMUTABLE (1 << 12) /* reserved for future use */ -#define DEFEX_ATTR_IMMUTABLE_WR (1 << 13) /* reserved for future use */ -#define DEFEX_ATTR_FIVE_EXP (1 << 14) /* reserved for future use */ /* -------------------------------------------------------------------------- */ /* Integrity feature */ @@ -68,40 +60,48 @@ #define DEFEX_INTEGRITY_FAIL (1 << 1) -/* -------------------------------------------------------------------------- */ -/* Hash tables */ -/* -------------------------------------------------------------------------- */ -extern DECLARE_HASHTABLE(creds_hash, 15); -void creds_fast_hash_init(void); - /* -------------------------------------------------------------------------- */ /* PrivEsc feature */ /* -------------------------------------------------------------------------- */ #ifdef STRICT_UID_TYPE_CHECKS -#define CHECK_ROOT_CREDS(x) (uid_eq(x->cred->uid, GLOBAL_ROOT_UID) || \ - gid_eq(x->cred->gid, GLOBAL_ROOT_GID) || \ - uid_eq(x->cred->euid, GLOBAL_ROOT_UID) || \ - gid_eq(x->cred->egid, GLOBAL_ROOT_GID)) +#define CHECK_ROOT_CREDS(x) (uid_eq((x)->uid, GLOBAL_ROOT_UID) || \ + gid_eq((x)->gid, GLOBAL_ROOT_GID) || \ + uid_eq((x)->euid, GLOBAL_ROOT_UID) || \ + gid_eq((x)->egid, GLOBAL_ROOT_GID)) #define GLOBAL_SYS_UID KUIDT_INIT(1000) #define GLOBAL_SYS_GID KGIDT_INIT(1000) -#define CHECK_SYS_CREDS(x) (uid_eq(x->cred->uid, GLOBAL_SYS_UID) || \ - gid_eq(x->cred->gid, GLOBAL_SYS_GID) || \ - uid_eq(x->cred->euid, GLOBAL_SYS_UID) || \ - gid_eq(x->cred->egid, GLOBAL_SYS_GID)) +#define CHECK_SYS_CREDS(x) (uid_eq((x)->uid, GLOBAL_SYS_UID) || \ + gid_eq((x)->gid, GLOBAL_SYS_GID) || \ + uid_eq((x)->euid, GLOBAL_SYS_UID) || \ + gid_eq((x)->egid, GLOBAL_SYS_GID)) #define uid_get_value(x) (x.val) #define uid_set_value(x, v) x.val = v #else -#define CHECK_ROOT_CREDS(x) ((x->cred->uid == 0) || (x->cred->gid == 0) || \ - (x->cred->euid == 0) || (x->cred->egid == 0)) +#define CHECK_ROOT_CREDS(x) (((x)->uid == 0) || ((x)->gid == 0) || \ + ((x)->euid == 0) || ((x)->egid == 0)) #define uid_get_value(x) (x) #define uid_set_value(x, v) (x = v) #endif /* STRICT_UID_TYPE_CHECKS */ +#define CRED_FLAGS_PROOT (1 << 0) /* parent is root */ +#define CRED_FLAGS_MAIN_UPDATED (1 << 1) /* main thread's permission updated */ +#define CRED_FLAGS_SUB_UPDATED (1 << 2) /* sub thread's permission updated */ + +#define GET_CREDS(ids_ptr, cred_data_ptr) do { uid = (ids_ptr)->uid; \ + fsuid = (ids_ptr)->fsuid; \ + egid = (ids_ptr)->egid; \ + cred_flags = (cred_data_ptr)->cred_flags; } while(0) + +#define SET_CREDS(ids_ptr, cred_data_ptr) do { (ids_ptr)->uid = uid; \ + (ids_ptr)->fsuid = fsuid; \ + (ids_ptr)->egid = egid; \ + (cred_data_ptr)->cred_flags |= cred_flags; } while(0) + struct defex_privesc { struct kobject kobj; unsigned int status; @@ -121,9 +121,9 @@ extern struct defex_privesc *global_privesc_obj; ssize_t task_defex_privesc_store_status(struct defex_privesc *privesc_obj, struct privesc_attribute *attr, const char *buf, size_t count); -void get_task_creds(int pid, unsigned int *uid_ptr, unsigned int *fsuid_ptr, unsigned int *egid_ptr); -int set_task_creds(int pid, unsigned int uid, unsigned int fsuid, unsigned int egid); -void delete_task_creds(int pid); +void get_task_creds(struct task_struct *p, unsigned int *uid_ptr, unsigned int *fsuid_ptr, unsigned int *egid_ptr, unsigned short *cred_flags_ptr); +int set_task_creds(struct task_struct *p, unsigned int uid, unsigned int fsuid, unsigned int egid, unsigned short cred_flags); +void set_task_creds_tcnt(struct task_struct *p, int addition); int is_task_creds_ready(void); /* -------------------------------------------------------------------------- */ @@ -150,16 +150,84 @@ ssize_t safeplace_status_store(struct defex_safeplace *safeplace_obj, struct safeplace_attribute *attr, const char *buf, size_t count); /* -------------------------------------------------------------------------- */ -/* Defex lookup API */ +/* Immutable feature */ +/* -------------------------------------------------------------------------- */ + +struct defex_immutable { + struct kobject kobj; + unsigned int status; +}; +#define to_immutable_obj(obj) container_of(obj, struct defex_immutable, kobj) + +struct immutable_attribute { + struct attribute attr; + ssize_t (*show)(struct defex_immutable *immutable, struct immutable_attribute *attr, char *buf); + ssize_t (*store)(struct defex_immutable *foo, struct immutable_attribute *attr, const char *buf, size_t count); +}; +#define to_immutable_attr(obj) container_of(obj, struct immutable_attribute, attr) + +struct defex_immutable *task_defex_create_immutable_obj(struct kset *defex_kset); +extern void task_defex_destroy_immutable_obj(struct defex_immutable *immutable); +extern struct defex_immutable *global_immutable_obj; +ssize_t immutable_status_store(struct defex_immutable *immutable_obj, + struct immutable_attribute *attr, const char *buf, size_t count); + /* -------------------------------------------------------------------------- */ +/* Common Helper API */ +/* -------------------------------------------------------------------------- */ + +struct defex_context { + int syscall_no; + struct task_struct *task; + struct file *process_file; + struct file *target_file; + const struct path *process_dpath; + const struct path *target_dpath; + char *process_name; + char *target_name; + char *target_name_buff; + char *process_name_buff; + struct cred cred; +}; +extern const char unknown_file[]; + +struct file *local_fopen(const char *fname, int flags, umode_t mode); +int local_fread(struct file *f, loff_t offset, void *ptr, unsigned long bytes); +void init_defex_context(struct defex_context *dc, int syscall, struct task_struct *p, struct file *f); +void release_defex_context(struct defex_context *dc); +struct file *get_dc_process_file(struct defex_context *dc); +const struct path *get_dc_process_dpath(struct defex_context *dc); +char *get_dc_process_name(struct defex_context *dc); +const struct path *get_dc_target_dpath(struct defex_context *dc); +char *get_dc_target_name(struct defex_context *dc); +struct file *defex_get_source_file(struct task_struct *p); char *defex_get_filename(struct task_struct *p); +char* defex_resolve_filename(const char *name, char **out_buff); +int defex_files_identical(const struct file *f1, const struct file *f2); +static inline void safe_str_free(void *ptr) +{ + if (ptr && ptr != unknown_file) + kfree(ptr); +} + + +/* -------------------------------------------------------------------------- */ +/* Defex lookup API */ +/* -------------------------------------------------------------------------- */ + int rules_lookup(const struct path *dpath, int attribute, struct file *f); +int rules_lookup2(const char *target_file, int attribute, struct file *f); /* -------------------------------------------------------------------------- */ /* Defex init API */ /* -------------------------------------------------------------------------- */ -int defex_init_sysfs(void); +int __init defex_init_sysfs(void); +void __init creds_fast_hash_init(void); + +#ifdef DEFEX_DEPENDING_ON_OEMUNLOCK +extern bool boot_state_unlocked __ro_after_init; +#endif /* DEFEX_DEPENDING_ON_OEMUNLOCK */ #endif /* CONFIG_SECURITY_DEFEX_INTERNAL_H */ diff --git a/security/defex_lsm/include/defex_rules.h b/security/defex_lsm/include/defex_rules.h index 495d85e8a3c5..5f7f07fd3d94 100755 --- a/security/defex_lsm/include/defex_rules.h +++ b/security/defex_lsm/include/defex_rules.h @@ -9,21 +9,31 @@ #ifndef __DEFEX_RULES_H #define __DEFEX_RULES_H -#define STATIC_RULES_MAX_STR 32 -#ifdef DEFEX_INTEGRITY_ENABLE -#define INTEGRITY_LENGTH 32 -#endif /* DEFEX_INTEGRITY_ENABLE */ +#define STATIC_RULES_MAX_STR 32 +#define INTEGRITY_LENGTH 32 +#define FEATURE_NAME_MAX_STR 32 #define GET_ITEM_OFFSET(item_ptr) (((char*)item_ptr) - ((char*)defex_packed_rules)) #define GET_ITEM_PTR(offset) ((struct rule_item_struct *)(((char*)defex_packed_rules) + (offset))) enum feature_types { feature_is_file = 1, - feature_ped_path = 2, - feature_ped_exception = 4, - feature_ped_status = 8, - feature_safeplace_path = 16, - feature_safeplace_status = 32 + feature_for_recovery = 2, + feature_ped_path = 4, + feature_ped_exception = 8, + feature_ped_status = 16, + feature_safeplace_path = 32, + feature_safeplace_status = 64, + feature_immutable_path_open = 128, + feature_immutable_path_write = 256, + feature_immutable_src_exception = 512, + feature_immutable_status = 1024, + feature_umhbin_path = 2048 +}; + +struct feature_match_entry { + char feature_name[FEATURE_NAME_MAX_STR]; + int feature_num; }; struct static_rule { @@ -32,9 +42,14 @@ struct static_rule { }; struct rule_item_struct { - unsigned short int next_file; unsigned short int next_level; - unsigned short int feature_type; + union { + struct { + unsigned short int next_file; + unsigned short int feature_type; + } __attribute__((packed)); + unsigned int data_size; + } __attribute__((packed)); unsigned char size; #ifdef DEFEX_INTEGRITY_ENABLE unsigned char integrity[INTEGRITY_LENGTH]; @@ -45,4 +60,6 @@ struct rule_item_struct { extern const struct static_rule defex_static_rules[]; extern const int static_rule_count; +int check_rules_ready(void); + #endif /* __DEFEX_RULES_H */ diff --git a/security/defex_lsm/include/defex_sign.h b/security/defex_lsm/include/defex_sign.h new file mode 100755 index 000000000000..b41bfc44772b --- /dev/null +++ b/security/defex_lsm/include/defex_sign.h @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. +*/ + +#ifndef __DEFEX_SIGN_H +#define __DEFEX_SIGN_H + +#ifdef DEFEX_DEBUG_ENABLE +#define PR_HEX(X) (int)sizeof(size_t), X +void __init blob(const char *buffer, const size_t bufLen, const int lineSize); +#endif +int __init defex_rules_signature_check(const char *rules_buffer, unsigned int rules_data_size, unsigned int *rules_size); + +#endif /* __DEFEX_SIGN_H */ diff --git a/security/defex_lsm/include/linux/defex.h b/security/defex_lsm/include/linux/defex.h new file mode 100755 index 000000000000..7facbcd62f0a --- /dev/null +++ b/security/defex_lsm/include/linux/defex.h @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd. All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + */ + +#ifndef __CONFIG_SECURITY_DEFEX_H +#define __CONFIG_SECURITY_DEFEX_H + +/* Defex init API */ +int task_defex_enforce(struct task_struct *p, struct file *f, int syscall); +int task_defex_zero_creds(struct task_struct *tsk); +asmlinkage int defex_syscall_enter(long int syscallno, struct pt_regs *regs); +int task_defex_user_exec(const char *new_file); +void __init defex_load_rules(void); +#endif /* CONFIG_SECURITY_DEFEX_H */ diff --git a/security/defex_lsm/pack_rules.c b/security/defex_lsm/pack_rules.c index 8e1f0a384475..6dd09dee75ca 100755 --- a/security/defex_lsm/pack_rules.c +++ b/security/defex_lsm/pack_rules.c @@ -6,8 +6,7 @@ * as published by the Free Software Foundation. */ -#include -#include +#include #include #include #include @@ -15,12 +14,23 @@ #define SAFE_STRCOPY(dst, src) do { strncpy(dst, src, sizeof(dst)); dst[sizeof(dst) - 1] = 0; } while(0) +const struct feature_match_entry feature_match[] = { + {"feature_safeplace_path", feature_safeplace_path}, + {"feature_ped_exception", feature_ped_exception}, + {"feature_immutable_path_open", feature_immutable_path_open}, + {"feature_immutable_path_write", feature_immutable_path_write}, + {"feature_immutable_src_exception", feature_immutable_src_exception}, + {"feature_umhbin_path", feature_umhbin_path}, +}; + +const int feature_match_size = sizeof(feature_match) / sizeof(feature_match[0]); + struct file_list_item { char file_name[PATH_MAX]; #ifdef DEFEX_INTEGRITY_ENABLE char integrity[INTEGRITY_LENGTH * 2 + 1]; #endif /* DEFEX_INTEGRITY_ENABLE */ - unsigned int is_recovery; + int is_recovery; }; struct rule_item_struct *defex_packed_rules; @@ -37,24 +47,26 @@ void process_debug_ifdef(const char *src_str); /* Suplementary functions for packing rules */ struct rule_item_struct *create_file_item(const char *name, int l); struct rule_item_struct *add_file_item(struct rule_item_struct *base, const char *name, int l); -struct rule_item_struct *lookup_dir(struct rule_item_struct *base, const char *name, int l); -struct rule_item_struct *add_file_path(const char *file_path); +struct rule_item_struct *lookup_dir(struct rule_item_struct *base, const char *name, int l, int for_recovery); +struct rule_item_struct *add_file_path(const char *file_path, int for_recovery); struct rule_item_struct *addline2tree(char *src_line, enum feature_types feature); char *extract_rule_text(const char *src_line); -int lookup_tree(const char *file_path, int attribute); +int lookup_tree(const char *file_path, int attribute, int for_recovery); int store_tree(FILE *f, FILE *f_bin); #ifdef DEFEX_INTEGRITY_ENABLE /* Transfer string to hex */ unsigned char ascii_to_hex(unsigned char input); int string_to_hex(unsigned char *input, size_t inputLen, unsigned char *output); +char null_integrity[INTEGRITY_LENGTH * 2 + 1]; #endif /* DEFEX_INTEGRITY_ENABLE */ /* Suplementary functions for reducing rules */ int remove_substr(char *str, const char *part); +void trim_cr_lf(char *str); char* remove_redundant_chars(char *str); int load_file_list(const char *name); -int lookup_file_list(const char *rule); +int lookup_file_list(const char *rule, int for_recovery); /* Main processing functions */ int reduce_rules(const char *source_rules_file, const char *reduced_rules_file, const char *list_file); @@ -104,7 +116,7 @@ struct rule_item_struct *add_file_item(struct rule_item_struct *base, const char return new_item; } -struct rule_item_struct *lookup_dir(struct rule_item_struct *base, const char *name, int l) +struct rule_item_struct *lookup_dir(struct rule_item_struct *base, const char *name, int l, int for_recovery) { struct rule_item_struct *item = NULL; unsigned int offset; @@ -113,14 +125,17 @@ struct rule_item_struct *lookup_dir(struct rule_item_struct *base, const char *n return item; item = GET_ITEM_PTR(base->next_level); do { - if (item->size == l && !memcmp(name, item->name, l)) return item; + if ((!(item->feature_type & feature_is_file) + || (!!(item->feature_type & feature_for_recovery)) == for_recovery) + && item->size == l + && !memcmp(name, item->name, l)) return item; offset = item->next_file; item = GET_ITEM_PTR(offset); } while(offset); return NULL; } -struct rule_item_struct *add_file_path(const char *file_path) +struct rule_item_struct *add_file_path(const char *file_path, int for_recovery) { const char *ptr, *next_separator; struct rule_item_struct *base, *cur_item = NULL; @@ -131,12 +146,12 @@ struct rule_item_struct *add_file_path(const char *file_path) if (!defex_packed_rules) { packfiles_count = 0; packfiles_size = 0; - defex_packed_rules = calloc(4, 1024 * 1024); + defex_packed_rules = calloc(sizeof(struct rule_item_struct), 100 * 1024); if (!defex_packed_rules) { printf("WARNING: Can not create the new item!\n"); exit(-1); } - create_file_item("HEAD", 4); + create_file_item("DEFEX_RULES_FILE", 16); } base = defex_packed_rules; ptr = file_path + 1; @@ -148,12 +163,15 @@ struct rule_item_struct *add_file_path(const char *file_path) l = next_separator - ptr; if (!l) return NULL; /* two slashes in sequence */ - cur_item = lookup_dir(base, ptr, l); + cur_item = lookup_dir(base, ptr, l, for_recovery); if (!cur_item) { cur_item = add_file_item(base, ptr, l); /* slash wasn't found, it's a file */ - if (!next_separator) + if (!next_separator) { cur_item->feature_type |= feature_is_file; + if (for_recovery) + cur_item->feature_type |= feature_for_recovery; + } } base = cur_item; ptr += l; @@ -163,7 +181,7 @@ struct rule_item_struct *add_file_path(const char *file_path) return cur_item; } -int lookup_tree(const char *file_path, int attribute) +int lookup_tree(const char *file_path, int attribute, int for_recovery) { const char *ptr, *next_separator; struct rule_item_struct *base, *cur_item = NULL; @@ -181,7 +199,7 @@ int lookup_tree(const char *file_path, int attribute) l = next_separator - ptr; if (!l) return 0; - cur_item = lookup_dir(base, ptr, l); + cur_item = lookup_dir(base, ptr, l, for_recovery); if (!cur_item) break; if (cur_item->feature_type & attribute) @@ -225,7 +243,7 @@ unsigned char ascii_to_hex(unsigned char input) int string_to_hex(unsigned char *input, size_t inputLen, unsigned char *output) { - char convert1, convert2; + unsigned char convert1, convert2; size_t i; if (input == NULL || output == NULL) @@ -243,7 +261,7 @@ int string_to_hex(unsigned char *input, size_t inputLen, unsigned char *output) if (convert1 == 0xFF || convert2 == 0xFF) return 0; - output[i] = (convert1 << 4) | convert2; + output[i] = (char)((convert1 << 4) | convert2); } return 1; @@ -256,32 +274,47 @@ struct rule_item_struct *addline2tree(char *src_line, enum feature_types feature char *str; #ifdef DEFEX_INTEGRITY_ENABLE - unsigned char *integrity; + unsigned char *integrity, *n_sign = NULL, *r_sign = NULL; int value; #endif /* DEFEX_INTEGRITY_ENABLE */ str = extract_rule_text(src_line); - if (str == NULL) + if (!str) return NULL; -#ifdef DEFEX_INTEGRITY_ENABLE - integrity = (unsigned char *)extract_rule_text(str + strnlen(str, PATH_MAX) +1); -#endif /* DEFEX_INTEGRITY_ENABLE */ - - if (str) { - item = add_file_path(str); +#ifndef DEFEX_INTEGRITY_ENABLE + item = add_file_path(str, 0); + if (item) + item->feature_type |= feature; +#else + integrity = (unsigned char *)extract_rule_text(str + strnlen(str, PATH_MAX) + 1); + if (integrity) { + n_sign = (unsigned char *)strchr((const char *)integrity, 'N'); + r_sign = (unsigned char *)strchr((const char *)integrity, 'R'); + } + if (!(n_sign == NULL && r_sign != NULL)) { + item = add_file_path(str, 0); if (item) { item->feature_type |= feature; - -#ifdef DEFEX_INTEGRITY_ENABLE - if (integrity) { - value = string_to_hex(integrity, INTEGRITY_LENGTH * 2, item->integrity); + if (n_sign) { + value = string_to_hex(n_sign + 1, INTEGRITY_LENGTH * 2, item->integrity); if (!value) return NULL; } -#endif /* DEFEX_INTEGRITY_ENABLE */ + + } + } + if (r_sign != NULL) { + item = add_file_path(str, 1); + if (item) { + item->feature_type |= feature; + value = string_to_hex(r_sign + 1, INTEGRITY_LENGTH * 2, item->integrity); + if (!value) + return NULL; + } } +#endif /* DEFEX_INTEGRITY_ENABLE */ return item; } @@ -291,7 +324,11 @@ int store_tree(FILE *f, FILE *f_bin) static char work_str[4096]; int i, offset = 0, index = 0; + if (packfiles_size) + defex_packed_rules->data_size = packfiles_size; + work_str[0] = 0; + fprintf(f, "#ifndef DEFEX_RAMDISK_ENABLE\n\n"); fprintf(f, "const unsigned char defex_packed_rules[] = {\n"); for (i = 0; i < packfiles_size; i++) { if (index) @@ -307,6 +344,8 @@ int store_tree(FILE *f, FILE *f_bin) if (index) fprintf(f, "\t%s\n", work_str); fprintf(f, "};\n"); + fprintf(f, "\n#endif /* DEFEX_RAMDISK_ENABLE */\n\n"); + fprintf(f, "#define DEFEX_RULES_ARRAY_SIZE\t\t%d\n", packfiles_size); if (f_bin) fwrite(defex_packed_rules, 1, packfiles_size, f_bin); return 0; @@ -327,14 +366,9 @@ int remove_substr(char *str, const char *part) return found; } -char* remove_redundant_chars(char *str) +void trim_cr_lf(char *str) { - int l; char *ptr; - - /* skip hash values in the begin */ - str += 65; - /* remove CR or LF at the end */ ptr = strchr(str, '\r'); if (ptr) @@ -342,6 +376,15 @@ char* remove_redundant_chars(char *str) ptr = strchr(str, '\n'); if (ptr) *ptr = 0; +} + +char* remove_redundant_chars(char *str) +{ + int l; + + /* skip hash values in the begin */ + str += 65; + trim_cr_lf(str); l = strnlen(str, PATH_MAX - 1); /* remove starting dot or space */ while(l && (*str == '.' || *str == ' ')) @@ -366,11 +409,15 @@ int load_file_list(const char *name) str = remove_redundant_chars(work_str); if (*str == '/' && (!strncmp(str, "/root/", 6) || + !strncmp(str, "/product/", 9) || !strncmp(str, "/recovery/", 10) || !strncmp(str, "/system/", 8) || !strncmp(str, "/tmp/", 5) || !strncmp(str, "/vendor/", 8) || - !strncmp(str, "/data/", 6))) { +#if defined(DEFEX_FACTORY_ENABLE) + !strncmp(str, "/data/", 6) || +#endif + !strncmp(str, "/apex/", 6))) { remove_substr(str, "/root/"); found = remove_substr(str, "/recovery/"); file_list_count++; @@ -387,12 +434,13 @@ int load_file_list(const char *name) return 0; } -int lookup_file_list(const char *rule) +int lookup_file_list(const char *rule, int for_recovery) { int i; for (i = 0; i < file_list_count; i++) { - if (!strncmp(file_list[i].file_name, rule, strnlen(rule, PATH_MAX)) + if (file_list[i].is_recovery == for_recovery + && !strncmp(file_list[i].file_name, rule, strnlen(rule, PATH_MAX)) && !strncmp(file_list[i].file_name, rule, strnlen(file_list[i].file_name, PATH_MAX))) return i+1; } @@ -426,12 +474,30 @@ void process_debug_ifdef(const char *src_str) } #endif +static int str_to_feature(const char *str) +{ + int i; + + for (i = 0; i < feature_match_size; i++) { + if (strstr(str, feature_match[i].feature_name)) { + return feature_match[i].feature_num; + } + } + + return 0; +} + int reduce_rules(const char *source_rules_file, const char *reduced_rules_file, const char *list_file) { - int exist = 0, ret_val = -1; - char *ptr, *rule; + int ret_val = -1; + int found_normal = 0, found_recovery = 0; + char *rule; static char work_str[PATH_MAX*2], tmp_str[PATH_MAX*2]; FILE *src_file = NULL, *dst_file = NULL; +#ifdef DEFEX_INTEGRITY_ENABLE + char *line_end, *integrity_normal; + char *integrity_recovery; +#endif /* DEFEX_INTEGRITY_ENABLE */ src_file = fopen(source_rules_file, "r"); if (!src_file) @@ -443,36 +509,60 @@ int reduce_rules(const char *source_rules_file, const char *reduced_rules_file, if (load_file_list(list_file) != 0) goto do_close1; +#ifdef DEFEX_INTEGRITY_ENABLE + memset(null_integrity, '0', sizeof(null_integrity) - 1); + null_integrity[sizeof(null_integrity) - 1] = 0; +#endif /* DEFEX_INTEGRITY_ENABLE */ + while(!feof(src_file)) { if (!fgets(work_str, sizeof(work_str), src_file)) break; - ptr = strstr(work_str, "feature_safeplace_path"); - if (!ptr) - ptr = strstr(work_str, "feature_ped_exception"); - if (ptr) { + if (str_to_feature(work_str)) { + trim_cr_lf(work_str); SAFE_STRCOPY(tmp_str, work_str); rule = extract_rule_text(tmp_str); - exist = lookup_file_list(rule); - if (rule && !exist && !strstr(work_str, "/* DEFAULT */")) { - printf("- removed rule: %s\n", rule); + found_normal = lookup_file_list(rule, 0); + found_recovery = lookup_file_list(rule, 1); + if (rule && !found_normal && !found_recovery && !strstr(work_str, "/* DEFAULT */")) { + printf("removed rule: %s\n", rule); continue; } - } #ifdef DEFEX_INTEGRITY_ENABLE - if (exist) { + integrity_normal = null_integrity; + integrity_recovery = null_integrity; + if (found_normal) + integrity_normal = file_list[found_normal - 1].integrity; + if (found_recovery) + integrity_recovery = file_list[found_recovery - 1].integrity; + + line_end = strstr(work_str, "},"); + if (line_end) { + *line_end = 0; + line_end += 2; + } + /* Add hash vale after each file path */ - printf("remained rule: %s, %s\n", rule, file_list[exist-1].integrity); - work_str[strnlen(work_str, PATH_MAX)-3]=0; - fputs(work_str, dst_file); - fputs(",\"", dst_file); - fputs(file_list[exist-1].integrity, dst_file); - fputs("\"},\n", dst_file); - exist = 0; - } + if (found_normal || (!found_normal && !found_recovery)) + printf("remained rule: %s, %s %s\n", rule, integrity_normal, (line_end != NULL)?line_end:""); + if (found_recovery) + printf("remained rule: %s, %s %s\n", rule, integrity_recovery, (line_end != NULL)?line_end:""); + + fprintf(dst_file, "%s,\"", work_str); + if (found_normal) + fprintf(dst_file, "N%s", integrity_normal); + if (found_recovery) + fprintf(dst_file, "R%s", integrity_recovery); + + fprintf(dst_file, "\"}, %s\n", (line_end != NULL)?line_end:""); + #else - fputs(work_str, dst_file); + printf("remained rule: %s\n", work_str); + fputs(work_str, dst_file); + fputs("\n", dst_file); #endif /* DEFEX_INTEGRITY_ENABLE */ + } else + fputs(work_str, dst_file); } ret_val = 0; do_close1: @@ -485,7 +575,7 @@ do_close2: int pack_rules(const char *source_rules_file, const char *packed_rules_file, const char *packed_rules_binfile) { int ret_val = -1; - char *ptr; + int feature; FILE *src_file = NULL, *dst_file = NULL, *dst_binfile = NULL; static char work_str[PATH_MAX*2]; @@ -508,15 +598,9 @@ int pack_rules(const char *source_rules_file, const char *packed_rules_file, con process_debug_ifdef(work_str); if (!debug_ifdef_is_active) { #endif - ptr = strstr(work_str, "feature_safeplace_path"); - if (ptr) { - addline2tree(work_str, feature_safeplace_path); - continue; - } - - ptr = strstr(work_str, "feature_ped_exception"); - if (ptr) { - addline2tree(work_str, feature_ped_exception); + feature = str_to_feature(work_str); + if (feature) { + addline2tree(work_str, feature); continue; } #ifndef DEFEX_DEBUG_ENABLE @@ -539,35 +623,44 @@ do_close2: int main(int argc, char **argv) { - static char param1[PATH_MAX], param2[PATH_MAX], param3[PATH_MAX]; + static char param[4][PATH_MAX]; + char *src_file = NULL, *packed_file = NULL, *packed_bin_file = NULL; + char *reduced_file = NULL, *list_file = NULL; + int i; - if (argc >= 4 && argc <= 5) { - SAFE_STRCOPY(param1, argv[2]); - SAFE_STRCOPY(param2, argv[3]); - if (argc == 5) { - SAFE_STRCOPY(param3, argv[4]); - } - if (argc == 5 && !strncmp(argv[1], "-r", 2)) { - if (reduce_rules(param1, param2, param3) != 0) - goto show_help; + if (argc < 4 || argc > 5) + goto show_help; + + for(i = 0; i < (argc - 2); i++) { + SAFE_STRCOPY(param[i], argv[i + 2]); + switch(i) { + case 0: + src_file = param[i]; + break; + case 1: + packed_file = reduced_file = param[i]; + break; + case 2: + packed_bin_file = list_file = param[i]; + break; } + } - if (argc == 4 && !strncmp(argv[1], "-p", 2)) { - if (pack_rules(param1, param2, NULL) != 0) - goto show_help; - } + if (!strncmp(argv[1], "-p", 2)) { + if (pack_rules(src_file, packed_file, packed_bin_file) != 0) + goto show_help; + return 0; - if (argc == 5 && !strncmp(argv[1], "-p", 2)) { - if (pack_rules(param1, param2, param3) != 0) - goto show_help; - } + } else if (!strncmp(argv[1], "-r", 2) && list_file) { + if (reduce_rules(src_file, reduced_file, list_file) != 0) + goto show_help; return 0; } show_help: printf("Defex rules processing utility.\nUSAGE:\n%s \n" "Commands:\n" - " -p - Pack rules file to the tree. Params: \n" + " -p - Pack rules file to the tree. Params: [PACKED_BIN_FILE]\n" " -r - Reduce rules file (remove unexistent files). Params: \n", argv[0]); return -1; diff --git a/security/defex_lsm/security_defex_lsm.py b/security/defex_lsm/security_defex_lsm.py new file mode 100755 index 000000000000..b3525d5f8993 --- /dev/null +++ b/security/defex_lsm/security_defex_lsm.py @@ -0,0 +1,99 @@ +config = { + "header": { + "uuid": "26aca962-0907-423d-99cb-e95b31eca255", + "type": "SECURITY", + "vendor": "SAMSUNG", + "product": "defex_lsm", + "variant": "defex_lsm", + "name": "defex_lsm", + }, + "build": { + "path": "security/defex_lsm", + "file": "security_defex_lsm.py", + "location": [ + { + "src": "*.c Makefile:update Kconfig:update", + "dst": "security/samsung/defex_lsm/", + }, + { + "src": "catch_engine/*", + "dst": "security/samsung/defex_lsm/catch_engine/", + }, + { + "src": "cert/*", + "dst": "security/samsung/defex_lsm/cert/", + }, + { + "src": "core/*", + "dst": "security/samsung/defex_lsm/core/", + }, + { + "src": "debug/*", + "dst": "security/samsung/defex_lsm/debug/", + }, + { + "src": "feature_immutable/*", + "dst": "security/samsung/defex_lsm/feature_immutable/", + }, + { + "src": "feature_privilege_escalation_detection/*", + "dst": "security/samsung/defex_lsm/feature_privilege_escalation_detection/", + }, + { + "src": "feature_safeplace/*", + "dst": "security/samsung/defex_lsm/feature_safeplace/", + }, + { + "src": "include/*.h", + "dst": "security/samsung/defex_lsm/include/", + }, + { + "src": "include/linux/defex.h", + "dst": "include/linux/defex.h", + }, + ], + }, + "features": [ + { + "label": "General", + "type": "boolean", + "configs": { + "True": [ + "# CONFIG_SECURITY_DEFEX is not set" + ], + "False": [], + }, + "value": True, + } + ], + "kunit_test": { + "build": { + "location": [ + { + "dst": "security/samsung/defex_lsm/kunit_test/", + "src": "kunit_test/*.c kunit_test/Makefile:cp", + }, + ], + }, + "features": [ + { + "label": "default", + "configs": { + "True": [ + "CONFIG_SECURITY_DEFEX=y", + ], + "False": [], + }, + "type": "boolean", + }, + ] + }, +} + + +def load(): + return config + + +if __name__ == "__main__": + print(load()) diff --git a/security/samsung/defex_lsm/core/defex_main.c b/security/samsung/defex_lsm/core/defex_main.c index 1afe55fd845c..18b527a478c1 100755 --- a/security/samsung/defex_lsm/core/defex_main.c +++ b/security/samsung/defex_lsm/core/defex_main.c @@ -180,7 +180,8 @@ __visible_for_testing int task_defex_is_secured(struct defex_context *dc) return DEFEX_ALLOW; } - if (!strncmp(p->comm, "ding:background", strlen(p->comm))) { + if (!strncmp(p->comm, "ding:background", strlen(p->comm)) \ + || !strncmp(p->comm, "android.vending", strlen(p->comm))) { return DEFEX_ALLOW; } diff --git a/security/samsung/five/five_porting.h b/security/samsung/five/five_porting.h index cf197937a93a..743807a44409 100755 --- a/security/samsung/five/five_porting.h +++ b/security/samsung/five/five_porting.h @@ -213,7 +213,7 @@ static inline struct dentry *d_real_comp(struct dentry *dentry) #else static inline struct dentry *d_real_comp(struct dentry *dentry) { - return d_real(dentry, NULL); + return d_real(dentry, d_real_inode(dentry)); } #endif diff --git a/techpack/audio/asoc/msm-pcm-routing-v2.c b/techpack/audio/asoc/msm-pcm-routing-v2.c index 9210c9622c3d..a7cb94fce4d5 100755 --- a/techpack/audio/asoc/msm-pcm-routing-v2.c +++ b/techpack/audio/asoc/msm-pcm-routing-v2.c @@ -72,7 +72,7 @@ static int quat_mi2s_switch_enable; static int quin_mi2s_switch_enable; static int fm_pcmrx_switch_enable; static int usb_switch_enable; -static int lsm_port_index; +static int lsm_port_index[MAX_LSM_SESSIONS]; static int slim0_rx_aanc_fb_port; static int msm_route_ec_ref_rx; static int msm_ec_ref_ch = 4; @@ -1265,9 +1265,10 @@ static bool route_check_fe_id_adm_support(int fe_id) if ((fe_id >= MSM_FRONTEND_DAI_LSM1) && (fe_id <= MSM_FRONTEND_DAI_LSM8)) { /* fe id is listen while port is set to afe */ - if (lsm_port_index != ADM_LSM_PORT_INDEX) { + if (lsm_port_index[fe_id - MSM_FRONTEND_DAI_LSM1] != + ADM_LSM_PORT_INDEX) { pr_debug("%s: fe_id %d, lsm mux slim port %d\n", - __func__, fe_id, lsm_port_index); + __func__, fe_id, lsm_port_index[fe_id - MSM_FRONTEND_DAI_LSM1]); rc = false; } } @@ -2666,10 +2667,44 @@ static int msm_routing_put_fm_pcmrx_switch_mixer(struct snd_kcontrol *kcontrol, return 1; } +static void msm_routing_get_lsm_fe_idx(struct snd_kcontrol *kcontrol, + u8 *fe_idx) +{ + int fe_id = MSM_FRONTEND_DAI_LSM1; + + if (strnstr(kcontrol->id.name, "LSM1", sizeof("LSM1"))) { + fe_id = MSM_FRONTEND_DAI_LSM1; + } else if (strnstr(kcontrol->id.name, "LSM2", sizeof("LSM2"))) { + fe_id = MSM_FRONTEND_DAI_LSM2; + } else if (strnstr(kcontrol->id.name, "LSM3", sizeof("LSM3"))) { + fe_id = MSM_FRONTEND_DAI_LSM3; + } else if (strnstr(kcontrol->id.name, "LSM4", sizeof("LSM4"))) { + fe_id = MSM_FRONTEND_DAI_LSM4; + } else if (strnstr(kcontrol->id.name, "LSM5", sizeof("LSM5"))) { + fe_id = MSM_FRONTEND_DAI_LSM5; + } else if (strnstr(kcontrol->id.name, "LSM6", sizeof("LSM6"))) { + fe_id = MSM_FRONTEND_DAI_LSM6; + } else if (strnstr(kcontrol->id.name, "LSM7", sizeof("LSM7"))) { + fe_id = MSM_FRONTEND_DAI_LSM7; + } else if (strnstr(kcontrol->id.name, "LSM8", sizeof("LSM8"))) { + fe_id = MSM_FRONTEND_DAI_LSM8; + } else { + pr_err("%s: Invalid kcontrol name:%s\n", __func__, + kcontrol->id.name); + return; + } + + *fe_idx = fe_id - MSM_FRONTEND_DAI_LSM1; + pr_debug("%s: fe_id: %d, fe_idx:%d\n", __func__, fe_id, *fe_idx); +} + + static int msm_routing_lsm_port_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - ucontrol->value.integer.value[0] = lsm_port_index; + u8 fe_idx = 0; + msm_routing_get_lsm_fe_idx(kcontrol, &fe_idx); + ucontrol->value.integer.value[0] = lsm_port_index[fe_idx]; return 0; } @@ -2679,7 +2714,9 @@ static int msm_routing_lsm_port_put(struct snd_kcontrol *kcontrol, struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; int mux = ucontrol->value.enumerated.item[0]; int lsm_port = AFE_PORT_ID_SLIMBUS_MULTI_CHAN_5_TX; - + int lsm_port_idx = 0; + u8 fe_idx = 0; + if (mux >= e->items) { pr_err("%s: Invalid mux value %d\n", __func__, mux); return -EINVAL; @@ -2687,6 +2724,7 @@ static int msm_routing_lsm_port_put(struct snd_kcontrol *kcontrol, pr_debug("%s: LSM enable %ld\n", __func__, ucontrol->value.integer.value[0]); + lsm_port_idx = ucontrol->value.integer.value[0]; switch (ucontrol->value.integer.value[0]) { case 1: lsm_port = AFE_PORT_ID_SLIMBUS_MULTI_CHAN_0_TX; @@ -2735,8 +2773,13 @@ static int msm_routing_lsm_port_put(struct snd_kcontrol *kcontrol, break; } set_lsm_port(lsm_port); - lsm_port_index = ucontrol->value.integer.value[0]; - + msm_routing_get_lsm_fe_idx(kcontrol, &fe_idx); + lsm_port_index[fe_idx] = ucontrol->value.integer.value[0]; + /* Set the default AFE LSM Port to 0xffff */ + if(lsm_port_idx <= 0 || lsm_port_idx >= ARRAY_SIZE(lsm_port_text)) + lsm_port = 0xffff; + afe_set_lsm_afe_port_id(fe_idx, lsm_port); + return 0; } diff --git a/techpack/audio/dsp/q6afe.c b/techpack/audio/dsp/q6afe.c index 78d045090c5f..c21ecc908e12 100755 --- a/techpack/audio/dsp/q6afe.c +++ b/techpack/audio/dsp/q6afe.c @@ -38,6 +38,7 @@ #include #endif /*CONFIG_TAS25XX_ALGO*/ #define WAKELOCK_TIMEOUT 5000 +#define MAX_LSM_SESSIONS 8 #ifdef CONFIG_TAS25XX_ALGO static int32_t smartamp_algo_callback(uint32_t opcode, uint32_t *payload, @@ -176,6 +177,7 @@ struct afe_ctl { /* FTM spk params */ uint32_t initial_cal; uint32_t v_vali_flag; + int lsm_afe_ports[MAX_LSM_SESSIONS]; #ifdef CONFIG_TAS25XX_ALGO struct afe_smartamp_calib_get_resp smart_amp_calib_data; #endif /*CONFIG_TAS25XX_ALGO*/ @@ -196,6 +198,8 @@ bool afe_close_done[2] = {true, true}; #define SIZEOF_CFG_CMD(y) \ (sizeof(struct apr_hdr) + sizeof(u16) + (sizeof(struct y))) +static bool q6afe_is_afe_lsm_port(int port_id); + static int afe_get_cal_hw_delay(int32_t path, struct audio_cal_hw_delay_entry *entry); static int remap_cal_data(struct cal_block_data *cal_block, int cal_index); @@ -2433,7 +2437,7 @@ static int afe_send_port_topology_id(u16 port_id) } ret = afe_get_cal_topology_id(port_id, &topology_id, AFE_TOPOLOGY_CAL); - if (ret < 0) { + if (ret < 0 && q6afe_is_afe_lsm_port(port_id)) { pr_debug("%s: Check for LSM topology\n", __func__); ret = afe_get_cal_topology_id(port_id, &topology_id, AFE_LSM_TOPOLOGY_CAL); @@ -2751,7 +2755,7 @@ void afe_send_cal(u16 port_id) if (afe_get_port_type(port_id) == MSM_AFE_PORT_TYPE_TX) { afe_send_cal_spkr_prot_tx(port_id); ret = send_afe_cal_type(AFE_COMMON_TX_CAL, port_id); - if (ret < 0) + if (ret < 0 && q6afe_is_afe_lsm_port(port_id)) send_afe_cal_type(AFE_LSM_TX_CAL, port_id); } else if (afe_get_port_type(port_id) == MSM_AFE_PORT_TYPE_RX) { send_afe_cal_type(AFE_COMMON_RX_CAL, port_id); @@ -9233,3 +9237,29 @@ done: } EXPORT_SYMBOL(afe_unvote_lpass_core_hw); +static bool q6afe_is_afe_lsm_port(int port_id) +{ + int i = 0; + + for (i = 0; i < MAX_LSM_SESSIONS; i++) { + if (port_id == this_afe.lsm_afe_ports[i]) + return true; + } + return false; +} + +/** + * afe_set_lsm_afe_port_id - + * Update LSM AFE port + * idx: LSM port index + * lsm_port: LSM port id +*/ +void afe_set_lsm_afe_port_id(int idx, int lsm_port) +{ + if (idx < 0 || idx >= MAX_LSM_SESSIONS) { + pr_err("%s: %d Invalid lsm port index\n", __func__, idx); + return; + } + this_afe.lsm_afe_ports[idx] = lsm_port; +} +EXPORT_SYMBOL(afe_set_lsm_afe_port_id); \ No newline at end of file diff --git a/techpack/audio/include/dsp/q6afe-v2.h b/techpack/audio/include/dsp/q6afe-v2.h index 2310537403f6..897fd9d7d969 100755 --- a/techpack/audio/include/dsp/q6afe-v2.h +++ b/techpack/audio/include/dsp/q6afe-v2.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2020, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2020, 2021, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -467,6 +467,7 @@ int afe_send_port_island_mode(u16 port_id); int afe_send_cmd_wakeup_register(void *handle, bool enable); void afe_register_wakeup_irq_callback( void (*afe_cb_wakeup_irq)(void *handle)); +void afe_set_lsm_afe_port_id(int idx, int lsm_port); #define AFE_LPASS_CORE_HW_BLOCK_ID_NONE 0 #define AFE_LPASS_CORE_HW_BLOCK_ID_AVTIMER 2 diff --git a/techpack/audio/include/dsp/q6lsm.h b/techpack/audio/include/dsp/q6lsm.h index f3eecf73b807..bc10bcd71be7 100755 --- a/techpack/audio/include/dsp/q6lsm.h +++ b/techpack/audio/include/dsp/q6lsm.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2019, 2021, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -27,6 +27,7 @@ #define LSM_V3P0_MAX_NUM_CHANNELS 9 #define LSM_API_VERSION_V3 3 +#define MAX_LSM_SESSIONS 8 typedef void (*lsm_app_cb)(uint32_t opcode, uint32_t token, uint32_t *payload, uint16_t client_size, void *priv); diff --git a/tools/dtc b/tools/dtc index 4224af39d5ec..6f5ee6250000 100755 Binary files a/tools/dtc and b/tools/dtc differ