Merge "[[rdkb][tops] add config file for ccn34 project]"
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/pinctrl/mediatek/pinctrl-mt7981.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/pinctrl/mediatek/pinctrl-mt7981.c
index 2e91034..4f0f145 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/pinctrl/mediatek/pinctrl-mt7981.c
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/pinctrl/mediatek/pinctrl-mt7981.c
@@ -436,6 +436,39 @@
PIN_FIELD_BASE(39, 39, 3, 0x40, 0x10, 1, 1),
};
+static const unsigned int mt7981_pull_type[] = {
+ MTK_PULL_PUPD_R1R0_TYPE,/*0*/ MTK_PULL_PUPD_R1R0_TYPE,/*1*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*2*/ MTK_PULL_PUPD_R1R0_TYPE,/*3*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*4*/ MTK_PULL_PUPD_R1R0_TYPE,/*5*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*6*/ MTK_PULL_PUPD_R1R0_TYPE,/*7*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*8*/ MTK_PULL_PUPD_R1R0_TYPE,/*9*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*10*/ MTK_PULL_PUPD_R1R0_TYPE,/*11*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*12*/ MTK_PULL_PUPD_R1R0_TYPE,/*13*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*14*/ MTK_PULL_PUPD_R1R0_TYPE,/*15*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*16*/ MTK_PULL_PUPD_R1R0_TYPE,/*17*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*18*/ MTK_PULL_PUPD_R1R0_TYPE,/*19*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*20*/ MTK_PULL_PUPD_R1R0_TYPE,/*21*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*22*/ MTK_PULL_PUPD_R1R0_TYPE,/*23*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*24*/ MTK_PULL_PUPD_R1R0_TYPE,/*25*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*26*/ MTK_PULL_PUPD_R1R0_TYPE,/*27*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*28*/ MTK_PULL_PUPD_R1R0_TYPE,/*29*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*30*/ MTK_PULL_PUPD_R1R0_TYPE,/*31*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*32*/ MTK_PULL_PUPD_R1R0_TYPE,/*33*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*34*/ MTK_PULL_PUPD_R1R0_TYPE,/*35*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*36*/ MTK_PULL_PUPD_R1R0_TYPE,/*37*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*38*/ MTK_PULL_PUPD_R1R0_TYPE,/*39*/
+ MTK_PULL_PU_PD_TYPE,/*40*/ MTK_PULL_PU_PD_TYPE,/*41*/
+ MTK_PULL_PU_PD_TYPE,/*42*/ MTK_PULL_PU_PD_TYPE,/*43*/
+ MTK_PULL_PU_PD_TYPE,/*44*/ MTK_PULL_PU_PD_TYPE,/*45*/
+ MTK_PULL_PU_PD_TYPE,/*46*/ MTK_PULL_PU_PD_TYPE,/*47*/
+ MTK_PULL_PU_PD_TYPE,/*48*/ MTK_PULL_PU_PD_TYPE,/*49*/
+ MTK_PULL_PU_PD_TYPE,/*50*/ MTK_PULL_PU_PD_TYPE,/*51*/
+ MTK_PULL_PU_PD_TYPE,/*52*/ MTK_PULL_PU_PD_TYPE,/*53*/
+ MTK_PULL_PU_PD_TYPE,/*54*/ MTK_PULL_PU_PD_TYPE,/*55*/
+ MTK_PULL_PU_PD_TYPE,/*56*/
+};
+
+
static const struct mtk_pin_reg_calc mt7981_reg_cals[] = {
[PINCTRL_PIN_REG_MODE] = MTK_RANGE(mt7981_pin_mode_range),
[PINCTRL_PIN_REG_DIR] = MTK_RANGE(mt7981_pin_dir_range),
@@ -964,6 +997,9 @@
.bias_disable_get = mtk_pinconf_bias_disable_get,
.bias_set = mtk_pinconf_bias_set,
.bias_get = mtk_pinconf_bias_get,
+ .pull_type = mt7981_pull_type,
+ .bias_set_combo = mtk_pinconf_bias_set_combo,
+ .bias_get_combo = mtk_pinconf_bias_get_combo,
.drive_set = mtk_pinconf_drive_set_rev1,
.drive_get = mtk_pinconf_drive_get_rev1,
.adv_pull_get = mtk_pinconf_adv_pull_get,
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/pinctrl/mediatek/pinctrl-mt7986.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/pinctrl/mediatek/pinctrl-mt7986.c
index b0f4c95..215642a 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/pinctrl/mediatek/pinctrl-mt7986.c
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/pinctrl/mediatek/pinctrl-mt7986.c
@@ -633,6 +633,60 @@
PIN_FIELD_BASE(68, 68, 4, 0x60, 0x10, 4, 1),
};
+static const unsigned int mt7986_pull_type[] = {
+ MTK_PULL_PUPD_R1R0_TYPE,/*0*/ MTK_PULL_PUPD_R1R0_TYPE,/*1*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*2*/ MTK_PULL_PUPD_R1R0_TYPE,/*3*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*4*/ MTK_PULL_PUPD_R1R0_TYPE,/*5*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*6*/ MTK_PULL_PUPD_R1R0_TYPE,/*7*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*8*/ MTK_PULL_PUPD_R1R0_TYPE,/*9*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*10*/ MTK_PULL_PUPD_R1R0_TYPE,/*11*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*12*/ MTK_PULL_PUPD_R1R0_TYPE,/*13*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*14*/ MTK_PULL_PUPD_R1R0_TYPE,/*15*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*16*/ MTK_PULL_PUPD_R1R0_TYPE,/*17*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*18*/ MTK_PULL_PUPD_R1R0_TYPE,/*19*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*20*/ MTK_PULL_PUPD_R1R0_TYPE,/*21*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*22*/ MTK_PULL_PUPD_R1R0_TYPE,/*23*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*24*/ MTK_PULL_PUPD_R1R0_TYPE,/*25*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*26*/ MTK_PULL_PUPD_R1R0_TYPE,/*27*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*28*/ MTK_PULL_PUPD_R1R0_TYPE,/*29*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*30*/ MTK_PULL_PUPD_R1R0_TYPE,/*31*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*32*/ MTK_PULL_PUPD_R1R0_TYPE,/*33*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*34*/ MTK_PULL_PUPD_R1R0_TYPE,/*35*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*36*/ MTK_PULL_PUPD_R1R0_TYPE,/*37*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*38*/ MTK_PULL_PUPD_R1R0_TYPE,/*39*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*40*/ MTK_PULL_PUPD_R1R0_TYPE,/*41*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*42*/ MTK_PULL_PUPD_R1R0_TYPE,/*43*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*44*/ MTK_PULL_PUPD_R1R0_TYPE,/*45*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*46*/ MTK_PULL_PUPD_R1R0_TYPE,/*47*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*48*/ MTK_PULL_PUPD_R1R0_TYPE,/*49*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*50*/ MTK_PULL_PUPD_R1R0_TYPE,/*51*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*52*/ MTK_PULL_PUPD_R1R0_TYPE,/*53*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*54*/ MTK_PULL_PUPD_R1R0_TYPE,/*55*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*56*/ MTK_PULL_PUPD_R1R0_TYPE,/*57*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*58*/ MTK_PULL_PUPD_R1R0_TYPE,/*59*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*60*/ MTK_PULL_PUPD_R1R0_TYPE,/*61*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*62*/ MTK_PULL_PUPD_R1R0_TYPE,/*63*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*64*/ MTK_PULL_PUPD_R1R0_TYPE,/*65*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*66*/ MTK_PULL_PUPD_R1R0_TYPE,/*67*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*68*/ MTK_PULL_PU_PD_TYPE,/*69*/
+ MTK_PULL_PU_PD_TYPE,/*70*/ MTK_PULL_PU_PD_TYPE,/*71*/
+ MTK_PULL_PU_PD_TYPE,/*72*/ MTK_PULL_PU_PD_TYPE,/*73*/
+ MTK_PULL_PU_PD_TYPE,/*74*/ MTK_PULL_PU_PD_TYPE,/*75*/
+ MTK_PULL_PU_PD_TYPE,/*76*/ MTK_PULL_PU_PD_TYPE,/*77*/
+ MTK_PULL_PU_PD_TYPE,/*78*/ MTK_PULL_PU_PD_TYPE,/*79*/
+ MTK_PULL_PU_PD_TYPE,/*80*/ MTK_PULL_PU_PD_TYPE,/*81*/
+ MTK_PULL_PU_PD_TYPE,/*82*/ MTK_PULL_PU_PD_TYPE,/*83*/
+ MTK_PULL_PU_PD_TYPE,/*84*/ MTK_PULL_PU_PD_TYPE,/*85*/
+ MTK_PULL_PU_PD_TYPE,/*86*/ MTK_PULL_PU_PD_TYPE,/*87*/
+ MTK_PULL_PU_PD_TYPE,/*88*/ MTK_PULL_PU_PD_TYPE,/*89*/
+ MTK_PULL_PU_PD_TYPE,/*90*/ MTK_PULL_PU_PD_TYPE,/*91*/
+ MTK_PULL_PU_PD_TYPE,/*92*/ MTK_PULL_PU_PD_TYPE,/*93*/
+ MTK_PULL_PU_PD_TYPE,/*94*/ MTK_PULL_PU_PD_TYPE,/*95*/
+ MTK_PULL_PU_PD_TYPE,/*96*/ MTK_PULL_PU_PD_TYPE,/*97*/
+ MTK_PULL_PU_PD_TYPE,/*98*/ MTK_PULL_PU_PD_TYPE,/*99*/
+ MTK_PULL_PU_PD_TYPE,/*100*/
+};
+
static const struct mtk_pin_reg_calc mt7986_reg_cals[] = {
[PINCTRL_PIN_REG_MODE] = MTK_RANGE(mt7986_pin_mode_range),
[PINCTRL_PIN_REG_DIR] = MTK_RANGE(mt7986_pin_dir_range),
@@ -1065,6 +1119,9 @@
.bias_disable_get = mtk_pinconf_bias_disable_get,
.bias_set = mtk_pinconf_bias_set,
.bias_get = mtk_pinconf_bias_get,
+ .pull_type = mt7986_pull_type,
+ .bias_set_combo = mtk_pinconf_bias_set_combo,
+ .bias_get_combo = mtk_pinconf_bias_get_combo,
.drive_set = mtk_pinconf_drive_set_rev1,
.drive_get = mtk_pinconf_drive_get_rev1,
.adv_pull_get = mtk_pinconf_adv_pull_get,
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/pinctrl/mediatek/pinctrl-mt7988.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/pinctrl/mediatek/pinctrl-mt7988.c
index 49c0be1..2fe1746 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/pinctrl/mediatek/pinctrl-mt7988.c
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/pinctrl/mediatek/pinctrl-mt7988.c
@@ -596,6 +596,51 @@
PIN_FIELD_BASE(83, 83, 1, 0x90, 0x10, 15, 1),
};
+static const unsigned int mt7988_pull_type[] = {
+ MTK_PULL_PUPD_R1R0_TYPE,/*0*/ MTK_PULL_PUPD_R1R0_TYPE,/*1*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*2*/ MTK_PULL_PUPD_R1R0_TYPE,/*3*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*4*/ MTK_PULL_PUPD_R1R0_TYPE,/*5*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*6*/ MTK_PULL_PU_PD_TYPE, /*7*/
+ MTK_PULL_PU_PD_TYPE, /*8*/ MTK_PULL_PU_PD_TYPE, /*9*/
+ MTK_PULL_PU_PD_TYPE, /*10*/ MTK_PULL_PUPD_R1R0_TYPE,/*11*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*12*/ MTK_PULL_PU_PD_TYPE, /*13*/
+ MTK_PULL_PU_PD_TYPE, /*14*/ MTK_PULL_PD_TYPE, /*15*/
+ MTK_PULL_PD_TYPE, /*16*/ MTK_PULL_PD_TYPE, /*17*/
+ MTK_PULL_PD_TYPE, /*18*/ MTK_PULL_PUPD_R1R0_TYPE,/*19*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*20*/ MTK_PULL_PUPD_R1R0_TYPE,/*21*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*22*/ MTK_PULL_PUPD_R1R0_TYPE,/*23*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*24*/ MTK_PULL_PUPD_R1R0_TYPE,/*25*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*26*/ MTK_PULL_PUPD_R1R0_TYPE,/*27*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*28*/ MTK_PULL_PUPD_R1R0_TYPE,/*29*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*30*/ MTK_PULL_PUPD_R1R0_TYPE,/*31*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*32*/ MTK_PULL_PUPD_R1R0_TYPE,/*33*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*34*/ MTK_PULL_PUPD_R1R0_TYPE,/*35*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*36*/ MTK_PULL_PUPD_R1R0_TYPE,/*37*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*38*/ MTK_PULL_PUPD_R1R0_TYPE,/*39*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*40*/ MTK_PULL_PUPD_R1R0_TYPE,/*41*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*42*/ MTK_PULL_PUPD_R1R0_TYPE,/*43*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*44*/ MTK_PULL_PUPD_R1R0_TYPE,/*45*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*46*/ MTK_PULL_PUPD_R1R0_TYPE,/*47*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*48*/ MTK_PULL_PUPD_R1R0_TYPE,/*49*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*50*/ MTK_PULL_PUPD_R1R0_TYPE,/*51*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*52*/ MTK_PULL_PUPD_R1R0_TYPE,/*53*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*54*/ MTK_PULL_PUPD_R1R0_TYPE,/*55*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*56*/ MTK_PULL_PUPD_R1R0_TYPE,/*57*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*58*/ MTK_PULL_PUPD_R1R0_TYPE,/*59*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*60*/ MTK_PULL_PUPD_R1R0_TYPE,/*61*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*62*/ MTK_PULL_PU_PD_TYPE, /*63*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*64*/ MTK_PULL_PUPD_R1R0_TYPE,/*65*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*66*/ MTK_PULL_PUPD_R1R0_TYPE,/*67*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*68*/ MTK_PULL_PUPD_R1R0_TYPE,/*69*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*70*/ MTK_PULL_PD_TYPE, /*71*/
+ MTK_PULL_PD_TYPE, /*72*/ MTK_PULL_PUPD_R1R0_TYPE,/*73*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*74*/ MTK_PULL_PU_PD_TYPE, /*75*/
+ MTK_PULL_PU_PD_TYPE, /*76*/ MTK_PULL_PU_PD_TYPE, /*77*/
+ MTK_PULL_PU_PD_TYPE, /*78*/ MTK_PULL_PU_PD_TYPE, /*79*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*80*/ MTK_PULL_PUPD_R1R0_TYPE,/*81*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*82*/ MTK_PULL_PUPD_R1R0_TYPE,/*83*/
+};
+
static const struct mtk_pin_reg_calc mt7988_reg_cals[] = {
[PINCTRL_PIN_REG_MODE] = MTK_RANGE(mt7988_pin_mode_range),
[PINCTRL_PIN_REG_DIR] = MTK_RANGE(mt7988_pin_dir_range),
@@ -1433,6 +1478,9 @@
.bias_disable_get = mtk_pinconf_bias_disable_get,
.bias_set = mtk_pinconf_bias_set,
.bias_get = mtk_pinconf_bias_get,
+ .pull_type = mt7988_pull_type,
+ .bias_set_combo = mtk_pinconf_bias_set_combo,
+ .bias_get_combo = mtk_pinconf_bias_get_combo,
.drive_set = mtk_pinconf_drive_set_rev1,
.drive_get = mtk_pinconf_drive_get_rev1,
.adv_pull_get = mtk_pinconf_adv_pull_get,
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/mt7988.cfg b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/mt7988.cfg
index d661a18..fb27f0d 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/mt7988.cfg
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/mt7988.cfg
@@ -7,6 +7,7 @@
CONFIG_AQUANTIA_PHY_FW_DOWNLOAD_GANG=y
# CONFIG_AQUANTIA_PHY_FW_DOWNLOAD_SINGLE is not set
CONFIG_AQUANTIA_PHY_FW_FILE="Rhe-05.06-Candidate9-AQR_Mediatek_23B_P5_ID45824_LCLVER1.cld"
+CONFIG_AQUANTIA_PHY_MIB=y
CONFIG_ARCH_CLOCKSOURCE_DATA=y
CONFIG_ARCH_DMA_ADDR_T_64BIT=y
CONFIG_ARCH_KEEP_MEMBLOCK=y
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1000-backport-pinctrl-pinconf-setting-combo.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1000-backport-pinctrl-pinconf-setting-combo.patch
new file mode 100644
index 0000000..43ca0c5
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1000-backport-pinctrl-pinconf-setting-combo.patch
@@ -0,0 +1,632 @@
+--- a/drivers/pinctrl/mediatek/pinctrl-moore.c
++++ b/drivers/pinctrl/mediatek/pinctrl-moore.c
+@@ -99,14 +99,22 @@ static int mtk_pinconf_get(struct pinctr
+ {
+ struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev);
+ u32 param = pinconf_to_config_param(*config);
+- int val, val2, err, reg, ret = 1;
++ int val, val2, err, pullup, reg, ret = 1;
+ const struct mtk_pin_desc *desc;
+
+ desc = (const struct mtk_pin_desc *)&hw->soc->pins[pin];
++ if (!desc->name)
++ return -ENOTSUPP;
+
+ switch (param) {
+ case PIN_CONFIG_BIAS_DISABLE:
+- if (hw->soc->bias_disable_get) {
++ if (hw->soc->bias_get_combo) {
++ err = hw->soc->bias_get_combo(hw, desc, &pullup, &ret);
++ if (err)
++ return err;
++ if (ret != MTK_PUPD_SET_R1R0_00 && ret != MTK_DISABLE)
++ return -EINVAL;
++ } else if (hw->soc->bias_disable_get) {
+ err = hw->soc->bias_disable_get(hw, desc, &ret);
+ if (err)
+ return err;
+@@ -115,7 +123,15 @@ static int mtk_pinconf_get(struct pinctr
+ }
+ break;
+ case PIN_CONFIG_BIAS_PULL_UP:
+- if (hw->soc->bias_get) {
++ if (hw->soc->bias_get_combo) {
++ err = hw->soc->bias_get_combo(hw, desc, &pullup, &ret);
++ if (err)
++ return err;
++ if (ret == MTK_PUPD_SET_R1R0_00 || ret == MTK_DISABLE)
++ return -EINVAL;
++ if (!pullup)
++ return -EINVAL;
++ } else if (hw->soc->bias_get) {
+ err = hw->soc->bias_get(hw, desc, 1, &ret);
+ if (err)
+ return err;
+@@ -124,7 +140,15 @@ static int mtk_pinconf_get(struct pinctr
+ }
+ break;
+ case PIN_CONFIG_BIAS_PULL_DOWN:
+- if (hw->soc->bias_get) {
++ if (hw->soc->bias_get_combo) {
++ err = hw->soc->bias_get_combo(hw, desc, &pullup, &ret);
++ if (err)
++ return err;
++ if (ret == MTK_PUPD_SET_R1R0_00 || ret == MTK_DISABLE)
++ return -EINVAL;
++ if (pullup)
++ return -EINVAL;
++ } else if (hw->soc->bias_get) {
+ err = hw->soc->bias_get(hw, desc, 0, &ret);
+ if (err)
+ return err;
+@@ -218,14 +242,19 @@ static int mtk_pinconf_set(struct pinctr
+ int cfg, err = 0;
+
+ desc = (const struct mtk_pin_desc *)&hw->soc->pins[pin];
++ if (!desc->name)
++ return -ENOTSUPP;
+
+ for (cfg = 0; cfg < num_configs; cfg++) {
+ param = pinconf_to_config_param(configs[cfg]);
+ arg = pinconf_to_config_argument(configs[cfg]);
+-
+ switch (param) {
+ case PIN_CONFIG_BIAS_DISABLE:
+- if (hw->soc->bias_disable_set) {
++ if (hw->soc->bias_set_combo) {
++ err = hw->soc->bias_set_combo(hw, desc, 0, MTK_DISABLE);
++ if (err)
++ return err;
++ } else if (hw->soc->bias_disable_set) {
+ err = hw->soc->bias_disable_set(hw, desc);
+ if (err)
+ return err;
+@@ -234,7 +263,11 @@ static int mtk_pinconf_set(struct pinctr
+ }
+ break;
+ case PIN_CONFIG_BIAS_PULL_UP:
+- if (hw->soc->bias_set) {
++ if (hw->soc->bias_set_combo) {
++ err = hw->soc->bias_set_combo(hw, desc, 1, arg);
++ if (err)
++ return err;
++ } else if (hw->soc->bias_set) {
+ err = hw->soc->bias_set(hw, desc, 1);
+ if (err)
+ return err;
+@@ -243,7 +276,11 @@ static int mtk_pinconf_set(struct pinctr
+ }
+ break;
+ case PIN_CONFIG_BIAS_PULL_DOWN:
+- if (hw->soc->bias_set) {
++ if (hw->soc->bias_set_combo) {
++ err = hw->soc->bias_set_combo(hw, desc, 0, arg);
++ if (err)
++ return err;
++ } else if (hw->soc->bias_set) {
+ err = hw->soc->bias_set(hw, desc, 0);
+ if (err)
+ return err;
+--- a/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c
++++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c
+@@ -506,6 +506,404 @@ int mtk_pinconf_bias_get_rev1(struct mtk
+ return 0;
+ }
+
++/* Combo for the following pull register type:
++ * 1. PU + PD
++ * 2. PULLSEL + PULLEN
++ * 3. PUPD + R0 + R1
++ */
++static int mtk_pinconf_bias_set_pu_pd(struct mtk_pinctrl *hw,
++ const struct mtk_pin_desc *desc,
++ u32 pullup, u32 arg)
++{
++ int err, pu, pd;
++
++ if (arg == MTK_DISABLE) {
++ pu = 0;
++ pd = 0;
++ } else if ((arg == MTK_ENABLE) && pullup) {
++ pu = 1;
++ pd = 0;
++ } else if ((arg == MTK_ENABLE) && !pullup) {
++ pu = 0;
++ pd = 1;
++ } else {
++ err = -EINVAL;
++ goto out;
++ }
++
++ err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_PU, pu);
++ if (err)
++ goto out;
++
++ err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_PD, pd);
++
++out:
++ return err;
++}
++
++static int mtk_pinconf_bias_set_pullsel_pullen(struct mtk_pinctrl *hw,
++ const struct mtk_pin_desc *desc,
++ u32 pullup, u32 arg)
++{
++ int err, enable;
++
++ if (arg == MTK_DISABLE)
++ enable = 0;
++ else if (arg == MTK_ENABLE)
++ enable = 1;
++ else {
++ err = -EINVAL;
++ goto out;
++ }
++
++ err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_PULLEN, enable);
++ if (err)
++ goto out;
++
++ err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_PULLSEL, pullup);
++
++out:
++ return err;
++}
++
++static int mtk_pinconf_bias_set_pupd_r1_r0(struct mtk_pinctrl *hw,
++ const struct mtk_pin_desc *desc,
++ u32 pullup, u32 arg)
++{
++ int err, r0, r1;
++
++ if ((arg == MTK_DISABLE) || (arg == MTK_PUPD_SET_R1R0_00)) {
++ pullup = 0;
++ r0 = 0;
++ r1 = 0;
++ } else if (arg == MTK_PUPD_SET_R1R0_01) {
++ r0 = 1;
++ r1 = 0;
++ } else if (arg == MTK_PUPD_SET_R1R0_10) {
++ r0 = 0;
++ r1 = 1;
++ } else if (arg == MTK_PUPD_SET_R1R0_11) {
++ r0 = 1;
++ r1 = 1;
++ } else {
++ err = -EINVAL;
++ goto out;
++ }
++
++ /* MTK HW PUPD bit: 1 for pull-down, 0 for pull-up */
++ err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_PUPD, !pullup);
++ if (err)
++ goto out;
++
++ err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_R0, r0);
++ if (err)
++ goto out;
++
++ err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_R1, r1);
++
++out:
++ return err;
++}
++
++static int mtk_hw_pin_rsel_lookup(struct mtk_pinctrl *hw,
++ const struct mtk_pin_desc *desc,
++ u32 pullup, u32 arg, u32 *rsel_val)
++{
++ const struct mtk_pin_rsel *rsel;
++ int check;
++ bool found = false;
++
++ rsel = hw->soc->pin_rsel;
++
++ for (check = 0; check <= hw->soc->npin_rsel - 1; check++) {
++ if (desc->number >= rsel[check].s_pin &&
++ desc->number <= rsel[check].e_pin) {
++ if (pullup) {
++ if (rsel[check].up_rsel == arg) {
++ found = true;
++ *rsel_val = rsel[check].rsel_index;
++ break;
++ }
++ } else {
++ if (rsel[check].down_rsel == arg) {
++ found = true;
++ *rsel_val = rsel[check].rsel_index;
++ break;
++ }
++ }
++ }
++ }
++
++ if (!found) {
++ dev_err(hw->dev, "Not support rsel value %d Ohm for pin = %d (%s)\n",
++ arg, desc->number, desc->name);
++ return -ENOTSUPP;
++ }
++
++ return 0;
++}
++
++static int mtk_pinconf_bias_set_rsel(struct mtk_pinctrl *hw,
++ const struct mtk_pin_desc *desc,
++ u32 pullup, u32 arg)
++{
++ int err, rsel_val;
++
++ if (!pullup && arg == MTK_DISABLE)
++ return 0;
++
++ if (hw->rsel_si_unit) {
++ /* find pin rsel_index from pin_rsel array*/
++ err = mtk_hw_pin_rsel_lookup(hw, desc, pullup, arg, &rsel_val);
++ if (err)
++ goto out;
++ } else {
++ if (arg < MTK_PULL_SET_RSEL_000 ||
++ arg > MTK_PULL_SET_RSEL_111) {
++ err = -EINVAL;
++ goto out;
++ }
++
++ rsel_val = arg - MTK_PULL_SET_RSEL_000;
++ }
++
++ err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_RSEL, rsel_val);
++ if (err)
++ goto out;
++
++ err = mtk_pinconf_bias_set_pu_pd(hw, desc, pullup, MTK_ENABLE);
++
++out:
++ return err;
++}
++
++int mtk_pinconf_bias_set_combo(struct mtk_pinctrl *hw,
++ const struct mtk_pin_desc *desc,
++ u32 pullup, u32 arg)
++{
++ int err = -ENOTSUPP;
++ u32 try_all_type;
++
++ if (hw->soc->pull_type)
++ try_all_type = hw->soc->pull_type[desc->number];
++ else
++ try_all_type = MTK_PULL_TYPE_MASK;
++
++ if (try_all_type & MTK_PULL_RSEL_TYPE) {
++ err = mtk_pinconf_bias_set_rsel(hw, desc, pullup, arg);
++ if (!err)
++ return err;
++ }
++
++ if (try_all_type & MTK_PULL_PU_PD_TYPE) {
++ err = mtk_pinconf_bias_set_pu_pd(hw, desc, pullup, arg);
++ if (!err)
++ return err;
++ }
++
++ if (try_all_type & MTK_PULL_PULLSEL_TYPE) {
++ err = mtk_pinconf_bias_set_pullsel_pullen(hw, desc,
++ pullup, arg);
++ if (!err)
++ return err;
++ }
++
++ if (try_all_type & MTK_PULL_PUPD_R1R0_TYPE)
++ err = mtk_pinconf_bias_set_pupd_r1_r0(hw, desc, pullup, arg);
++
++ if (err)
++ dev_err(hw->dev, "Invalid pull argument\n");
++
++ return err;
++}
++EXPORT_SYMBOL_GPL(mtk_pinconf_bias_set_combo);
++
++static int mtk_rsel_get_si_unit(struct mtk_pinctrl *hw,
++ const struct mtk_pin_desc *desc,
++ u32 pullup, u32 rsel_val, u32 *si_unit)
++{
++ const struct mtk_pin_rsel *rsel;
++ int check;
++
++ rsel = hw->soc->pin_rsel;
++
++ for (check = 0; check <= hw->soc->npin_rsel - 1; check++) {
++ if (desc->number >= rsel[check].s_pin &&
++ desc->number <= rsel[check].e_pin) {
++ if (rsel_val == rsel[check].rsel_index) {
++ if (pullup)
++ *si_unit = rsel[check].up_rsel;
++ else
++ *si_unit = rsel[check].down_rsel;
++ break;
++ }
++ }
++ }
++
++ return 0;
++}
++
++static int mtk_pinconf_bias_get_rsel(struct mtk_pinctrl *hw,
++ const struct mtk_pin_desc *desc,
++ u32 *pullup, u32 *enable)
++{
++ int pu, pd, rsel, err;
++
++ err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_RSEL, &rsel);
++ if (err)
++ goto out;
++
++ err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_PU, &pu);
++ if (err)
++ goto out;
++
++ err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_PD, &pd);
++ if (err)
++ goto out;
++
++ if (pu == 0 && pd == 0) {
++ *pullup = 0;
++ *enable = MTK_DISABLE;
++ } else if (pu == 1 && pd == 0) {
++ *pullup = 1;
++ if (hw->rsel_si_unit)
++ mtk_rsel_get_si_unit(hw, desc, *pullup, rsel, enable);
++ else
++ *enable = rsel + MTK_PULL_SET_RSEL_000;
++ } else if (pu == 0 && pd == 1) {
++ *pullup = 0;
++ if (hw->rsel_si_unit)
++ mtk_rsel_get_si_unit(hw, desc, *pullup, rsel, enable);
++ else
++ *enable = rsel + MTK_PULL_SET_RSEL_000;
++ } else {
++ err = -EINVAL;
++ goto out;
++ }
++
++out:
++ return err;
++}
++
++static int mtk_pinconf_bias_get_pu_pd(struct mtk_pinctrl *hw,
++ const struct mtk_pin_desc *desc,
++ u32 *pullup, u32 *enable)
++{
++ int err, pu, pd;
++
++ err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_PU, &pu);
++ if (err)
++ goto out;
++
++ err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_PD, &pd);
++ if (err)
++ goto out;
++
++ if (pu == 0 && pd == 0) {
++ *pullup = 0;
++ *enable = MTK_DISABLE;
++ } else if (pu == 1 && pd == 0) {
++ *pullup = 1;
++ *enable = MTK_ENABLE;
++ } else if (pu == 0 && pd == 1) {
++ *pullup = 0;
++ *enable = MTK_ENABLE;
++ } else
++ err = -EINVAL;
++
++out:
++ return err;
++}
++
++static int mtk_pinconf_bias_get_pullsel_pullen(struct mtk_pinctrl *hw,
++ const struct mtk_pin_desc *desc,
++ u32 *pullup, u32 *enable)
++{
++ int err;
++
++ err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_PULLSEL, pullup);
++ if (err)
++ goto out;
++
++ err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_PULLEN, enable);
++
++out:
++ return err;
++}
++
++static int mtk_pinconf_bias_get_pupd_r1_r0(struct mtk_pinctrl *hw,
++ const struct mtk_pin_desc *desc,
++ u32 *pullup, u32 *enable)
++{
++ int err, r0, r1;
++
++ err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_PUPD, pullup);
++ if (err)
++ goto out;
++ /* MTK HW PUPD bit: 1 for pull-down, 0 for pull-up */
++ *pullup = !(*pullup);
++
++ err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_R0, &r0);
++ if (err)
++ goto out;
++
++ err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_R1, &r1);
++ if (err)
++ goto out;
++
++ if ((r1 == 0) && (r0 == 0))
++ *enable = MTK_PUPD_SET_R1R0_00;
++ else if ((r1 == 0) && (r0 == 1))
++ *enable = MTK_PUPD_SET_R1R0_01;
++ else if ((r1 == 1) && (r0 == 0))
++ *enable = MTK_PUPD_SET_R1R0_10;
++ else if ((r1 == 1) && (r0 == 1))
++ *enable = MTK_PUPD_SET_R1R0_11;
++ else
++ err = -EINVAL;
++
++out:
++ return err;
++}
++
++int mtk_pinconf_bias_get_combo(struct mtk_pinctrl *hw,
++ const struct mtk_pin_desc *desc,
++ u32 *pullup, u32 *enable)
++{
++ int err = -ENOTSUPP;
++ u32 try_all_type;
++
++ if (hw->soc->pull_type)
++ try_all_type = hw->soc->pull_type[desc->number];
++ else
++ try_all_type = MTK_PULL_TYPE_MASK;
++
++ if (try_all_type & MTK_PULL_RSEL_TYPE) {
++ err = mtk_pinconf_bias_get_rsel(hw, desc, pullup, enable);
++ if (!err)
++ return err;
++ }
++
++ if (try_all_type & MTK_PULL_PU_PD_TYPE) {
++ err = mtk_pinconf_bias_get_pu_pd(hw, desc, pullup, enable);
++ if (!err)
++ return err;
++ }
++
++ if (try_all_type & MTK_PULL_PULLSEL_TYPE) {
++ err = mtk_pinconf_bias_get_pullsel_pullen(hw, desc,
++ pullup, enable);
++ if (!err)
++ return err;
++ }
++
++ if (try_all_type & MTK_PULL_PUPD_R1R0_TYPE)
++ err = mtk_pinconf_bias_get_pupd_r1_r0(hw, desc, pullup, enable);
++
++ return err;
++}
++EXPORT_SYMBOL_GPL(mtk_pinconf_bias_get_combo);
++
+ /* Revision 0 */
+ int mtk_pinconf_drive_set(struct mtk_pinctrl *hw,
+ const struct mtk_pin_desc *desc, u32 arg)
+--- a/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.h
++++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.h
+@@ -17,6 +17,34 @@
+ #define MTK_ENABLE 1
+ #define MTK_PULLDOWN 0
+ #define MTK_PULLUP 1
++#define MTK_PULL_PU_PD_TYPE BIT(0)
++#define MTK_PULL_PULLSEL_TYPE BIT(1)
++#define MTK_PULL_PUPD_R1R0_TYPE BIT(2)
++/* MTK_PULL_RSEL_TYPE can select resistance and can be
++ * turned on/off itself. But it can't be selected pull up/down
++ */
++#define MTK_PULL_RSEL_TYPE BIT(3)
++/* MTK_PULL_PU_PD_RSEL_TYPE is a type which is controlled by
++ * MTK_PULL_PU_PD_TYPE and MTK_PULL_RSEL_TYPE.
++ */
++#define MTK_PULL_PU_PD_RSEL_TYPE (MTK_PULL_PU_PD_TYPE \
++ | MTK_PULL_RSEL_TYPE)
++#define MTK_PULL_TYPE_MASK (MTK_PULL_PU_PD_TYPE |\
++ MTK_PULL_PULLSEL_TYPE |\
++ MTK_PULL_PUPD_R1R0_TYPE |\
++ MTK_PULL_RSEL_TYPE)
++#define MTK_PUPD_SET_R1R0_00 100
++#define MTK_PUPD_SET_R1R0_01 101
++#define MTK_PUPD_SET_R1R0_10 102
++#define MTK_PUPD_SET_R1R0_11 103
++#define MTK_PULL_SET_RSEL_000 200
++#define MTK_PULL_SET_RSEL_001 201
++#define MTK_PULL_SET_RSEL_010 202
++#define MTK_PULL_SET_RSEL_011 203
++#define MTK_PULL_SET_RSEL_100 204
++#define MTK_PULL_SET_RSEL_101 205
++#define MTK_PULL_SET_RSEL_110 206
++#define MTK_PULL_SET_RSEL_111 207
+
+ #define EINT_NA U16_MAX
+ #define NO_EINT_SUPPORT EINT_NA
+@@ -66,6 +94,8 @@ enum {
+ PINCTRL_PIN_REG_DRV_EN,
+ PINCTRL_PIN_REG_DRV_E0,
+ PINCTRL_PIN_REG_DRV_E1,
++ PINCTRL_PIN_REG_DRV_ADV,
++ PINCTRL_PIN_REG_RSEL,
+ PINCTRL_PIN_REG_MAX,
+ };
+
+@@ -101,6 +131,22 @@ struct mtk_pin_field {
+ u8 next;
+ };
+
++/**
++ * struct mtk_pin_rsel - the structure that provides bias resistance selection.
++ * @s_pin: the start pin within the rsel range
++ * @e_pin: the end pin within the rsel range
++ * @rsel_index: the rsel bias resistance index
++ * @up_rsel: the pullup rsel bias resistance value
++ * @down_rsel: the pulldown rsel bias resistance value
++ */
++struct mtk_pin_rsel {
++ u16 s_pin;
++ u16 e_pin;
++ u16 rsel_index;
++ u32 up_rsel;
++ u32 down_rsel;
++};
++
+ /* struct mtk_pin_field_calc - the structure that holds the range providing
+ * the guide used to look up the relevant field
+ * @s_pin: the start pin within the range
+@@ -205,6 +251,9 @@ struct mtk_pin_soc {
+ bool ies_present;
+ const char * const *base_names;
+ unsigned int nbase_names;
++ const unsigned int *pull_type;
++ const struct mtk_pin_rsel *pin_rsel;
++ unsigned int npin_rsel;
+
+ /* Specific pinconfig operations */
+ int (*bias_disable_set)(struct mtk_pinctrl *hw,
+@@ -215,7 +264,10 @@ struct mtk_pin_soc {
+ const struct mtk_pin_desc *desc, bool pullup);
+ int (*bias_get)(struct mtk_pinctrl *hw,
+ const struct mtk_pin_desc *desc, bool pullup, int *res);
+-
++ int (*bias_set_combo)(struct mtk_pinctrl *hw,
++ const struct mtk_pin_desc *desc, u32 pullup, u32 arg);
++ int (*bias_get_combo)(struct mtk_pinctrl *hw,
++ const struct mtk_pin_desc *desc, u32 *pullup, u32 *arg);
+ int (*drive_set)(struct mtk_pinctrl *hw,
+ const struct mtk_pin_desc *desc, u32 arg);
+ int (*drive_get)(struct mtk_pinctrl *hw,
+@@ -246,6 +298,10 @@ struct mtk_pinctrl {
+ struct mtk_eint *eint;
+ struct mtk_pinctrl_group *groups;
+ const char **grp_names;
++ /* lock pin's register resource to avoid multiple threads issue*/
++ spinlock_t lock;
++ /* identify rsel setting by si unit or rsel define in dts node */
++ bool rsel_si_unit;
+ };
+
+ void mtk_rmw(struct mtk_pinctrl *pctl, u8 i, u32 reg, u32 mask, u32 set);
+@@ -282,7 +338,12 @@ int mtk_pinconf_drive_set(struct mtk_pin
+ const struct mtk_pin_desc *desc, u32 arg);
+ int mtk_pinconf_drive_get(struct mtk_pinctrl *hw,
+ const struct mtk_pin_desc *desc, int *val);
+-
++int mtk_pinconf_bias_set_combo(struct mtk_pinctrl *hw,
++ const struct mtk_pin_desc *desc,
++ u32 pullup, u32 enable);
++int mtk_pinconf_bias_get_combo(struct mtk_pinctrl *hw,
++ const struct mtk_pin_desc *desc,
++ u32 *pullup, u32 *enable);
+ int mtk_pinconf_drive_set_rev1(struct mtk_pinctrl *hw,
+ const struct mtk_pin_desc *desc, u32 arg);
+ int mtk_pinconf_drive_get_rev1(struct mtk_pinctrl *hw,
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2023-pinctrl-add-mt7988-pd-pulltype-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2023-pinctrl-add-mt7988-pd-pulltype-support.patch
new file mode 100644
index 0000000..6ef9357
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2023-pinctrl-add-mt7988-pd-pulltype-support.patch
@@ -0,0 +1,99 @@
+--- a/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c
++++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c
+@@ -541,6 +541,30 @@ out:
+ return err;
+ }
+
++static int mtk_pinconf_bias_set_pd(struct mtk_pinctrl *hw,
++ const struct mtk_pin_desc *desc,
++ u32 pullup, u32 arg)
++{
++ int err, pd;
++
++ if (arg == MTK_DISABLE)
++ pd = 0;
++ else if ((arg == MTK_ENABLE) && pullup)
++ pd = 0;
++ else if ((arg == MTK_ENABLE) && !pullup)
++ pd = 1;
++ else {
++ err = -EINVAL;
++ goto out;
++ }
++
++ err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_PD, pd);
++
++out:
++ return err;
++
++}
++
+ static int mtk_pinconf_bias_set_pullsel_pullen(struct mtk_pinctrl *hw,
+ const struct mtk_pin_desc *desc,
+ u32 pullup, u32 arg)
+@@ -695,6 +719,12 @@ int mtk_pinconf_bias_set_combo(struct mt
+ return err;
+ }
+
++ if (try_all_type & MTK_PULL_PD_TYPE) {
++ err = mtk_pinconf_bias_set_pd(hw, desc, pullup, arg);
++ if (!err)
++ return err;
++ }
++
+ if (try_all_type & MTK_PULL_PU_PD_TYPE) {
+ err = mtk_pinconf_bias_set_pu_pd(hw, desc, pullup, arg);
+ if (!err)
+@@ -815,6 +845,29 @@ out:
+ return err;
+ }
+
++static int mtk_pinconf_bias_get_pd(struct mtk_pinctrl *hw,
++ const struct mtk_pin_desc *desc,
++ u32 *pullup, u32 *enable)
++{
++ int err, pd;
++
++ err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_PD, &pd);
++ if (err)
++ goto out;
++
++ if (pd == 0) {
++ *pullup = 0;
++ *enable = MTK_DISABLE;
++ } else if (pd == 1) {
++ *pullup = 0;
++ *enable = MTK_ENABLE;
++ } else
++ err = -EINVAL;
++
++out:
++ return err;
++}
++
+ static int mtk_pinconf_bias_get_pullsel_pullen(struct mtk_pinctrl *hw,
+ const struct mtk_pin_desc *desc,
+ u32 *pullup, u32 *enable)
+@@ -883,6 +936,12 @@ int mtk_pinconf_bias_get_combo(struct mt
+ if (!err)
+ return err;
+ }
++
++ if (try_all_type & MTK_PULL_PD_TYPE) {
++ err = mtk_pinconf_bias_get_pd(hw, desc, pullup, enable);
++ if (!err)
++ return err;
++ }
+
+ if (try_all_type & MTK_PULL_PU_PD_TYPE) {
+ err = mtk_pinconf_bias_get_pu_pd(hw, desc, pullup, enable);
+--- a/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.h
++++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.h
+@@ -24,6 +24,7 @@
+ * turned on/off itself. But it can't be selected pull up/down
+ */
+ #define MTK_PULL_RSEL_TYPE BIT(3)
++#define MTK_PULL_PD_TYPE BIT(4)
+ /* MTK_PULL_PU_PD_RSEL_TYPE is a type which is controlled by
+ * MTK_PULL_PU_PD_TYPE and MTK_PULL_RSEL_TYPE.
+ */
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/patches-5.4.inc b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/patches-5.4.inc
index 3fce397..1fe0212 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/patches-5.4.inc
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/patches-5.4.inc
@@ -35,6 +35,7 @@
file://1010-pcie-mediatek-fix-clearing-interrupt-status.patch \
file://1020-spi-nor-w25q512jv.patch \
file://1021-ubnt-ledbar-driver.patch \
+ file://999-1000-backport-pinctrl-pinconf-setting-combo.patch \
file://999-1600-mdiobus-add-c45.patch \
file://999-1700-macsec-revert-async-support.patch \
file://999-1701-add-default-setting-to-dsa-unused-port.patch \
@@ -58,6 +59,7 @@
file://999-2020-pinctrl-add-mt7986-driver.patch \
file://999-2021-pinctrl-enable-mt7988-pinctrl-config.patch \
file://999-2022-pinctrl-add-mt7981-driver.patch \
+ file://999-2023-pinctrl-add-mt7988-pd-pulltype-support.patch \
file://999-2040-powerdomain-add-mt7988-support.patch \
file://999-2050-watchdog-add-mt7986-assert.patch \
file://999-2100-mt7986-trng-add-rng-support.patch \
diff --git a/recipes-wifi/hostapd/files/002-rdkb-add-ucode-support.patch b/recipes-wifi/hostapd/files/002-rdkb-add-ucode-support.patch
new file mode 100644
index 0000000..16e099a
--- /dev/null
+++ b/recipes-wifi/hostapd/files/002-rdkb-add-ucode-support.patch
@@ -0,0 +1,21 @@
+--- a/hostapd/Makefile 2023-08-14 14:07:55.808647300 +0800
++++ b/hostapd/Makefile 2023-08-14 14:09:14.222019605 +0800
+@@ -182,6 +182,7 @@
+ OBJS += ../src/utils/ucode.o
+ OBJS += ../src/ap/ucode.o
+ NEED_ULOOP:=y
++LIBS += -lblobmsg_json -lucode
+ endif
+
+ ifdef NEED_ULOOP
+
+--- a/wpa_supplicant/Makefile 2023-08-14 17:51:44.351944100 +0800
++++ b/wpa_supplicant/Makefile 2023-08-14 17:54:54.232111091 +0800
+@@ -206,6 +206,7 @@
+ OBJS += ../src/utils/ucode.o
+ OBJS += ucode.o
+ NEED_ULOOP:=y
++LIBS += -lblobmsg_json -lucode
+ endif
+
+ ifdef NEED_ULOOP
\ No newline at end of file
diff --git a/recipes-wifi/hostapd/files/common.uc b/recipes-wifi/hostapd/files/common.uc
new file mode 100644
index 0000000..9ece3b1
--- /dev/null
+++ b/recipes-wifi/hostapd/files/common.uc
@@ -0,0 +1,168 @@
+import * as nl80211 from "nl80211";
+import * as rtnl from "rtnl";
+import { readfile } from "fs";
+
+const iftypes = {
+ ap: nl80211.const.NL80211_IFTYPE_AP,
+ mesh: nl80211.const.NL80211_IFTYPE_MESH_POINT,
+ sta: nl80211.const.NL80211_IFTYPE_STATION,
+ adhoc: nl80211.const.NL80211_IFTYPE_ADHOC,
+ monitor: nl80211.const.NL80211_IFTYPE_MONITOR,
+};
+
+function wdev_remove(name)
+{
+ nl80211.request(nl80211.const.NL80211_CMD_DEL_INTERFACE, 0, { dev: name });
+}
+
+function __phy_is_fullmac(phyidx)
+{
+ let data = nl80211.request(nl80211.const.NL80211_CMD_GET_WIPHY, 0, { wiphy: phyidx });
+
+ return !data.software_iftypes.ap_vlan;
+}
+
+function phy_is_fullmac(phy)
+{
+ let phyidx = int(trim(readfile(`/sys/class/ieee80211/${phy}/index`)));
+
+ return __phy_is_fullmac(phyidx);
+}
+
+function find_reusable_wdev(phyidx)
+{
+ if (!__phy_is_fullmac(phyidx))
+ return null;
+
+ let data = nl80211.request(
+ nl80211.const.NL80211_CMD_GET_INTERFACE,
+ nl80211.const.NLM_F_DUMP,
+ { wiphy: phyidx });
+ for (let res in data)
+ if (trim(readfile(`/sys/class/net/${res.ifname}/operstate`)) == "down")
+ return res.ifname;
+ return null;
+}
+
+function wdev_create(phy, name, data)
+{
+ let phyidx = int(readfile(`/sys/class/ieee80211/${phy}/index`));
+
+ wdev_remove(name);
+
+ if (!iftypes[data.mode])
+ return `Invalid mode: ${data.mode}`;
+
+ let req = {
+ wiphy: phyidx,
+ ifname: name,
+ iftype: iftypes[data.mode],
+ };
+
+ if (data["4addr"])
+ req["4addr"] = data["4addr"];
+ if (data.macaddr)
+ req.mac = data.macaddr;
+
+ nl80211.error();
+
+ let reuse_ifname = find_reusable_wdev(phyidx);
+ if (reuse_ifname &&
+ (reuse_ifname == name ||
+ rtnl.request(rtnl.const.RTM_SETLINK, 0, { dev: reuse_ifname, ifname: name}) != false))
+ nl80211.request(
+ nl80211.const.NL80211_CMD_SET_INTERFACE, 0, {
+ wiphy: phyidx,
+ dev: name,
+ iftype: iftypes[data.mode],
+ });
+ else
+ nl80211.request(
+ nl80211.const.NL80211_CMD_NEW_INTERFACE,
+ nl80211.const.NLM_F_CREATE,
+ req);
+
+ let error = nl80211.error();
+ if (error)
+ return error;
+
+ if (data.powersave != null) {
+ nl80211.request(nl80211.const.NL80211_CMD_SET_POWER_SAVE, 0,
+ { dev: name, ps_state: data.powersave ? 1 : 0});
+ }
+
+ return null;
+}
+
+const vlist_proto = {
+ update: function(values, arg) {
+ let data = this.data;
+ let cb = this.cb;
+ let seq = { };
+ let new_data = {};
+ let old_data = {};
+
+ this.data = new_data;
+
+ if (type(values) == "object") {
+ for (let key in values) {
+ old_data[key] = data[key];
+ new_data[key] = values[key];
+ delete data[key];
+ }
+ } else {
+ for (let val in values) {
+ let cur_key = val[0];
+ let cur_obj = val[1];
+
+ old_data[cur_key] = data[cur_key];
+ new_data[cur_key] = val[1];
+ delete data[cur_key];
+ }
+ }
+
+ for (let key in data) {
+ cb(null, data[key], arg);
+ delete data[key];
+ }
+ for (let key in new_data)
+ cb(new_data[key], old_data[key], arg);
+ }
+};
+
+function is_equal(val1, val2) {
+ let t1 = type(val1);
+
+ if (t1 != type(val2))
+ return false;
+
+ if (t1 == "array") {
+ if (length(val1) != length(val2))
+ return false;
+
+ for (let i = 0; i < length(val1); i++)
+ if (!is_equal(val1[i], val2[i]))
+ return false;
+
+ return true;
+ } else if (t1 == "object") {
+ for (let key in val1)
+ if (!is_equal(val1[key], val2[key]))
+ return false;
+ for (let key in val2)
+ if (!val1[key])
+ return false;
+ return true;
+ } else {
+ return val1 == val2;
+ }
+}
+
+function vlist_new(cb) {
+ return proto({
+ cb: cb,
+ data: {}
+ }, vlist_proto);
+}
+
+export { wdev_remove, wdev_create, is_equal, vlist_new, phy_is_fullmac };
diff --git a/recipes-wifi/hostapd/files/hostapd.uc b/recipes-wifi/hostapd/files/hostapd.uc
new file mode 100644
index 0000000..b52732a
--- /dev/null
+++ b/recipes-wifi/hostapd/files/hostapd.uc
@@ -0,0 +1,402 @@
+let libubus = require("ubus");
+import { open, readfile } from "fs";
+import { wdev_create, wdev_remove, is_equal, vlist_new, phy_is_fullmac } from "common";
+
+let ubus = libubus.connect();
+
+hostapd.data.config = {};
+
+hostapd.data.file_fields = {
+ vlan_file: true,
+ wpa_psk_file: true,
+ accept_mac_file: true,
+ deny_mac_file: true,
+ eap_user_file: true,
+ ca_cert: true,
+ server_cert: true,
+ server_cert2: true,
+ private_key: true,
+ private_key2: true,
+ dh_file: true,
+ eap_sim_db: true,
+};
+
+function iface_remove(cfg)
+{
+ if (!cfg || !cfg.bss || !cfg.bss[0] || !cfg.bss[0].ifname)
+ return;
+
+ hostapd.remove_iface(cfg.bss[0].ifname);
+ for (let bss in cfg.bss)
+ wdev_remove(bss.ifname);
+}
+
+function iface_gen_config(phy, config)
+{
+ let str = `data:
+${join("\n", config.radio.data)}
+channel=${config.radio.channel}
+`;
+
+ for (let i = 0; i < length(config.bss); i++) {
+ let bss = config.bss[i];
+ let type = i > 0 ? "bss" : "interface";
+
+ str += `
+${type}=${bss.ifname}
+${join("\n", bss.data)}
+`;
+ }
+
+ return str;
+}
+
+function iface_restart(phy, config, old_config)
+{
+ iface_remove(old_config);
+ iface_remove(config);
+
+ if (!config.bss || !config.bss[0]) {
+ hostapd.printf(`No bss for phy ${phy}`);
+ return;
+ }
+
+ let bss = config.bss[0];
+ let err = wdev_create(phy, bss.ifname, { mode: "ap" });
+ if (err)
+ hostapd.printf(`Failed to create ${bss.ifname} on phy ${phy}: ${err}`);
+ let config_inline = iface_gen_config(phy, config);
+ if (hostapd.add_iface(`bss_config=${bss.ifname}:${config_inline}`) < 0) {
+ hostapd.printf(`hostapd.add_iface failed for phy ${phy} ifname=${bss.ifname}`);
+ return;
+ }
+}
+
+function array_to_obj(arr, key, start)
+{
+ let obj = {};
+
+ start ??= 0;
+ for (let i = start; i < length(arr); i++) {
+ let cur = arr[i];
+ obj[cur[key]] = cur;
+ }
+
+ return obj;
+}
+
+function find_array_idx(arr, key, val)
+{
+ for (let i = 0; i < length(arr); i++)
+ if (arr[i][key] == val)
+ return i;
+
+ return -1;
+}
+
+function bss_reload_psk(bss, config, old_config)
+{
+ if (is_equal(old_config.hash.wpa_psk_file, config.hash.wpa_psk_file))
+ return;
+
+ old_config.hash.wpa_psk_file = config.hash.wpa_psk_file;
+ if (!is_equal(old_config, config))
+ return;
+
+ let ret = bss.ctrl("RELOAD_WPA_PSK");
+ ret ??= "failed";
+
+ hostapd.printf(`Reload WPA PSK file for bss ${config.ifname}: ${ret}`);
+}
+
+function iface_reload_config(phy, config, old_config)
+{
+ if (!old_config || !is_equal(old_config.radio, config.radio))
+ return false;
+
+ if (is_equal(old_config.bss, config.bss))
+ return true;
+
+ if (!old_config.bss || !old_config.bss[0])
+ return false;
+
+ if (config.bss[0].ifname != old_config.bss[0].ifname)
+ return false;
+
+ let iface = hostapd.interfaces[config.bss[0].ifname];
+ if (!iface)
+ return false;
+
+ let config_inline = iface_gen_config(phy, config);
+
+ bss_reload_psk(iface.bss[0], config.bss[0], old_config.bss[0]);
+ if (!is_equal(config.bss[0], old_config.bss[0])) {
+ if (phy_is_fullmac(phy))
+ return false;
+
+ hostapd.printf(`Reload config for bss '${config.bss[0].ifname}' on phy '${phy}'`);
+ if (iface.bss[0].set_config(config_inline, 0) < 0) {
+ hostapd.printf(`Failed to set config`);
+ return false;
+ }
+ }
+
+ let bss_list = array_to_obj(iface.bss, "name", 1);
+ let new_cfg = array_to_obj(config.bss, "ifname", 1);
+ let old_cfg = array_to_obj(old_config.bss, "ifname", 1);
+
+ for (let name in old_cfg) {
+ let bss = bss_list[name];
+ if (!bss) {
+ hostapd.printf(`bss '${name}' not found`);
+ return false;
+ }
+
+ if (!new_cfg[name]) {
+ hostapd.printf(`Remove bss '${name}' on phy '${phy}'`);
+ bss.delete();
+ wdev_remove(name);
+ continue;
+ }
+
+ let new_cfg_data = new_cfg[name];
+ delete new_cfg[name];
+
+ if (is_equal(old_cfg[name], new_cfg_data))
+ continue;
+
+ hostapd.printf(`Reload config for bss '${name}' on phy '${phy}'`);
+ let idx = find_array_idx(config.bss, "ifname", name);
+ if (idx < 0) {
+ hostapd.printf(`bss index not found`);
+ return false;
+ }
+
+ if (bss.set_config(config_inline, idx) < 0) {
+ hostapd.printf(`Failed to set config`);
+ return false;
+ }
+ }
+
+ for (let name in new_cfg) {
+ hostapd.printf(`Add bss '${name}' on phy '${phy}'`);
+
+ let idx = find_array_idx(config.bss, "ifname", name);
+ if (idx < 0) {
+ hostapd.printf(`bss index not found`);
+ return false;
+ }
+
+ if (iface.add_bss(config_inline, idx) < 0) {
+ hostapd.printf(`Failed to add bss`);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+function iface_set_config(phy, config)
+{
+ let old_config = hostapd.data.config[phy];
+
+ hostapd.data.config[phy] = config;
+
+ if (!config)
+ return iface_remove(old_config);
+
+ let ret = iface_reload_config(phy, config, old_config);
+ if (ret) {
+ hostapd.printf(`Reloaded settings for phy ${phy}`);
+ return 0;
+ }
+
+ hostapd.printf(`Restart interface for phy ${phy}`);
+ return iface_restart(phy, config, old_config);
+}
+
+function config_add_bss(config, name)
+{
+ let bss = {
+ ifname: name,
+ data: [],
+ hash: {}
+ };
+
+ push(config.bss, bss);
+
+ return bss;
+}
+
+function iface_load_config(filename)
+{
+ let f = open(filename, "r");
+ if (!f)
+ return null;
+
+ let config = {
+ radio: {
+ data: []
+ },
+ bss: [],
+ orig_file: filename,
+ };
+
+ let bss;
+ let line;
+ while ((line = trim(f.read("line"))) != null) {
+ let val = split(line, "=", 2);
+ if (!val[0])
+ continue;
+
+ if (val[0] == "interface") {
+ bss = config_add_bss(config, val[1]);
+ break;
+ }
+
+ if (val[0] == "channel") {
+ config.radio.channel = val[1];
+ continue;
+ }
+
+ push(config.radio.data, line);
+ }
+
+ while ((line = trim(f.read("line"))) != null) {
+ let val = split(line, "=", 2);
+ if (!val[0])
+ continue;
+
+ if (val[0] == "bss") {
+ bss = config_add_bss(config, val[1]);
+ continue;
+ }
+
+ if (hostapd.data.file_fields[val[0]])
+ bss.hash[val[0]] = hostapd.sha1(readfile(val[1]));
+
+ push(bss.data, line);
+ }
+ f.close();
+
+ return config;
+}
+
+
+
+let main_obj = {
+ reload: {
+ args: {
+ phy: "",
+ },
+ call: function(req) {
+ try {
+ let phy_list = req.args.phy ? [ req.args.phy ] : keys(hostapd.data.config);
+ for (let phy_name in phy_list) {
+ let phy = hostapd.data.config[phy_name];
+ let config = iface_load_config(phy.orig_file);
+ iface_set_config(phy_name, config);
+ }
+ } catch(e) {
+ hostapd.printf(`Error reloading config: ${e}\n${e.stacktrace[0].context}`);
+ return libubus.STATUS_INVALID_ARGUMENT;
+ }
+
+ return 0;
+ }
+ },
+ config_set: {
+ args: {
+ phy: "",
+ config: "",
+ prev_config: "",
+ },
+ call: function(req) {
+ let phy = req.args.phy;
+ let file = req.args.config;
+ let prev_file = req.args.prev_config;
+
+ if (!phy)
+ return libubus.STATUS_INVALID_ARGUMENT;
+
+ try {
+ if (prev_file && !hostapd.data.config[phy]) {
+ let config = iface_load_config(prev_file);
+ if (config)
+ config.radio.data = [];
+ hostapd.data.config[phy] = config;
+ }
+
+ let config = iface_load_config(file);
+
+ hostapd.printf(`Set new config for phy ${phy}: ${file}`);
+ iface_set_config(phy, config);
+ } catch(e) {
+ hostapd.printf(`Error loading config: ${e}\n${e.stacktrace[0].context}`);
+ return libubus.STATUS_INVALID_ARGUMENT;
+ }
+
+ return {
+ pid: hostapd.getpid()
+ };
+ }
+ },
+ config_add: {
+ args: {
+ iface: "",
+ config: "",
+ },
+ call: function(req) {
+ if (!req.args.iface || !req.args.config)
+ return libubus.STATUS_INVALID_ARGUMENT;
+
+ if (hostapd.add_iface(`bss_config=${req.args.iface}:${req.args.config}`) < 0)
+ return libubus.STATUS_INVALID_ARGUMENT;
+
+ return {
+ pid: hostapd.getpid()
+ };
+ }
+ },
+ config_remove: {
+ args: {
+ iface: ""
+ },
+ call: function(req) {
+ if (!req.args.iface)
+ return libubus.STATUS_INVALID_ARGUMENT;
+
+ hostapd.remove_iface(req.args.iface);
+ return 0;
+ }
+ },
+};
+
+hostapd.data.ubus = ubus;
+hostapd.data.obj = ubus.publish("hostapd", main_obj);
+
+function bss_event(type, name, data) {
+ let ubus = hostapd.data.ubus;
+
+ data ??= {};
+ data.name = name;
+ hostapd.data.obj.notify(`bss.${type}`, data, null, null, null, -1);
+ ubus.call("service", "event", { type: `hostapd.${name}.${type}`, data: {} });
+}
+
+return {
+ shutdown: function() {
+ for (let phy in hostapd.data.config)
+ iface_set_config(phy, null);
+ hostapd.ubus.disconnect();
+ },
+ bss_add: function(name, obj) {
+ bss_event("add", name);
+ },
+ bss_reload: function(name, obj, reconf) {
+ bss_event("reload", name, { reconf: reconf != 0 });
+ },
+ bss_remove: function(name, obj) {
+ bss_event("remove", name);
+ }
+};
diff --git a/recipes-wifi/hostapd/files/patches-2.10.3/mtk-0029-hostapd-mtk-Fix-CCA-issue.patch b/recipes-wifi/hostapd/files/patches-2.10.3/180-BSS-coloring-fix-CCA-with-multiple-BSS.patch
similarity index 66%
rename from recipes-wifi/hostapd/files/patches-2.10.3/mtk-0029-hostapd-mtk-Fix-CCA-issue.patch
rename to recipes-wifi/hostapd/files/patches-2.10.3/180-BSS-coloring-fix-CCA-with-multiple-BSS.patch
index 7196118..7b0435a 100644
--- a/recipes-wifi/hostapd/files/patches-2.10.3/mtk-0029-hostapd-mtk-Fix-CCA-issue.patch
+++ b/recipes-wifi/hostapd/files/patches-2.10.3/180-BSS-coloring-fix-CCA-with-multiple-BSS.patch
@@ -1,23 +1,32 @@
-From ce585467d784d1015b5a40ec09895d0949690b04 Mon Sep 17 00:00:00 2001
-From: Michael Lee <michael-cy.lee@mediatek.com>
-Date: Wed, 3 May 2023 14:55:18 +0800
-Subject: [PATCH 29/32] hostapd: mtk: Fix CCA issue
+From: Felix Fietkau <nbd@nbd.name>
+Date: Mon, 7 Aug 2023 21:55:57 +0200
+Subject: [PATCH] BSS coloring: fix CCA with multiple BSS
-When receiving CCA-related nl80211 commands, hostapd used to work on
-struct wpa_driver_nl80211_data, whose ctx always points to
-hostpad_iface->bss[0]. However, CCA commands are sent on a per-BSS based.
-This patch makes hostapd handle CCA-related commands on a per-BSS based.
+Pass bss->ctx instead of drv->ctx in order to avoid multiple reports for
+the first bss. The first report would otherwise clear hapd->cca_color and
+subsequent reports would cause the iface bss color to be set to 0.
+In order to avoid any issues with cancellations, only overwrite the color
+based on hapd->cca_color if it was actually set.
-Signed-off-by: Michael Lee <michael-cy.lee@mediatek.com>
+Fixes: 33c4dd26cd11 ("BSS coloring: Handle the collision and CCA events coming from the kernel")
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
- src/drivers/driver_nl80211_event.c | 24 ++++++++++++------------
- 1 file changed, 12 insertions(+), 12 deletions(-)
-diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c
-index 3d0d9b7bb..ab988fad7 100644
+--- a/src/ap/drv_callbacks.c
++++ b/src/ap/drv_callbacks.c
+@@ -2260,7 +2260,8 @@ void wpa_supplicant_event(void *ctx, enu
+ case EVENT_CCA_NOTIFY:
+ wpa_printf(MSG_DEBUG, "CCA finished on on %s",
+ hapd->conf->iface);
+- hapd->iface->conf->he_op.he_bss_color = hapd->cca_color;
++ if (hapd->cca_color)
++ hapd->iface->conf->he_op.he_bss_color = hapd->cca_color;
+ hostapd_cleanup_cca_params(hapd);
+ break;
+ #endif /* CONFIG_IEEE80211AX */
--- a/src/drivers/driver_nl80211_event.c
+++ b/src/drivers/driver_nl80211_event.c
-@@ -3662,7 +3662,7 @@ static void nl80211_assoc_comeback(struct wpa_driver_nl80211_data *drv,
+@@ -3653,7 +3653,7 @@ static void nl80211_assoc_comeback(struc
#ifdef CONFIG_IEEE80211AX
@@ -26,7 +35,7 @@
struct nlattr *tb[])
{
union wpa_event_data data;
-@@ -3676,37 +3676,37 @@ static void nl80211_obss_color_collision(struct wpa_driver_nl80211_data *drv,
+@@ -3667,37 +3667,37 @@ static void nl80211_obss_color_collision
wpa_printf(MSG_DEBUG, "nl80211: BSS color collision - bitmap %08llx",
(long long unsigned int) data.bss_color_collision.bitmap);
@@ -71,7 +80,7 @@
}
#endif /* CONFIG_IEEE80211AX */
-@@ -3968,16 +3968,16 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd,
+@@ -3957,16 +3957,16 @@ static void do_process_drv_event(struct
break;
#ifdef CONFIG_IEEE80211AX
case NL80211_CMD_OBSS_COLOR_COLLISION:
@@ -92,6 +101,3 @@
break;
#endif /* CONFIG_IEEE80211AX */
default:
---
-2.39.2
-
diff --git a/recipes-wifi/hostapd/files/patches-2.10.3/200-multicall.patch b/recipes-wifi/hostapd/files/patches-2.10.3/200-multicall.patch
index f7e797a..8ebbed0 100644
--- a/recipes-wifi/hostapd/files/patches-2.10.3/200-multicall.patch
+++ b/recipes-wifi/hostapd/files/patches-2.10.3/200-multicall.patch
@@ -189,7 +189,7 @@
{
struct hostapd_data *hapd = ctx;
#ifndef CONFIG_NO_STDOUT_DEBUG
-@@ -2271,7 +2271,7 @@ void wpa_supplicant_event(void *ctx, enu
+@@ -2272,7 +2272,7 @@ void wpa_supplicant_event(void *ctx, enu
}
diff --git a/recipes-wifi/hostapd/files/patches-2.10.3/600-ubus_support.patch b/recipes-wifi/hostapd/files/patches-2.10.3/600-ubus_support.patch
index f393634..f420c18 100644
--- a/recipes-wifi/hostapd/files/patches-2.10.3/600-ubus_support.patch
+++ b/recipes-wifi/hostapd/files/patches-2.10.3/600-ubus_support.patch
@@ -1,11 +1,12 @@
--- a/hostapd/Makefile
+++ b/hostapd/Makefile
-@@ -166,6 +166,11 @@ OBJS += ../src/common/hw_features_common
+@@ -166,6 +166,12 @@ OBJS += ../src/common/hw_features_common
OBJS += ../src/eapol_auth/eapol_auth_sm.o
+ifdef CONFIG_UBUS
+CFLAGS += -DUBUS_SUPPORT
++OBJS += ../src/utils/uloop.o
+OBJS += ../src/ap/ubus.o
+LIBS += -lubox -lubus
+endif
@@ -22,15 +23,6 @@
#define OCE_STA_CFON_ENABLED(hapd) \
((hapd->conf->oce & OCE_STA_CFON) && \
-@@ -92,7 +93,7 @@ struct hapd_interfaces {
- #ifdef CONFIG_CTRL_IFACE_UDP
- unsigned char ctrl_iface_cookie[CTRL_IFACE_COOKIE_LEN];
- #endif /* CONFIG_CTRL_IFACE_UDP */
--
-+ struct ubus_object ubus;
- };
-
- enum hostapd_chan_status {
@@ -184,6 +185,7 @@ struct hostapd_data {
struct hostapd_iface *iface;
struct hostapd_config *iconf;
@@ -330,20 +322,21 @@
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
-@@ -194,6 +194,12 @@ ifdef CONFIG_EAPOL_TEST
+@@ -194,6 +194,13 @@ ifdef CONFIG_EAPOL_TEST
CFLAGS += -Werror -DEAPOL_TEST
endif
+ifdef CONFIG_UBUS
+CFLAGS += -DUBUS_SUPPORT
+OBJS += ubus.o
++OBJS += ../src/utils/uloop.o
+LIBS += -lubox -lubus
+endif
+
ifdef CONFIG_CODE_COVERAGE
CFLAGS += -O0 -fprofile-arcs -ftest-coverage
LIBS += -lgcov
-@@ -989,6 +995,9 @@ ifdef CONFIG_CTRL_IFACE_MIB
+@@ -989,6 +996,9 @@ ifdef CONFIG_CTRL_IFACE_MIB
CFLAGS += -DCONFIG_CTRL_IFACE_MIB
endif
OBJS += ../src/ap/ctrl_iface_ap.o
@@ -432,24 +425,6 @@
if (wpa_s->conf->wps_cred_processing == 1)
return 0;
---- a/hostapd/main.c
-+++ b/hostapd/main.c
-@@ -991,6 +991,7 @@ int main(int argc, char *argv[])
- }
-
- hostapd_global_ctrl_iface_init(&interfaces);
-+ hostapd_ubus_add(&interfaces);
-
- if (hostapd_global_run(&interfaces, daemonize, pid_file)) {
- wpa_printf(MSG_ERROR, "Failed to start eloop");
-@@ -1000,6 +1001,7 @@ int main(int argc, char *argv[])
- ret = 0;
-
- out:
-+ hostapd_ubus_free(&interfaces);
- hostapd_global_ctrl_iface_deinit(&interfaces);
- /* Deinitialize all interfaces */
- for (i = 0; i < interfaces.count; i++) {
--- a/wpa_supplicant/main.c
+++ b/wpa_supplicant/main.c
@@ -204,7 +204,7 @@ int main(int argc, char *argv[])
@@ -623,3 +598,151 @@
wpa_hexdump(MSG_DEBUG, "WNM: BSS Transition Candidate List Entries",
pos, end - pos);
}
+--- a/src/utils/eloop.c
++++ b/src/utils/eloop.c
+@@ -77,6 +77,9 @@ struct eloop_sock_table {
+ struct eloop_data {
+ int max_sock;
+
++ eloop_timeout_poll_handler timeout_poll_cb;
++ eloop_poll_handler poll_cb;
++
+ size_t count; /* sum of all table counts */
+ #ifdef CONFIG_ELOOP_POLL
+ size_t max_pollfd_map; /* number of pollfds_map currently allocated */
+@@ -1121,6 +1124,12 @@ void eloop_run(void)
+ os_reltime_sub(&timeout->time, &now, &tv);
+ else
+ tv.sec = tv.usec = 0;
++ }
++
++ if (eloop.timeout_poll_cb && eloop.timeout_poll_cb(&tv, !!timeout))
++ timeout = (void *)1;
++
++ if (timeout) {
+ #if defined(CONFIG_ELOOP_POLL) || defined(CONFIG_ELOOP_EPOLL)
+ timeout_ms = tv.sec * 1000 + tv.usec / 1000;
+ #endif /* defined(CONFIG_ELOOP_POLL) || defined(CONFIG_ELOOP_EPOLL) */
+@@ -1190,7 +1199,8 @@ void eloop_run(void)
+ eloop.exceptions.changed = 0;
+
+ eloop_process_pending_signals();
+-
++ if (eloop.poll_cb)
++ eloop.poll_cb();
+
+ /* check if some registered timeouts have occurred */
+ timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,
+@@ -1252,6 +1262,14 @@ out:
+ return;
+ }
+
++int eloop_register_cb(eloop_poll_handler poll_cb,
++ eloop_timeout_poll_handler timeout_cb)
++{
++ eloop.poll_cb = poll_cb;
++ eloop.timeout_poll_cb = timeout_cb;
++
++ return 0;
++}
+
+ void eloop_terminate(void)
+ {
+--- a/src/utils/eloop.h
++++ b/src/utils/eloop.h
+@@ -65,6 +65,9 @@ typedef void (*eloop_timeout_handler)(vo
+ */
+ typedef void (*eloop_signal_handler)(int sig, void *signal_ctx);
+
++typedef bool (*eloop_timeout_poll_handler)(struct os_reltime *tv, bool tv_set);
++typedef void (*eloop_poll_handler)(void);
++
+ /**
+ * eloop_init() - Initialize global event loop data
+ * Returns: 0 on success, -1 on failure
+@@ -73,6 +76,9 @@ typedef void (*eloop_signal_handler)(int
+ */
+ int eloop_init(void);
+
++int eloop_register_cb(eloop_poll_handler poll_cb,
++ eloop_timeout_poll_handler timeout_cb);
++
+ /**
+ * eloop_register_read_sock - Register handler for read events
+ * @sock: File descriptor number for the socket
+@@ -320,6 +326,8 @@ int eloop_register_signal_reconfig(eloop
+ */
+ int eloop_sock_requeue(void);
+
++void eloop_add_uloop(void);
++
+ /**
+ * eloop_run - Start the event loop
+ *
+--- /dev/null
++++ b/src/utils/uloop.c
+@@ -0,0 +1,64 @@
++#include <libubox/uloop.h>
++#include "includes.h"
++#include "common.h"
++#include "eloop.h"
++
++static void eloop_uloop_event_cb(int sock, void *eloop_ctx, void *sock_ctx)
++{
++}
++
++static void eloop_uloop_fd_cb(struct uloop_fd *fd, unsigned int events)
++{
++ unsigned int changed = events ^ fd->flags;
++
++ if (changed & ULOOP_READ) {
++ if (events & ULOOP_READ)
++ eloop_register_sock(fd->fd, EVENT_TYPE_READ, eloop_uloop_event_cb, fd, fd);
++ else
++ eloop_unregister_sock(fd->fd, EVENT_TYPE_READ);
++ }
++
++ if (changed & ULOOP_WRITE) {
++ if (events & ULOOP_WRITE)
++ eloop_register_sock(fd->fd, EVENT_TYPE_WRITE, eloop_uloop_event_cb, fd, fd);
++ else
++ eloop_unregister_sock(fd->fd, EVENT_TYPE_WRITE);
++ }
++}
++
++static bool uloop_timeout_poll_handler(struct os_reltime *tv, bool tv_set)
++{
++ struct os_reltime tv_uloop;
++ int timeout_ms = uloop_get_next_timeout();
++
++ if (timeout_ms < 0)
++ return false;
++
++ tv_uloop.sec = timeout_ms / 1000;
++ tv_uloop.usec = (timeout_ms % 1000) * 1000;
++
++ if (!tv_set || os_reltime_before(&tv_uloop, tv)) {
++ *tv = tv_uloop;
++ return true;
++ }
++
++ return false;
++}
++
++static void uloop_poll_handler(void)
++{
++ uloop_run_timeout(0);
++}
++
++void eloop_add_uloop(void)
++{
++ static bool init_done = false;
++
++ if (!init_done) {
++ uloop_init();
++ uloop_fd_set_cb = eloop_uloop_fd_cb;
++ init_done = true;
++ }
++
++ eloop_register_cb(uloop_poll_handler, uloop_timeout_poll_handler);
++}
diff --git a/recipes-wifi/hostapd/files/patches-2.10.3/601-ucode_support.patch b/recipes-wifi/hostapd/files/patches-2.10.3/601-ucode_support.patch
new file mode 100644
index 0000000..ff1a9dd
--- /dev/null
+++ b/recipes-wifi/hostapd/files/patches-2.10.3/601-ucode_support.patch
@@ -0,0 +1,234 @@
+--- a/hostapd/Makefile
++++ b/hostapd/Makefile
+@@ -168,9 +168,21 @@ OBJS += ../src/eapol_auth/eapol_auth_sm.
+
+ ifdef CONFIG_UBUS
+ CFLAGS += -DUBUS_SUPPORT
+-OBJS += ../src/utils/uloop.o
+ OBJS += ../src/ap/ubus.o
+-LIBS += -lubox -lubus
++LIBS += -lubus
++NEED_ULOOP:=y
++endif
++
++ifdef CONFIG_UCODE
++CFLAGS += -DUCODE_SUPPORT
++OBJS += ../src/utils/ucode.o
++OBJS += ../src/ap/ucode.o
++NEED_ULOOP:=y
++endif
++
++ifdef NEED_ULOOP
++OBJS += ../src/utils/uloop.o
++LIBS += -lubox
+ endif
+
+ ifdef CONFIG_CODE_COVERAGE
+--- a/hostapd/main.c
++++ b/hostapd/main.c
+@@ -991,6 +991,7 @@ int main(int argc, char *argv[])
+ }
+
+ hostapd_global_ctrl_iface_init(&interfaces);
++ hostapd_ucode_init(&interfaces);
+
+ if (hostapd_global_run(&interfaces, daemonize, pid_file)) {
+ wpa_printf(MSG_ERROR, "Failed to start eloop");
+@@ -1000,6 +1001,7 @@ int main(int argc, char *argv[])
+ ret = 0;
+
+ out:
++ hostapd_ucode_free();
+ hostapd_global_ctrl_iface_deinit(&interfaces);
+ /* Deinitialize all interfaces */
+ for (i = 0; i < interfaces.count; i++) {
+--- a/src/ap/hostapd.h
++++ b/src/ap/hostapd.h
+@@ -19,6 +19,7 @@
+ #include "ap_config.h"
+ #include "drivers/driver.h"
+ #include "ubus.h"
++#include "ucode.h"
+
+ #define OCE_STA_CFON_ENABLED(hapd) \
+ ((hapd->conf->oce & OCE_STA_CFON) && \
+@@ -51,6 +52,10 @@ struct hapd_interfaces {
+ struct hostapd_config * (*config_read_cb)(const char *config_fname);
+ int (*ctrl_iface_init)(struct hostapd_data *hapd);
+ void (*ctrl_iface_deinit)(struct hostapd_data *hapd);
++ int (*ctrl_iface_recv)(struct hostapd_data *hapd,
++ char *buf, char *reply, int reply_size,
++ struct sockaddr_storage *from,
++ socklen_t fromlen);
+ int (*for_each_interface)(struct hapd_interfaces *interfaces,
+ int (*cb)(struct hostapd_iface *iface,
+ void *ctx), void *ctx);
+@@ -186,6 +191,7 @@ struct hostapd_data {
+ struct hostapd_config *iconf;
+ struct hostapd_bss_config *conf;
+ struct hostapd_ubus_bss ubus;
++ struct hostapd_ucode_bss ucode;
+ int interface_added; /* virtual interface added for this BSS */
+ unsigned int started:1;
+ unsigned int disabled:1;
+@@ -506,6 +512,7 @@ struct hostapd_sta_info {
+ */
+ struct hostapd_iface {
+ struct hapd_interfaces *interfaces;
++ struct hostapd_ucode_iface ucode;
+ void *owner;
+ char *config_fname;
+ struct hostapd_config *conf;
+--- a/src/ap/hostapd.c
++++ b/src/ap/hostapd.c
+@@ -276,6 +276,8 @@ int hostapd_reload_config(struct hostapd
+ size_t j;
+ int i;
+
++ hostapd_ucode_reload_bss(hapd, reconf);
++
+ if (iface->config_fname == NULL) {
+ /* Only in-memory config in use - assume it has been updated */
+ hostapd_clear_old(iface);
+@@ -455,6 +457,7 @@ void hostapd_free_hapd_data(struct hosta
+ hapd->beacon_set_done = 0;
+
+ wpa_printf(MSG_DEBUG, "%s(%s)", __func__, hapd->conf->iface);
++ hostapd_ucode_free_bss(hapd);
+ hostapd_ubus_free_bss(hapd);
+ accounting_deinit(hapd);
+ hostapd_deinit_wpa(hapd);
+@@ -619,6 +622,7 @@ void hostapd_cleanup_iface_partial(struc
+ static void hostapd_cleanup_iface(struct hostapd_iface *iface)
+ {
+ wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface);
++ hostapd_ucode_free_iface(iface);
+ eloop_cancel_timeout(channel_list_update_timeout, iface, NULL);
+ eloop_cancel_timeout(hostapd_interface_setup_failure_handler, iface,
+ NULL);
+@@ -1209,6 +1213,7 @@ static int hostapd_start_beacon(struct h
+ hapd->driver->set_operstate(hapd->drv_priv, 1);
+
+ hostapd_ubus_add_bss(hapd);
++ hostapd_ucode_add_bss(hapd);
+
+ return 0;
+ }
+--- a/wpa_supplicant/Makefile
++++ b/wpa_supplicant/Makefile
+@@ -197,8 +197,20 @@ endif
+ ifdef CONFIG_UBUS
+ CFLAGS += -DUBUS_SUPPORT
+ OBJS += ubus.o
++LIBS += -lubus
++NEED_ULOOP:=y
++endif
++
++ifdef CONFIG_UCODE
++CFLAGS += -DUCODE_SUPPORT
++OBJS += ../src/utils/ucode.o
++OBJS += ucode.o
++NEED_ULOOP:=y
++endif
++
++ifdef NEED_ULOOP
+ OBJS += ../src/utils/uloop.o
+-LIBS += -lubox -lubus
++LIBS += -lubox
+ endif
+
+ ifdef CONFIG_CODE_COVERAGE
+@@ -999,6 +1011,9 @@ OBJS += ../src/ap/ctrl_iface_ap.o
+ ifdef CONFIG_UBUS
+ OBJS += ../src/ap/ubus.o
+ endif
++ifdef CONFIG_UCODE
++OBJS += ../src/ap/ucode.o
++endif
+ endif
+
+ CFLAGS += -DEAP_SERVER -DEAP_SERVER_IDENTITY
+--- a/wpa_supplicant/wpa_supplicant.c
++++ b/wpa_supplicant/wpa_supplicant.c
+@@ -7636,6 +7636,7 @@ struct wpa_supplicant * wpa_supplicant_a
+ #endif /* CONFIG_P2P */
+
+ wpas_ubus_add_bss(wpa_s);
++ wpas_ucode_add_bss(wpa_s);
+
+ return wpa_s;
+ }
+@@ -7663,6 +7664,7 @@ int wpa_supplicant_remove_iface(struct w
+ struct wpa_supplicant *parent = wpa_s->parent;
+ #endif /* CONFIG_MESH */
+
++ wpas_ucode_free_bss(wpa_s);
+ wpas_ubus_free_bss(wpa_s);
+
+ /* Remove interface from the global list of interfaces */
+@@ -7973,6 +7975,7 @@ struct wpa_global * wpa_supplicant_init(
+
+ eloop_register_timeout(WPA_SUPPLICANT_CLEANUP_INTERVAL, 0,
+ wpas_periodic, global, NULL);
++ wpas_ucode_init(global);
+
+ return global;
+ }
+@@ -8011,12 +8014,8 @@ int wpa_supplicant_run(struct wpa_global
+ eloop_register_signal_terminate(wpa_supplicant_terminate, global);
+ eloop_register_signal_reconfig(wpa_supplicant_reconfig, global);
+
+- wpas_ubus_add(global);
+-
+ eloop_run();
+
+- wpas_ubus_free(global);
+-
+ return 0;
+ }
+
+@@ -8049,6 +8048,8 @@ void wpa_supplicant_deinit(struct wpa_gl
+
+ wpas_notify_supplicant_deinitialized(global);
+
++ wpas_ucode_free();
++
+ eap_peer_unregister_methods();
+ #ifdef CONFIG_AP
+ eap_server_unregister_methods();
+--- a/wpa_supplicant/wpa_supplicant_i.h
++++ b/wpa_supplicant/wpa_supplicant_i.h
+@@ -22,6 +22,7 @@
+ #include "wmm_ac.h"
+ #include "pasn/pasn_common.h"
+ #include "ubus.h"
++#include "ucode.h"
+
+ extern const char *const wpa_supplicant_version;
+ extern const char *const wpa_supplicant_license;
+@@ -659,6 +660,7 @@ struct wpa_supplicant {
+ unsigned char perm_addr[ETH_ALEN];
+ char ifname[100];
+ struct wpas_ubus_bss ubus;
++ struct wpas_ucode_bss ucode;
+ #ifdef CONFIG_MATCH_IFACE
+ int matched;
+ #endif /* CONFIG_MATCH_IFACE */
+--- a/hostapd/ctrl_iface.c
++++ b/hostapd/ctrl_iface.c
+@@ -4921,6 +4921,7 @@ try_again:
+ return -1;
+ }
+
++ interface->ctrl_iface_recv = hostapd_ctrl_iface_receive_process;
+ wpa_msg_register_cb(hostapd_ctrl_iface_msg_cb);
+
+ return 0;
+@@ -5022,6 +5023,7 @@ fail:
+ os_free(fname);
+
+ interface->global_ctrl_sock = s;
++ interface->ctrl_iface_recv = hostapd_ctrl_iface_receive_process;
+ eloop_register_read_sock(s, hostapd_global_ctrl_iface_receive,
+ interface, NULL);
+
diff --git a/recipes-wifi/hostapd/files/patches-2.10.3/700-wifi-reload.patch b/recipes-wifi/hostapd/files/patches-2.10.3/700-wifi-reload.patch
index 0c76276..c0e7e4d 100644
--- a/recipes-wifi/hostapd/files/patches-2.10.3/700-wifi-reload.patch
+++ b/recipes-wifi/hostapd/files/patches-2.10.3/700-wifi-reload.patch
@@ -40,6 +40,15 @@
int rts_threshold;
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
+@@ -127,7 +127,7 @@ void hostapd_reconfig_encryption(struct
+ }
+
+
+-static void hostapd_reload_bss(struct hostapd_data *hapd)
++void hostapd_reload_bss(struct hostapd_data *hapd)
+ {
+ struct hostapd_ssid *ssid;
+
@@ -255,6 +255,10 @@ static int hostapd_iface_conf_changed(st
{
size_t i;
@@ -60,7 +69,7 @@
{
struct hapd_interfaces *interfaces = iface->interfaces;
struct hostapd_data *hapd = iface->bss[0];
-@@ -296,6 +300,9 @@ int hostapd_reload_config(struct hostapd
+@@ -298,6 +302,9 @@ int hostapd_reload_config(struct hostapd
char *fname;
int res;
@@ -70,7 +79,7 @@
hostapd_clear_old(iface);
wpa_printf(MSG_DEBUG,
-@@ -322,6 +329,24 @@ int hostapd_reload_config(struct hostapd
+@@ -324,6 +331,24 @@ int hostapd_reload_config(struct hostapd
wpa_printf(MSG_ERROR,
"Failed to enable interface on config reload");
return res;
@@ -95,7 +104,7 @@
}
iface->conf = newconf;
-@@ -338,6 +363,12 @@ int hostapd_reload_config(struct hostapd
+@@ -340,6 +365,12 @@ int hostapd_reload_config(struct hostapd
for (j = 0; j < iface->num_bss; j++) {
hapd = iface->bss[j];
@@ -108,7 +117,17 @@
if (!hapd->conf->config_id || !newconf->bss[j]->config_id ||
os_strcmp(hapd->conf->config_id,
newconf->bss[j]->config_id) != 0)
-@@ -2700,6 +2731,10 @@ hostapd_alloc_bss_data(struct hostapd_if
+@@ -1236,8 +1267,7 @@ static int hostapd_start_beacon(struct h
+ * initialized. Most of the modules that are initialized here will be
+ * deinitialized in hostapd_cleanup().
+ */
+-static int hostapd_setup_bss(struct hostapd_data *hapd, int first,
+- bool start_beacon)
++int hostapd_setup_bss(struct hostapd_data *hapd, int first, bool start_beacon)
+ {
+ struct hostapd_bss_config *conf = hapd->conf;
+ u8 ssid[SSID_MAX_LEN + 1];
+@@ -2705,6 +2735,10 @@ hostapd_alloc_bss_data(struct hostapd_if
hapd->iconf = conf;
hapd->conf = bss;
hapd->iface = hapd_iface;
@@ -119,9 +138,18 @@
if (conf)
hapd->driver = conf->driver;
hapd->ctrl_sock = -1;
+@@ -2723,7 +2757,7 @@ hostapd_alloc_bss_data(struct hostapd_if
+ }
+
+
+-static void hostapd_bss_deinit(struct hostapd_data *hapd)
++void hostapd_bss_deinit(struct hostapd_data *hapd)
+ {
+ if (!hapd)
+ return;
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
-@@ -47,7 +47,7 @@ struct mesh_conf;
+@@ -48,7 +48,7 @@ struct mesh_conf;
struct hostapd_iface;
struct hapd_interfaces {
@@ -130,23 +158,33 @@
struct hostapd_config * (*config_read_cb)(const char *config_fname);
int (*ctrl_iface_init)(struct hostapd_data *hapd);
void (*ctrl_iface_deinit)(struct hostapd_data *hapd);
-@@ -186,6 +186,7 @@ struct hostapd_data {
- struct hostapd_config *iconf;
+@@ -192,6 +192,7 @@ struct hostapd_data {
struct hostapd_bss_config *conf;
struct hostapd_ubus_bss ubus;
+ struct hostapd_ucode_bss ucode;
+ char *config_id;
int interface_added; /* virtual interface added for this BSS */
unsigned int started:1;
unsigned int disabled:1;
-@@ -689,7 +690,7 @@ struct hostapd_iface {
+@@ -696,7 +697,9 @@ struct hostapd_iface {
int hostapd_for_each_interface(struct hapd_interfaces *interfaces,
int (*cb)(struct hostapd_iface *iface,
void *ctx), void *ctx);
-int hostapd_reload_config(struct hostapd_iface *iface);
+int hostapd_reload_config(struct hostapd_iface *iface, int reconf);
++void hostapd_reload_bss(struct hostapd_data *hapd);
++void hostapd_bss_deinit(struct hostapd_data *hapd);
void hostapd_reconfig_encryption(struct hostapd_data *hapd);
struct hostapd_data *
hostapd_alloc_bss_data(struct hostapd_iface *hapd_iface,
+@@ -713,6 +716,7 @@ struct hostapd_iface * hostapd_init(stru
+ struct hostapd_iface *
+ hostapd_interface_init_bss(struct hapd_interfaces *interfaces, const char *phy,
+ const char *config_fname, int debug);
++int hostapd_setup_bss(struct hostapd_data *hapd, int first, bool start_beacon);
+ void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta,
+ int reassoc);
+ void hostapd_interface_deinit_free(struct hostapd_iface *iface);
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -5322,6 +5322,9 @@ static int wpa_driver_nl80211_set_ap(voi
diff --git a/recipes-wifi/hostapd/files/patches-2.10.3/701-reload_config_inline.patch b/recipes-wifi/hostapd/files/patches-2.10.3/701-reload_config_inline.patch
new file mode 100644
index 0000000..071281e
--- /dev/null
+++ b/recipes-wifi/hostapd/files/patches-2.10.3/701-reload_config_inline.patch
@@ -0,0 +1,33 @@
+--- a/hostapd/config_file.c
++++ b/hostapd/config_file.c
+@@ -4814,7 +4814,12 @@ struct hostapd_config * hostapd_config_r
+ int errors = 0;
+ size_t i;
+
+- f = fopen(fname, "r");
++ if (!strncmp(fname, "data:", 5)) {
++ f = fmemopen((void *)(fname + 5), strlen(fname + 5), "r");
++ fname = "<inline>";
++ } else {
++ f = fopen(fname, "r");
++ }
+ if (f == NULL) {
+ wpa_printf(MSG_ERROR, "Could not open configuration file '%s' "
+ "for reading.", fname);
+--- a/wpa_supplicant/config_file.c
++++ b/wpa_supplicant/config_file.c
+@@ -326,8 +326,13 @@ struct wpa_config * wpa_config_read(cons
+ while (cred_tail && cred_tail->next)
+ cred_tail = cred_tail->next;
+
++ if (!strncmp(name, "data:", 5)) {
++ f = fmemopen((void *)(name + 5), strlen(name + 5), "r");
++ name = "<inline>";
++ } else {
++ f = fopen(name, "r");
++ }
+ wpa_printf(MSG_DEBUG, "Reading configuration file '%s'", name);
+- f = fopen(name, "r");
+ if (f == NULL) {
+ wpa_printf(MSG_ERROR, "Failed to open config file '%s', "
+ "error: %s", name, strerror(errno));
diff --git a/recipes-wifi/hostapd/files/patches-2.10.3/720-iface_max_num_sta.patch b/recipes-wifi/hostapd/files/patches-2.10.3/720-iface_max_num_sta.patch
index 0bb00f9..5f40aab 100644
--- a/recipes-wifi/hostapd/files/patches-2.10.3/720-iface_max_num_sta.patch
+++ b/recipes-wifi/hostapd/files/patches-2.10.3/720-iface_max_num_sta.patch
@@ -17,7 +17,7 @@
} else if (os_strcmp(buf, "extended_key_id") == 0) {
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
-@@ -734,6 +734,7 @@ void hostapd_cleanup_cs_params(struct ho
+@@ -744,6 +744,7 @@ void hostapd_cleanup_cs_params(struct ho
void hostapd_periodic_iface(struct hostapd_iface *iface);
int hostapd_owe_trans_get_info(struct hostapd_data *hapd);
void hostapd_ocv_check_csa_sa_query(void *eloop_ctx, void *timeout_ctx);
diff --git a/recipes-wifi/hostapd/files/patches-2.10.3/750-qos_map_set_without_interworking.patch b/recipes-wifi/hostapd/files/patches-2.10.3/750-qos_map_set_without_interworking.patch
index 124f5ea..3e282b4 100644
--- a/recipes-wifi/hostapd/files/patches-2.10.3/750-qos_map_set_without_interworking.patch
+++ b/recipes-wifi/hostapd/files/patches-2.10.3/750-qos_map_set_without_interworking.patch
@@ -32,7 +32,7 @@
os_free(bss->dump_msk_file);
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
-@@ -1534,6 +1534,7 @@ static int hostapd_setup_bss(struct host
+@@ -1538,6 +1538,7 @@ int hostapd_setup_bss(struct hostapd_dat
wpa_printf(MSG_ERROR, "GAS server initialization failed");
return -1;
}
@@ -40,7 +40,7 @@
if (conf->qos_map_set_len &&
hostapd_drv_set_qos_map(hapd, conf->qos_map_set,
-@@ -1541,7 +1542,6 @@ static int hostapd_setup_bss(struct host
+@@ -1545,7 +1546,6 @@ int hostapd_setup_bss(struct hostapd_dat
wpa_printf(MSG_ERROR, "Failed to initialize QoS Map");
return -1;
}
diff --git a/recipes-wifi/hostapd/files/patches-2.10.3/761-shared_das_port.patch b/recipes-wifi/hostapd/files/patches-2.10.3/761-shared_das_port.patch
index dad7afd..d60764a 100644
--- a/recipes-wifi/hostapd/files/patches-2.10.3/761-shared_das_port.patch
+++ b/recipes-wifi/hostapd/files/patches-2.10.3/761-shared_das_port.patch
@@ -10,7 +10,7 @@
unsigned int time_window;
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
-@@ -1471,6 +1471,7 @@ static int hostapd_setup_bss(struct host
+@@ -1475,6 +1475,7 @@ int hostapd_setup_bss(struct hostapd_dat
os_memset(&das_conf, 0, sizeof(das_conf));
das_conf.port = conf->radius_das_port;
diff --git a/recipes-wifi/hostapd/files/patches-2.10.3/770-radius_server.patch b/recipes-wifi/hostapd/files/patches-2.10.3/770-radius_server.patch
new file mode 100644
index 0000000..6fca86d
--- /dev/null
+++ b/recipes-wifi/hostapd/files/patches-2.10.3/770-radius_server.patch
@@ -0,0 +1,154 @@
+--- a/hostapd/Makefile
++++ b/hostapd/Makefile
+@@ -63,6 +63,10 @@ endif
+ OBJS += main.o
+ OBJS += config_file.o
+
++ifdef CONFIG_RADIUS_SERVER
++OBJS += radius.o
++endif
++
+ OBJS += ../src/ap/hostapd.o
+ OBJS += ../src/ap/wpa_auth_glue.o
+ OBJS += ../src/ap/drv_callbacks.o
+--- a/hostapd/main.c
++++ b/hostapd/main.c
+@@ -42,6 +42,7 @@ static struct hapd_global global;
+ static int daemonize = 0;
+ static char *pid_file = NULL;
+
++extern int radius_main(int argc, char **argv);
+
+ #ifndef CONFIG_NO_HOSTAPD_LOGGER
+ static void hostapd_logger_cb(void *ctx, const u8 *addr, unsigned int module,
+@@ -755,6 +756,11 @@ int main(int argc, char *argv[])
+ if (os_program_init())
+ return -1;
+
++#ifdef RADIUS_SERVER
++ if (strstr(argv[0], "radius"))
++ return radius_main(argc, argv);
++#endif
++
+ os_memset(&interfaces, 0, sizeof(interfaces));
+ interfaces.reload_config = hostapd_reload_config;
+ interfaces.config_read_cb = hostapd_config_read;
+--- a/src/radius/radius_server.c
++++ b/src/radius/radius_server.c
+@@ -63,6 +63,12 @@ struct radius_server_counters {
+ u32 unknown_acct_types;
+ };
+
++struct radius_accept_attr {
++ u8 type;
++ u16 len;
++ void *data;
++};
++
+ /**
+ * struct radius_session - Internal RADIUS server data for a session
+ */
+@@ -90,7 +96,7 @@ struct radius_session {
+ unsigned int macacl:1;
+ unsigned int t_c_filtering:1;
+
+- struct hostapd_radius_attr *accept_attr;
++ struct radius_accept_attr *accept_attr;
+
+ u32 t_c_timestamp; /* Last read T&C timestamp from user DB */
+ };
+@@ -394,6 +400,7 @@ static void radius_server_session_free(s
+ radius_msg_free(sess->last_reply);
+ os_free(sess->username);
+ os_free(sess->nas_ip);
++ os_free(sess->accept_attr);
+ os_free(sess);
+ data->num_sess--;
+ }
+@@ -554,6 +561,36 @@ radius_server_erp_find_key(struct radius
+ }
+ #endif /* CONFIG_ERP */
+
++static struct radius_accept_attr *
++radius_server_copy_attr(const struct hostapd_radius_attr *data)
++{
++ const struct hostapd_radius_attr *attr;
++ struct radius_accept_attr *attr_new;
++ size_t data_size = 0;
++ void *data_buf;
++ int n_attr = 1;
++
++ for (attr = data; attr; attr = attr->next) {
++ n_attr++;
++ data_size += wpabuf_len(attr->val);
++ }
++
++ attr_new = os_zalloc(n_attr * sizeof(*attr) + data_size);
++ if (!attr_new)
++ return NULL;
++
++ data_buf = &attr_new[n_attr];
++ for (n_attr = 0, attr = data; attr; attr = attr->next) {
++ struct radius_accept_attr *cur = &attr_new[n_attr++];
++
++ cur->type = attr->type;
++ cur->len = wpabuf_len(attr->val);
++ cur->data = memcpy(data_buf, wpabuf_head(attr->val), cur->len);
++ data_buf += cur->len;
++ }
++
++ return attr_new;
++}
+
+ static struct radius_session *
+ radius_server_get_new_session(struct radius_server_data *data,
+@@ -607,7 +644,7 @@ radius_server_get_new_session(struct rad
+ eap_user_free(tmp);
+ return NULL;
+ }
+- sess->accept_attr = tmp->accept_attr;
++ sess->accept_attr = radius_server_copy_attr(tmp->accept_attr);
+ sess->macacl = tmp->macacl;
+ eap_user_free(tmp);
+
+@@ -1118,11 +1155,10 @@ radius_server_encapsulate_eap(struct rad
+ }
+
+ if (code == RADIUS_CODE_ACCESS_ACCEPT) {
+- struct hostapd_radius_attr *attr;
+- for (attr = sess->accept_attr; attr; attr = attr->next) {
+- if (!radius_msg_add_attr(msg, attr->type,
+- wpabuf_head(attr->val),
+- wpabuf_len(attr->val))) {
++ struct radius_accept_attr *attr;
++ for (attr = sess->accept_attr; attr->data; attr++) {
++ if (!radius_msg_add_attr(msg, attr->type, attr->data,
++ attr->len)) {
+ wpa_printf(MSG_ERROR, "Could not add RADIUS attribute");
+ radius_msg_free(msg);
+ return NULL;
+@@ -1211,11 +1247,10 @@ radius_server_macacl(struct radius_serve
+ }
+
+ if (code == RADIUS_CODE_ACCESS_ACCEPT) {
+- struct hostapd_radius_attr *attr;
+- for (attr = sess->accept_attr; attr; attr = attr->next) {
+- if (!radius_msg_add_attr(msg, attr->type,
+- wpabuf_head(attr->val),
+- wpabuf_len(attr->val))) {
++ struct radius_accept_attr *attr;
++ for (attr = sess->accept_attr; attr->data; attr++) {
++ if (!radius_msg_add_attr(msg, attr->type, attr->data,
++ attr->len)) {
+ wpa_printf(MSG_ERROR, "Could not add RADIUS attribute");
+ radius_msg_free(msg);
+ return NULL;
+@@ -2512,7 +2547,7 @@ static int radius_server_get_eap_user(vo
+ ret = data->get_eap_user(data->conf_ctx, identity, identity_len,
+ phase2, user);
+ if (ret == 0 && user) {
+- sess->accept_attr = user->accept_attr;
++ sess->accept_attr = radius_server_copy_attr(user->accept_attr);
+ sess->remediation = user->remediation;
+ sess->macacl = user->macacl;
+ sess->t_c_timestamp = user->t_c_timestamp;
diff --git a/recipes-wifi/hostapd/files/patches-2.10.3/mtk-0001-hostapd-mtk-Add-neighbor-report-and-BSS-Termination-.patch b/recipes-wifi/hostapd/files/patches-2.10.3/mtk-0001-hostapd-mtk-Add-neighbor-report-and-BSS-Termination-.patch
index 4e51a1c..4fa2dfb 100644
--- a/recipes-wifi/hostapd/files/patches-2.10.3/mtk-0001-hostapd-mtk-Add-neighbor-report-and-BSS-Termination-.patch
+++ b/recipes-wifi/hostapd/files/patches-2.10.3/mtk-0001-hostapd-mtk-Add-neighbor-report-and-BSS-Termination-.patch
@@ -1,8 +1,8 @@
-From df9a616286f2d33e5c580517238b93ee22359f95 Mon Sep 17 00:00:00 2001
+From bfca3c43597bf827e4d5faec91ac8f420d33c921 Mon Sep 17 00:00:00 2001
From: "howard.hsu" <howard-yh.hsu@mediatek.com>
Date: Wed, 19 Jan 2022 19:18:07 +0800
-Subject: [PATCH 01/32] hostapd: mtk: Add neighbor report and BSS Termination
- for MBO certification
+Subject: [PATCH] hostapd: mtk: Add neighbor report and BSS Termination for MBO
+ certification
1. Add hostapd_neighbor_count() and hostapd_neighbor_insert_buffer ()
The first function can count the number of neighbor report in neighbore report
@@ -13,12 +13,11 @@
3. Support including neignbor report elements in BTM response
4. Support configuring BSS Termination TSF by using hostapd_cli command
5. Disable interface if BSS Termination TSF is set
-6. Add set_send_disassoc_frame_timer() to send disassociate frame
-Function set_disassoc_timer() may fail if key was deleted first. This new
-function will not ask to delete key as set_disassoc_timer() did.
-7. Support including neighbor report elements in BTM request
-8. Add hostapd_neighbor_set_own_report_pref()
-9. Add hostapd_neighbor_set_pref_by_non_pref_chan()
+6. Support including neighbor report elements in BTM request
+7. Add hostapd_neighbor_set_own_report_pref()
+8. Add hostapd_neighbor_set_pref_by_non_pref_chan()
+
+Revert set_send_disassoc_frame_timer
---
hostapd/ctrl_iface.c | 5 ++
src/ap/ap_config.c | 1 +
@@ -28,11 +27,11 @@
src/ap/gas_serv.h | 2 +
src/ap/neighbor_db.c | 119 +++++++++++++++++++++++++++++++++++++++++
src/ap/neighbor_db.h | 9 ++++
- src/ap/wnm_ap.c | 72 +++++++++++++++++++++++--
- 9 files changed, 252 insertions(+), 5 deletions(-)
+ src/ap/wnm_ap.c | 42 ++++++++++++++-
+ 9 files changed, 223 insertions(+), 4 deletions(-)
diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
-index 55711ab10..fab1287cd 100644
+index 55711ab..fab1287 100644
--- a/hostapd/ctrl_iface.c
+++ b/hostapd/ctrl_iface.c
@@ -1347,6 +1347,11 @@ static int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd)
@@ -48,7 +47,7 @@
ret = hostapd_set_iface(hapd->iconf, hapd->conf, cmd, value);
if (ret)
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
-index 41c70708d..7d0de122d 100644
+index 41c7070..7d0de12 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -171,6 +171,7 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
@@ -60,7 +59,7 @@
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
-index 02fd4940c..dc6025279 100644
+index 02fd494..dc60252 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -558,6 +558,7 @@ struct hostapd_bss_config {
@@ -72,7 +71,7 @@
/* IEEE 802.11u - Interworking */
int interworking;
diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c
-index 50a4dc4d6..cf1cff447 100644
+index 50a4dc4..cf1cff4 100644
--- a/src/ap/ctrl_iface_ap.c
+++ b/src/ap/ctrl_iface_ap.c
@@ -1280,6 +1280,10 @@ int hostapd_ctrl_iface_bss_tm_req(struct hostapd_data *hapd,
@@ -115,7 +114,7 @@
if (pos) {
unsigned int mbo_reason, cell_pref, reassoc_delay;
diff --git a/src/ap/gas_serv.c b/src/ap/gas_serv.c
-index 4642e4927..cce6df41c 100644
+index 4642e49..cce6df4 100644
--- a/src/ap/gas_serv.c
+++ b/src/ap/gas_serv.c
@@ -19,6 +19,7 @@
@@ -183,7 +182,7 @@
#ifdef CONFIG_FILS
if (info_id == ANQP_FILS_REALM_INFO &&
diff --git a/src/ap/gas_serv.h b/src/ap/gas_serv.h
-index 7646a98a4..ce492b53f 100644
+index 7646a98..ce492b5 100644
--- a/src/ap/gas_serv.h
+++ b/src/ap/gas_serv.h
@@ -40,6 +40,8 @@
@@ -196,7 +195,7 @@
* First 15 Hotspot 2.0 vendor specific ANQP-elements can be included in the
* optimized bitmap.
diff --git a/src/ap/neighbor_db.c b/src/ap/neighbor_db.c
-index 5b276e8da..1c14b3201 100644
+index 5b276e8..1c14b32 100644
--- a/src/ap/neighbor_db.c
+++ b/src/ap/neighbor_db.c
@@ -89,6 +89,38 @@ int hostapd_neighbor_show(struct hostapd_data *hapd, char *buf, size_t buflen)
@@ -330,7 +329,7 @@
+}
+#endif
diff --git a/src/ap/neighbor_db.h b/src/ap/neighbor_db.h
-index 992671b62..a1ddc075b 100644
+index 992671b..a1ddc07 100644
--- a/src/ap/neighbor_db.h
+++ b/src/ap/neighbor_db.h
@@ -24,4 +24,13 @@ int hostapd_neighbor_remove(struct hostapd_data *hapd, const u8 *bssid,
@@ -348,7 +347,7 @@
+#endif
#endif /* NEIGHBOR_DB_H */
diff --git a/src/ap/wnm_ap.c b/src/ap/wnm_ap.c
-index ba1dd2ed1..32ccf14ae 100644
+index ba1dd2e..939d447 100644
--- a/src/ap/wnm_ap.c
+++ b/src/ap/wnm_ap.c
@@ -20,6 +20,7 @@
@@ -402,38 +401,10 @@
hapd->openwrt_stats.wnm.bss_transition_request_tx++;
wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Request to "
MACSTR " dialog_token=%u req_mode=0x%x disassoc_timer=%u "
-@@ -890,6 +911,50 @@ static void set_disassoc_timer(struct hostapd_data *hapd, struct sta_info *sta,
+@@ -890,6 +911,22 @@ static void set_disassoc_timer(struct hostapd_data *hapd, struct sta_info *sta,
}
-+static void set_send_disassoc_frame_timer(struct hostapd_data *hapd, struct sta_info *sta,
-+ int disassoc_timer)
-+{
-+ int timeout, beacon_int;
-+
-+ /*
-+ * Prevent STA from reconnecting using cached PMKSA to force
-+ * full authentication with the authentication server (which may
-+ * decide to reject the connection),
-+ */
-+ wpa_auth_pmksa_remove(hapd->wpa_auth, sta->addr);
-+
-+ beacon_int = hapd->iconf->beacon_int;
-+ if (beacon_int < 1)
-+ beacon_int = 100; /* best guess */
-+ /* Calculate timeout in ms based on beacon_int in TU */
-+ timeout = disassoc_timer * beacon_int * 128 / 125;
-+ wpa_printf(MSG_DEBUG, "Disassociation timer for " MACSTR
-+ " set to %d ms", MAC2STR(sta->addr), timeout);
-+
-+ u16 reason = WLAN_REASON_PREV_AUTH_NOT_VALID;
-+
-+ hostapd_drv_sta_disassoc(hapd, sta->addr, reason);
-+ if (sta)
-+ ap_sta_disassociate(hapd, sta, reason);
-+}
-+
-+
+void bss_termination_disable_iface(void *eloop_ctx, void *timeout_ctx)
+{
+ struct hostapd_data *hapd = eloop_ctx;
@@ -453,16 +424,7 @@
int wnm_send_ess_disassoc_imminent(struct hostapd_data *hapd,
struct sta_info *sta, const char *url,
int disassoc_timer)
-@@ -934,7 +999,7 @@ int wnm_send_ess_disassoc_imminent(struct hostapd_data *hapd,
- hapd->openwrt_stats.wnm.bss_transition_request_tx++;
- if (disassoc_timer) {
- /* send disassociation frame after time-out */
-- set_disassoc_timer(hapd, sta, disassoc_timer);
-+ set_send_disassoc_frame_timer(hapd, sta, disassoc_timer);
- }
-
- return 0;
-@@ -979,6 +1044,7 @@ int wnm_send_bss_tm_req(struct hostapd_data *hapd, struct sta_info *sta,
+@@ -979,6 +1016,7 @@ int wnm_send_bss_tm_req(struct hostapd_data *hapd, struct sta_info *sta,
bss_term_dur) {
os_memcpy(pos, bss_term_dur, 12);
pos += 12;
@@ -471,5 +433,5 @@
if (url) {
--
-2.39.2
+2.18.0
diff --git a/recipes-wifi/hostapd/files/patches-2.10.3/mtk-0026-hostapd-mtk-avoid-setting-beacon-after-wpa_supplican.patch b/recipes-wifi/hostapd/files/patches-2.10.3/mtk-0026-hostapd-mtk-Avoid-setting-beacon-after-wpa_supplican.patch
similarity index 89%
rename from recipes-wifi/hostapd/files/patches-2.10.3/mtk-0026-hostapd-mtk-avoid-setting-beacon-after-wpa_supplican.patch
rename to recipes-wifi/hostapd/files/patches-2.10.3/mtk-0026-hostapd-mtk-Avoid-setting-beacon-after-wpa_supplican.patch
index af79b24..dbd7163 100644
--- a/recipes-wifi/hostapd/files/patches-2.10.3/mtk-0026-hostapd-mtk-avoid-setting-beacon-after-wpa_supplican.patch
+++ b/recipes-wifi/hostapd/files/patches-2.10.3/mtk-0026-hostapd-mtk-Avoid-setting-beacon-after-wpa_supplican.patch
@@ -1,4 +1,4 @@
-From ff273381d463d82898df70cb7b43341405e3d943 Mon Sep 17 00:00:00 2001
+From 67e2363c4875dd918418dd84b43f86041db690c7 Mon Sep 17 00:00:00 2001
From: Evelyn Tsai <evelyn.tsai@mediatek.com>
Date: Fri, 12 May 2023 05:21:28 +0800
Subject: [PATCH] hostapd: mtk: Avoid setting beacon after wpa_supplicant stop
@@ -19,7 +19,7 @@
6 files changed, 22 insertions(+), 6 deletions(-)
diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
-index 9989a04..4952bef 100644
+index e575c37d1..0e352c5c7 100644
--- a/hostapd/ctrl_iface.c
+++ b/hostapd/ctrl_iface.c
@@ -194,11 +194,15 @@ static int hostapd_ctrl_iface_update(struct hostapd_data *hapd, char *txt)
@@ -39,7 +39,7 @@
iface->interfaces->config_read_cb = config_read_cb;
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
-index f26e525..1aaeaa8 100644
+index f26e5254c..1aaeaa8e4 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -2246,7 +2246,8 @@ int ieee802_11_set_beacon(struct hostapd_data *hapd)
@@ -69,7 +69,7 @@
ret = -1;
}
diff --git a/src/ap/bss_load.c b/src/ap/bss_load.c
-index 725d3cd..f2a1a10 100644
+index 725d3cd34..78fd9d8ec 100644
--- a/src/ap/bss_load.c
+++ b/src/ap/bss_load.c
@@ -49,6 +49,9 @@ static void update_channel_utilization(void *eloop_data, void *user_data)
@@ -104,7 +104,7 @@
NULL);
}
diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c
-index aab8a46..d52188b 100644
+index aab8a4665..d52188bb7 100644
--- a/src/ap/ctrl_iface_ap.c
+++ b/src/ap/ctrl_iface_ap.c
@@ -1028,8 +1028,10 @@ int hostapd_ctrl_iface_stop_ap(struct hostapd_data *hapd)
@@ -120,18 +120,18 @@
return 0;
}
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
-index abadd1a..afe0611 100644
+index 28e549b61..be75613c8 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
-@@ -508,6 +508,7 @@ void hostapd_free_hapd_data(struct hostapd_data *hapd)
+@@ -510,6 +510,7 @@ void hostapd_free_hapd_data(struct hostapd_data *hapd)
}
hapd->started = 0;
hapd->beacon_set_done = 0;
+ hapd->stopped_by_supplicant = 0;
wpa_printf(MSG_DEBUG, "%s(%s)", __func__, hapd->conf->iface);
- hostapd_ubus_free_bss(hapd);
-@@ -1316,6 +1317,7 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first,
+ hostapd_ucode_free_bss(hapd);
+@@ -1320,6 +1321,7 @@ int hostapd_setup_bss(struct hostapd_data *hapd, int first, bool start_beacon)
return -1;
}
hapd->started = 1;
@@ -139,7 +139,7 @@
if (!first || first == -1) {
u8 *addr = hapd->own_addr;
-@@ -4285,7 +4287,7 @@ void hostapd_switch_color(struct hostapd_data *hapd, u64 bitmap)
+@@ -4289,7 +4291,7 @@ void hostapd_switch_color(struct hostapd_data *hapd, u64 bitmap)
{
struct os_reltime now;
@@ -149,10 +149,10 @@
if (os_get_reltime(&now))
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
-index 072205c..4f1f988 100644
+index 5bd1537fe..435dbd027 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
-@@ -191,6 +191,7 @@ struct hostapd_data {
+@@ -197,6 +197,7 @@ struct hostapd_data {
unsigned int started:1;
unsigned int disabled:1;
unsigned int reenable_beacon:1;
@@ -161,5 +161,5 @@
u8 own_addr[ETH_ALEN];
u8 mld_addr[ETH_ALEN];
--
-2.25.1
+2.39.2
diff --git a/recipes-wifi/hostapd/files/patches-2.10.3/mtk-0033-hostapd-mtk-Fix-background-channel-overlapping-opera.patch b/recipes-wifi/hostapd/files/patches-2.10.3/mtk-0033-hostapd-mtk-Fix-background-channel-overlapping-opera.patch
new file mode 100644
index 0000000..dd121ca
--- /dev/null
+++ b/recipes-wifi/hostapd/files/patches-2.10.3/mtk-0033-hostapd-mtk-Fix-background-channel-overlapping-opera.patch
@@ -0,0 +1,64 @@
+From 76e54b095fdd8ab65a562c28fba330afcfb519ec Mon Sep 17 00:00:00 2001
+From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
+Date: Wed, 5 Jul 2023 10:44:15 +0800
+Subject: [PATCH] hostapd: mtk: Fix background channel overlapping operating
+ channel issue
+
+Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
+---
+ src/ap/dfs.c | 18 ++++++++++++++++++
+ 1 file changed, 18 insertions(+)
+
+diff --git a/src/ap/dfs.c b/src/ap/dfs.c
+index 2f5c86e..c9a9c6c 100644
+--- a/src/ap/dfs.c
++++ b/src/ap/dfs.c
+@@ -807,6 +807,20 @@ static int dfs_are_channels_overlapped(struct hostapd_iface *iface, int freq,
+ }
+
+
++static void dfs_check_background_overlapped(struct hostapd_iface *iface)
++{
++ int width = hostapd_get_oper_chwidth(iface->conf);
++
++ if (!dfs_use_radar_background(iface))
++ return;
++
++ if (dfs_are_channels_overlapped(iface, iface->radar_background.freq,
++ width, iface->radar_background.centr_freq_seg0_idx,
++ iface->radar_background.centr_freq_seg1_idx))
++ iface->radar_background.channel = -1;
++}
++
++
+ static unsigned int dfs_get_cac_time(struct hostapd_iface *iface,
+ int start_chan_idx, int n_chans)
+ {
+@@ -1127,6 +1141,8 @@ static void hostpad_dfs_update_background_chain(struct hostapd_iface *iface)
+ &oper_centr_freq_seg1_idx,
+ &channel_type);
+ if (!channel ||
++ channel->chan == iface->conf->channel ||
++ channel->chan == iface->radar_background.channel ||
+ hostapd_start_dfs_cac(iface, iface->conf->hw_mode,
+ channel->freq, channel->chan,
+ iface->conf->ieee80211n,
+@@ -1361,6 +1377,7 @@ static int hostapd_dfs_start_channel_switch_cac(struct hostapd_iface *iface)
+ hostapd_set_oper_centr_freq_seg1_idx(iface->conf,
+ oper_centr_freq_seg1_idx);
+ err = 0;
++ dfs_check_background_overlapped(iface);
+
+ hostapd_setup_interface_complete(iface, err);
+ return err;
+@@ -1488,6 +1505,7 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
+ hostapd_set_oper_centr_freq_seg1_idx(
+ iface->conf, oper_centr_freq_seg1_idx);
+
++ dfs_check_background_overlapped(iface);
+ hostapd_disable_iface(iface);
+ hostapd_enable_iface(iface);
+ return 0;
+--
+2.18.0
+
diff --git a/recipes-wifi/hostapd/files/patches-2.10.3/mtk-0038-hostapd-mtk-Fix-11vmbss-aid-using-wrong-pool.patch b/recipes-wifi/hostapd/files/patches-2.10.3/mtk-0038-hostapd-mtk-Fix-11vmbss-aid-using-wrong-pool.patch
new file mode 100644
index 0000000..7cd34cd
--- /dev/null
+++ b/recipes-wifi/hostapd/files/patches-2.10.3/mtk-0038-hostapd-mtk-Fix-11vmbss-aid-using-wrong-pool.patch
@@ -0,0 +1,30 @@
+From 1671a37b5990929bd11823158d496e7877d83d92 Mon Sep 17 00:00:00 2001
+From: "Allen.Ye" <allen.ye@mediatek.com>
+Date: Wed, 2 Aug 2023 18:33:31 +0800
+Subject: [PATCH 38/38] hostapd: mtk: Fix 11vmbss aid using wrong pool
+
+Fix 11vmbss aid using wrong pool.
+All STAs use the aid pool in transmitted bss.
+
+Signed-off-by: Allen.Ye <allen.ye@mediatek.com>
+---
+ src/ap/ieee802_11.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
+index d36798e..f20073c 100755
+--- a/src/ap/ieee802_11.c
++++ b/src/ap/ieee802_11.c
+@@ -3307,6 +3307,9 @@ int hostapd_get_aid(struct hostapd_data *hapd, struct sta_info *sta)
+ {
+ int i, j = 32, aid;
+
++ if (hapd->iconf->mbssid)
++ hapd = hostapd_mbssid_get_tx_bss(hapd);
++
+ /* get a unique AID */
+ if (sta->aid > 0) {
+ wpa_printf(MSG_DEBUG, " old AID %d", sta->aid);
+--
+2.18.0
+
diff --git a/recipes-wifi/hostapd/files/patches-2.10.3/mtk-0039-hostapd-mtk-Fix-rnr-ie-length-when-no-need-to-report.patch b/recipes-wifi/hostapd/files/patches-2.10.3/mtk-0039-hostapd-mtk-Fix-rnr-ie-length-when-no-need-to-report.patch
new file mode 100644
index 0000000..9218f9b
--- /dev/null
+++ b/recipes-wifi/hostapd/files/patches-2.10.3/mtk-0039-hostapd-mtk-Fix-rnr-ie-length-when-no-need-to-report.patch
@@ -0,0 +1,34 @@
+From ea3e20d6cc8d11750e509a701131297da81ef35d Mon Sep 17 00:00:00 2001
+From: "Allen.Ye" <allen.ye@mediatek.com>
+Date: Mon, 7 Aug 2023 15:27:27 +0800
+Subject: [PATCH 39/39] hostapd: mtk: Fix rnr ie length when no need to report
+ bss
+
+Fix rnr ie length when no need to report bss. If we don't have content in
+TBTT then don't change the length of the ie (*size_offset).
+
+Signed-off-by: Allen.Ye <allen.ye@mediatek.com>
+---
+ src/ap/ieee802_11.c | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
+index f20073c..ef520c8 100755
+--- a/src/ap/ieee802_11.c
++++ b/src/ap/ieee802_11.c
+@@ -7494,8 +7494,10 @@ static u8 * hostapd_eid_rnr_iface(struct hostapd_data *hapd,
+ }
+
+ start = i;
+- *tbtt_count_pos = RNR_TBTT_INFO_COUNT(tbtt_count - 1);
+- *size_offset = (eid - size_offset) - 1;
++ if (tbtt_count != 0) {
++ *tbtt_count_pos = RNR_TBTT_INFO_COUNT(tbtt_count - 1);
++ *size_offset = (eid - size_offset) - 1;
++ }
+ }
+
+ if (tbtt_count == 0)
+--
+2.18.0
+
diff --git a/recipes-wifi/hostapd/files/patches-2.10.3/mtk-0040-hostapd-mtk-add-back-ht-vht-cap-missing-field-before.patch b/recipes-wifi/hostapd/files/patches-2.10.3/mtk-0040-hostapd-mtk-add-back-ht-vht-cap-missing-field-before.patch
new file mode 100644
index 0000000..0a27496
--- /dev/null
+++ b/recipes-wifi/hostapd/files/patches-2.10.3/mtk-0040-hostapd-mtk-add-back-ht-vht-cap-missing-field-before.patch
@@ -0,0 +1,44 @@
+From 2ea36366ea036e3063ff553a2939c9cac17c6ac8 Mon Sep 17 00:00:00 2001
+From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
+Date: Tue, 8 Aug 2023 19:21:41 +0800
+Subject: [PATCH] hostapd: mtk: add back ht vht cap missing field before dfs
+ channel fallback
+
+hostapd_event_ch_switch would set / clear ht_capab and vht_capab, based
+on the bandwidth of switched channel.
+For example, vht bw 160 support field would be cleared if we switch to
+non bw 160 channel.
+This design works fine with NON-DFS channel switch.
+However, for those DFS channels who require CAC, channel switch command
+calls hostapd_switch_channel_fallback instead of hostapd_switch_channel.
+This is simply restarting the interface not CHANNEL SWITCHING, so
+hostapd will not receive any ch_switch event from kernel.
+Therefore, the cleared field in vht_capab will not be set back to 1,
+even if we channel switch to dfs channel bw 160.
+
+Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
+---
+ src/ap/hostapd.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
+index c2e0b13..4b7ebc5 100644
+--- a/src/ap/hostapd.c
++++ b/src/ap/hostapd.c
+@@ -4161,6 +4161,13 @@ hostapd_switch_channel_fallback(struct hostapd_iface *iface,
+ break;
+ }
+
++ if ((iface->current_mode->ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET) &&
++ freq_params->bandwidth > 20)
++ iface->conf->ht_capab |= HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET;
++ if ((iface->current_mode->vht_capab & VHT_CAP_SUPP_CHAN_WIDTH_160MHZ) &&
++ freq_params->bandwidth == 160)
++ iface->conf->vht_capab |= VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
++
+ iface->freq = freq_params->freq;
+ iface->conf->channel = freq_params->channel;
+ iface->conf->secondary_channel = freq_params->sec_channel_offset;
+--
+2.18.0
+
diff --git a/recipes-wifi/hostapd/files/patches-2.10.3/patches.inc b/recipes-wifi/hostapd/files/patches-2.10.3/patches.inc
index 78dae59..89585bc 100644
--- a/recipes-wifi/hostapd/files/patches-2.10.3/patches.inc
+++ b/recipes-wifi/hostapd/files/patches-2.10.3/patches.inc
@@ -17,6 +17,7 @@
file://150-add-NULL-checks-encountered-during-tests-hwsim.patch \
file://160-dpp_pkex-EC-point-mul-w-value-prime.patch \
file://170-hostapd-update-cfs0-and-cfs1-for-160MHz.patch \
+ file://180-BSS-coloring-fix-CCA-with-multiple-BSS.patch \
file://200-multicall.patch \
file://300-noscan.patch \
file://301-mesh-noscan.patch \
@@ -46,8 +47,10 @@
file://590-rrm-wnm-statistics.patch \
file://599-wpa_supplicant-fix-warnings.patch \
file://600-ubus_support.patch \
+ file://601-ucode_support.patch \
file://610-hostapd_cli_ujail_permission.patch \
file://700-wifi-reload.patch \
+ file://701-reload_config_inline.patch \
file://710-vlan_no_bridge.patch \
file://711-wds_bridge_force.patch \
file://720-iface_max_num_sta.patch \
@@ -57,6 +60,7 @@
file://751-qos_map_ignore_when_unsupported.patch \
file://760-dynamic_own_ip.patch \
file://761-shared_das_port.patch \
+ file://770-radius_server.patch \
file://990-ctrl-make-WNM_AP-functions-dependant-on-CONFIG_AP.patch \
file://mtk-0001-hostapd-mtk-Add-neighbor-report-and-BSS-Termination-.patch \
file://mtk-0002-hostapd-mtk-print-sae-groups-by-hostapd-ctrl.patch \
@@ -83,17 +87,20 @@
file://mtk-0023-hostapd-mtk-Add-vendor-for-CAPI-certification-comman.patch \
file://mtk-0024-hostapd-mtk-Air-Monitor-support-in-hostapd-by-vendor.patch \
file://mtk-0025-hostapd-mtk-Fix-scan-result-updating-issue.patch \
- file://mtk-0026-hostapd-mtk-avoid-setting-beacon-after-wpa_supplican.patch \
+ file://mtk-0026-hostapd-mtk-Avoid-setting-beacon-after-wpa_supplican.patch \
file://mtk-0027-hostapd-mtk-Fix-setting-wrong-seg0-index-for-5G-cent.patch \
file://mtk-0028-hostapd-mtk-Add-muru-user-number-debug-command.patch \
- file://mtk-0029-hostapd-mtk-Fix-CCA-issue.patch \
file://mtk-0030-hostapd-mtk-Fix-unexpected-AP-beacon-state-transitio.patch \
file://mtk-0031-hostapd-mtk-add-connac3-PHY-MURU-manual-mode-config-.patch \
file://mtk-0032-hostapd-mtk-Add-HE-capabilities-check.patch \
+ file://mtk-0033-hostapd-mtk-Fix-background-channel-overlapping-opera.patch \
file://mtk-0034-hostapd-mtk-Fix-hostapd_dfs_start_cac-log.patch \
file://mtk-0035-hostapd-mtk-Check-the-bridge-after-ioctl-SIOCBRADDIF.patch \
file://mtk-0036-hostapd-mtk-Update-parameter_set_count-in-MU-EDCA-IE.patch \
file://mtk-0037-hostapd-mtk-Add-extension-IE-list-for-non-inherit-IE.patch \
+ file://mtk-0038-hostapd-mtk-Fix-11vmbss-aid-using-wrong-pool.patch \
+ file://mtk-0039-hostapd-mtk-Fix-rnr-ie-length-when-no-need-to-report.patch \
+ file://mtk-0040-hostapd-mtk-add-back-ht-vht-cap-missing-field-before.patch \
file://mtk-1000-hostapd-mtk-update-eht-operation-element.patch \
file://mtk-1001-hostapd-mtk-Add-support-for-gtk-rekeying-in-hostapd-.patch \
"
diff --git a/recipes-wifi/hostapd/files/patches/mtk-0006-hostapd-mtk-Add-hostapd-MU-SET-GET-control.patch b/recipes-wifi/hostapd/files/patches/mtk-0006-hostapd-mtk-Add-hostapd-MU-SET-GET-control.patch
index f51b42f..b3f4138 100644
--- a/recipes-wifi/hostapd/files/patches/mtk-0006-hostapd-mtk-Add-hostapd-MU-SET-GET-control.patch
+++ b/recipes-wifi/hostapd/files/patches/mtk-0006-hostapd-mtk-Add-hostapd-MU-SET-GET-control.patch
@@ -1,7 +1,7 @@
-From e063e89785d74506976e34a0a3cbb14836d6b8e3 Mon Sep 17 00:00:00 2001
+From 53a7b7af61b75ea0e3f9d12d3d6302cf40941a8a Mon Sep 17 00:00:00 2001
From: TomLiu <tomml.liu@mediatek.com>
Date: Tue, 9 Aug 2022 10:23:44 -0700
-Subject: [PATCH 06/35] hostapd: mtk: Add hostapd MU SET/GET control
+Subject: [PATCH 06/37] hostapd: mtk: Add hostapd MU SET/GET control
---
hostapd/config_file.c | 9 +++
@@ -156,14 +156,14 @@
{ "dpp_qr_code", hostapd_cli_cmd_dpp_qr_code, NULL,
"report a scanned DPP URI from a QR Code" },
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
-index 344585a..d4fc191 100644
+index 344585a..1b0e990 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -280,6 +280,7 @@ struct hostapd_config * hostapd_config_defaults(void)
conf->he_6ghz_max_ampdu_len_exp = 7;
conf->he_6ghz_rx_ant_pat = 1;
conf->he_6ghz_tx_ant_pat = 1;
-+ conf->mu_onoff = 13;
++ conf->mu_onoff = 0xf;
#endif /* CONFIG_IEEE80211AX */
/* The third octet of the country string uses an ASCII space character
@@ -446,5 +446,5 @@
}
--
-2.18.0
+2.39.0
diff --git a/recipes-wifi/hostapd/files/patches/mtk-0037-hostapd-mtk-Fix-11vmbss-aid-using-wrong-pool.patch b/recipes-wifi/hostapd/files/patches/mtk-0037-hostapd-mtk-Fix-11vmbss-aid-using-wrong-pool.patch
new file mode 100644
index 0000000..aff2234
--- /dev/null
+++ b/recipes-wifi/hostapd/files/patches/mtk-0037-hostapd-mtk-Fix-11vmbss-aid-using-wrong-pool.patch
@@ -0,0 +1,30 @@
+From 845f192fe55b4774425752ecba8cb8f5c4e24c69 Mon Sep 17 00:00:00 2001
+From: "Allen.Ye" <allen.ye@mediatek.com>
+Date: Wed, 2 Aug 2023 18:33:31 +0800
+Subject: [PATCH 37/38] hostapd: mtk: Fix 11vmbss aid using wrong pool
+
+Fix 11vmbss aid using wrong pool.
+All STAs use the aid pool in transmitted bss.
+
+Signed-off-by: Allen.Ye <allen.ye@mediatek.com>
+---
+ src/ap/ieee802_11.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
+index f866b8a..b73b821 100644
+--- a/src/ap/ieee802_11.c
++++ b/src/ap/ieee802_11.c
+@@ -4002,6 +4002,9 @@ int hostapd_get_aid(struct hostapd_data *hapd, struct sta_info *sta)
+ {
+ int i, j = 32, aid;
+
++ if (hapd->iconf->mbssid)
++ hapd = hostapd_mbssid_get_tx_bss(hapd);
++
+ /* get a unique AID */
+ if (sta->aid > 0) {
+ wpa_printf(MSG_DEBUG, " old AID %d", sta->aid);
+--
+2.18.0
+
diff --git a/recipes-wifi/hostapd/files/patches/mtk-0037-hostapd-mtk-add-back-ht-vht-cap-missing-field-before.patch b/recipes-wifi/hostapd/files/patches/mtk-0037-hostapd-mtk-add-back-ht-vht-cap-missing-field-before.patch
new file mode 100644
index 0000000..ec82302
--- /dev/null
+++ b/recipes-wifi/hostapd/files/patches/mtk-0037-hostapd-mtk-add-back-ht-vht-cap-missing-field-before.patch
@@ -0,0 +1,44 @@
+From 87ed81b81030cb5567c04227d0fe65c6a15148f3 Mon Sep 17 00:00:00 2001
+From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
+Date: Tue, 8 Aug 2023 19:21:41 +0800
+Subject: [PATCH] hostapd: mtk: add back ht vht cap missing field before dfs
+ channel fallback
+
+hostapd_event_ch_switch would set / clear ht_capab and vht_capab, based
+on the bandwidth of switched channel.
+For example, vht bw 160 support field would be cleared if we switch to
+non bw 160 channel.
+This design works fine with NON-DFS channel switch.
+However, for those DFS channels who require CAC, channel switch command
+calls hostapd_switch_channel_fallback instead of hostapd_switch_channel.
+This is simply restarting the interface not CHANNEL SWITCHING, so
+hostapd will not receive any ch_switch event from kernel.
+Therefore, the cleared field in vht_capab will not be set back to 1,
+even if we channel switch to dfs channel bw 160.
+
+Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
+---
+ src/ap/hostapd.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
+index 707e7d5..5d17cf8 100644
+--- a/src/ap/hostapd.c
++++ b/src/ap/hostapd.c
+@@ -3888,6 +3888,13 @@ hostapd_switch_channel_fallback(struct hostapd_iface *iface,
+ break;
+ }
+
++ if ((iface->current_mode->ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET) &&
++ freq_params->bandwidth > 20)
++ iface->conf->ht_capab |= HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET;
++ if ((iface->current_mode->vht_capab & VHT_CAP_SUPP_CHAN_WIDTH_160MHZ) &&
++ freq_params->bandwidth == 160)
++ iface->conf->vht_capab |= VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
++
+ iface->freq = freq_params->freq;
+ iface->conf->channel = freq_params->channel;
+ iface->conf->secondary_channel = freq_params->sec_channel_offset;
+--
+2.18.0
+
diff --git a/recipes-wifi/hostapd/files/patches/mtk-0038-hostapd-mtk-Fix-rnr-ie-length-when-no-need-to-report.patch b/recipes-wifi/hostapd/files/patches/mtk-0038-hostapd-mtk-Fix-rnr-ie-length-when-no-need-to-report.patch
new file mode 100644
index 0000000..d6fa8b6
--- /dev/null
+++ b/recipes-wifi/hostapd/files/patches/mtk-0038-hostapd-mtk-Fix-rnr-ie-length-when-no-need-to-report.patch
@@ -0,0 +1,34 @@
+From 70c8f9355c4df3c083965ce652d33e01f8fe7e7c Mon Sep 17 00:00:00 2001
+From: "Allen.Ye" <allen.ye@mediatek.com>
+Date: Mon, 7 Aug 2023 15:27:27 +0800
+Subject: [PATCH 38/38] hostapd: mtk: Fix rnr ie length when no need to report
+ bss
+
+Fix rnr ie length when no need to report bss. If we don't have content in
+TBTT then don't change the length of the ie (*size_offset).
+
+Signed-off-by: Allen.Ye <allen.ye@mediatek.com>
+---
+ src/ap/ieee802_11.c | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
+index b73b821..ff39fad 100644
+--- a/src/ap/ieee802_11.c
++++ b/src/ap/ieee802_11.c
+@@ -7530,8 +7530,10 @@ static u8 * hostapd_eid_rnr_iface(struct hostapd_data *hapd,
+ }
+
+ start = i;
+- *tbtt_count_pos = RNR_TBTT_INFO_COUNT(tbtt_count - 1);
+- *size_offset = (eid - size_offset) - 1;
++ if (tbtt_count != 0) {
++ *tbtt_count_pos = RNR_TBTT_INFO_COUNT(tbtt_count - 1);
++ *size_offset = (eid - size_offset) - 1;
++ }
+ }
+
+ if (tbtt_count == 0)
+--
+2.18.0
+
diff --git a/recipes-wifi/hostapd/files/patches/patches.inc b/recipes-wifi/hostapd/files/patches/patches.inc
index 3e8cc14..f783c48 100644
--- a/recipes-wifi/hostapd/files/patches/patches.inc
+++ b/recipes-wifi/hostapd/files/patches/patches.inc
@@ -99,4 +99,7 @@
file://mtk-0035-hostapd-mtk-add-extension-IE-list-for-non-inherit-IE.patch \
file://mtk-0036-hostapd-mtk-Fix-background-channel-overlapping-opera.patch \
file://mtk-0036-hostapd-mtk-Fix-wpa_supplicant-configuration-parsing.patch \
+ file://mtk-0037-hostapd-mtk-Fix-11vmbss-aid-using-wrong-pool.patch \
+ file://mtk-0037-hostapd-mtk-add-back-ht-vht-cap-missing-field-before.patch \
+ file://mtk-0038-hostapd-mtk-Fix-rnr-ie-length-when-no-need-to-report.patch \
"
diff --git a/recipes-wifi/hostapd/files/src-2.10.3/hostapd/radius.c b/recipes-wifi/hostapd/files/src-2.10.3/hostapd/radius.c
new file mode 100644
index 0000000..362a22c
--- /dev/null
+++ b/recipes-wifi/hostapd/files/src-2.10.3/hostapd/radius.c
@@ -0,0 +1,715 @@
+#include "utils/includes.h"
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "crypto/crypto.h"
+#include "crypto/tls.h"
+
+#include "ap/ap_config.h"
+#include "eap_server/eap.h"
+#include "radius/radius.h"
+#include "radius/radius_server.h"
+#include "eap_register.h"
+
+#include <libubox/blobmsg_json.h>
+#include <libubox/blobmsg.h>
+#include <libubox/avl.h>
+#include <libubox/avl-cmp.h>
+#include <libubox/kvlist.h>
+
+#include <sys/stat.h>
+#include <fnmatch.h>
+
+#define VENDOR_ID_WISPR 14122
+#define VENDOR_ATTR_SIZE 6
+
+struct radius_parse_attr_data {
+ unsigned int vendor;
+ u8 type;
+ int size;
+ char format;
+ const char *data;
+};
+
+struct radius_parse_attr_state {
+ struct hostapd_radius_attr *prev;
+ struct hostapd_radius_attr *attr;
+ struct wpabuf *buf;
+ void *attrdata;
+};
+
+struct radius_user_state {
+ struct avl_node node;
+ struct eap_user data;
+};
+
+struct radius_user_data {
+ struct kvlist users;
+ struct avl_tree user_state;
+ struct blob_attr *wildcard;
+};
+
+struct radius_state {
+ struct radius_server_data *radius;
+ struct eap_config eap;
+
+ struct radius_user_data phase1, phase2;
+ const char *user_file;
+ time_t user_file_ts;
+
+ int n_attrs;
+ struct hostapd_radius_attr *attrs;
+};
+
+struct radius_config {
+ struct tls_connection_params tls;
+ struct radius_server_conf radius;
+};
+
+enum {
+ USER_ATTR_PASSWORD,
+ USER_ATTR_HASH,
+ USER_ATTR_SALT,
+ USER_ATTR_METHODS,
+ USER_ATTR_RADIUS,
+ USER_ATTR_VLAN,
+ USER_ATTR_MAX_RATE_UP,
+ USER_ATTR_MAX_RATE_DOWN,
+ __USER_ATTR_MAX
+};
+
+static void radius_tls_event(void *ctx, enum tls_event ev,
+ union tls_event_data *data)
+{
+ switch (ev) {
+ case TLS_CERT_CHAIN_SUCCESS:
+ wpa_printf(MSG_DEBUG, "radius: remote certificate verification success");
+ break;
+ case TLS_CERT_CHAIN_FAILURE:
+ wpa_printf(MSG_INFO, "radius: certificate chain failure: reason=%d depth=%d subject='%s' err='%s'",
+ data->cert_fail.reason,
+ data->cert_fail.depth,
+ data->cert_fail.subject,
+ data->cert_fail.reason_txt);
+ break;
+ case TLS_PEER_CERTIFICATE:
+ wpa_printf(MSG_DEBUG, "radius: peer certificate: depth=%d serial_num=%s subject=%s",
+ data->peer_cert.depth,
+ data->peer_cert.serial_num ? data->peer_cert.serial_num : "N/A",
+ data->peer_cert.subject);
+ break;
+ case TLS_ALERT:
+ if (data->alert.is_local)
+ wpa_printf(MSG_DEBUG, "radius: local TLS alert: %s",
+ data->alert.description);
+ else
+ wpa_printf(MSG_DEBUG, "radius: remote TLS alert: %s",
+ data->alert.description);
+ break;
+ case TLS_UNSAFE_RENEGOTIATION_DISABLED:
+ /* Not applicable to TLS server */
+ break;
+ }
+}
+
+static void radius_userdata_init(struct radius_user_data *u)
+{
+ kvlist_init(&u->users, kvlist_blob_len);
+ avl_init(&u->user_state, avl_strcmp, false, NULL);
+}
+
+static void radius_userdata_free(struct radius_user_data *u)
+{
+ struct radius_user_state *s, *tmp;
+
+ kvlist_free(&u->users);
+ free(u->wildcard);
+ u->wildcard = NULL;
+ avl_remove_all_elements(&u->user_state, s, node, tmp)
+ free(s);
+}
+
+static void
+radius_userdata_load(struct radius_user_data *u, struct blob_attr *data)
+{
+ enum {
+ USERSTATE_USERS,
+ USERSTATE_WILDCARD,
+ __USERSTATE_MAX,
+ };
+ static const struct blobmsg_policy policy[__USERSTATE_MAX] = {
+ [USERSTATE_USERS] = { "users", BLOBMSG_TYPE_TABLE },
+ [USERSTATE_WILDCARD] = { "wildcard", BLOBMSG_TYPE_ARRAY },
+ };
+ struct blob_attr *tb[__USERSTATE_MAX], *cur;
+ int rem;
+
+ if (!data)
+ return;
+
+ blobmsg_parse(policy, __USERSTATE_MAX, tb, blobmsg_data(data), blobmsg_len(data));
+
+ blobmsg_for_each_attr(cur, tb[USERSTATE_USERS], rem)
+ kvlist_set(&u->users, blobmsg_name(cur), cur);
+
+ if (tb[USERSTATE_WILDCARD])
+ u->wildcard = blob_memdup(tb[USERSTATE_WILDCARD]);
+}
+
+static void
+load_userfile(struct radius_state *s)
+{
+ enum {
+ USERDATA_PHASE1,
+ USERDATA_PHASE2,
+ __USERDATA_MAX
+ };
+ static const struct blobmsg_policy policy[__USERDATA_MAX] = {
+ [USERDATA_PHASE1] = { "phase1", BLOBMSG_TYPE_TABLE },
+ [USERDATA_PHASE2] = { "phase2", BLOBMSG_TYPE_TABLE },
+ };
+ struct blob_attr *tb[__USERDATA_MAX], *cur;
+ static struct blob_buf b;
+ struct stat st;
+ int rem;
+
+ if (stat(s->user_file, &st))
+ return;
+
+ if (s->user_file_ts == st.st_mtime)
+ return;
+
+ s->user_file_ts = st.st_mtime;
+ radius_userdata_free(&s->phase1);
+ radius_userdata_free(&s->phase2);
+
+ blob_buf_init(&b, 0);
+ blobmsg_add_json_from_file(&b, s->user_file);
+ blobmsg_parse(policy, __USERDATA_MAX, tb, blob_data(b.head), blob_len(b.head));
+ radius_userdata_load(&s->phase1, tb[USERDATA_PHASE1]);
+ radius_userdata_load(&s->phase2, tb[USERDATA_PHASE2]);
+
+ blob_buf_free(&b);
+}
+
+static struct blob_attr *
+radius_user_get(struct radius_user_data *s, const char *name)
+{
+ struct blob_attr *cur;
+ int rem;
+
+ cur = kvlist_get(&s->users, name);
+ if (cur)
+ return cur;
+
+ blobmsg_for_each_attr(cur, s->wildcard, rem) {
+ static const struct blobmsg_policy policy = {
+ "name", BLOBMSG_TYPE_STRING
+ };
+ struct blob_attr *pattern;
+
+ if (blobmsg_type(cur) != BLOBMSG_TYPE_TABLE)
+ continue;
+
+ blobmsg_parse(&policy, 1, &pattern, blobmsg_data(cur), blobmsg_len(cur));
+ if (!name)
+ continue;
+
+ if (!fnmatch(blobmsg_get_string(pattern), name, 0))
+ return cur;
+ }
+
+ return NULL;
+}
+
+static struct radius_parse_attr_data *
+radius_parse_attr(struct blob_attr *attr)
+{
+ static const struct blobmsg_policy policy[4] = {
+ { .type = BLOBMSG_TYPE_INT32 },
+ { .type = BLOBMSG_TYPE_INT32 },
+ { .type = BLOBMSG_TYPE_STRING },
+ { .type = BLOBMSG_TYPE_STRING },
+ };
+ static struct radius_parse_attr_data data;
+ struct blob_attr *tb[4];
+ const char *format;
+
+ blobmsg_parse_array(policy, ARRAY_SIZE(policy), tb, blobmsg_data(attr), blobmsg_len(attr));
+
+ if (!tb[0] || !tb[1] || !tb[2] || !tb[3])
+ return NULL;
+
+ format = blobmsg_get_string(tb[2]);
+ if (strlen(format) != 1)
+ return NULL;
+
+ data.vendor = blobmsg_get_u32(tb[0]);
+ data.type = blobmsg_get_u32(tb[1]);
+ data.format = format[0];
+ data.data = blobmsg_get_string(tb[3]);
+ data.size = strlen(data.data);
+
+ switch (data.format) {
+ case 's':
+ break;
+ case 'x':
+ if (data.size & 1)
+ return NULL;
+ data.size /= 2;
+ break;
+ case 'd':
+ data.size = 4;
+ break;
+ default:
+ return NULL;
+ }
+
+ return &data;
+}
+
+static void
+radius_count_attrs(struct blob_attr **tb, int *n_attr, size_t *attr_size)
+{
+ struct blob_attr *data = tb[USER_ATTR_RADIUS];
+ struct blob_attr *cur;
+ int rem;
+
+ blobmsg_for_each_attr(cur, data, rem) {
+ struct radius_parse_attr_data *data;
+ size_t prev = *attr_size;
+
+ data = radius_parse_attr(cur);
+ if (!data)
+ continue;
+
+ *attr_size += data->size;
+ if (data->vendor)
+ *attr_size += VENDOR_ATTR_SIZE;
+
+ (*n_attr)++;
+ }
+
+ *n_attr += !!tb[USER_ATTR_VLAN] * 3 +
+ !!tb[USER_ATTR_MAX_RATE_UP] +
+ !!tb[USER_ATTR_MAX_RATE_DOWN];
+ *attr_size += !!tb[USER_ATTR_VLAN] * (4 + 4 + 5) +
+ !!tb[USER_ATTR_MAX_RATE_UP] * (4 + VENDOR_ATTR_SIZE) +
+ !!tb[USER_ATTR_MAX_RATE_DOWN] * (4 + VENDOR_ATTR_SIZE);
+}
+
+static void *
+radius_add_attr(struct radius_parse_attr_state *state,
+ u32 vendor, u8 type, u8 len)
+{
+ struct hostapd_radius_attr *attr;
+ struct wpabuf *buf;
+ void *val;
+
+ val = state->attrdata;
+
+ buf = state->buf++;
+ buf->buf = val;
+
+ attr = state->attr++;
+ attr->val = buf;
+ attr->type = type;
+
+ if (state->prev)
+ state->prev->next = attr;
+ state->prev = attr;
+
+ if (vendor) {
+ u8 *vendor_hdr = val + 4;
+
+ WPA_PUT_BE32(val, vendor);
+ vendor_hdr[0] = type;
+ vendor_hdr[1] = len + 2;
+
+ len += VENDOR_ATTR_SIZE;
+ val += VENDOR_ATTR_SIZE;
+ attr->type = RADIUS_ATTR_VENDOR_SPECIFIC;
+ }
+
+ buf->size = buf->used = len;
+ state->attrdata += len;
+
+ return val;
+}
+
+static void
+radius_parse_attrs(struct blob_attr **tb, struct radius_parse_attr_state *state)
+{
+ struct blob_attr *data = tb[USER_ATTR_RADIUS];
+ struct hostapd_radius_attr *prev = NULL;
+ struct blob_attr *cur;
+ int len, rem;
+ void *val;
+
+ if ((cur = tb[USER_ATTR_VLAN]) != NULL && blobmsg_get_u32(cur) < 4096) {
+ char buf[5];
+
+ val = radius_add_attr(state, 0, RADIUS_ATTR_TUNNEL_TYPE, 4);
+ WPA_PUT_BE32(val, RADIUS_TUNNEL_TYPE_VLAN);
+
+ val = radius_add_attr(state, 0, RADIUS_ATTR_TUNNEL_MEDIUM_TYPE, 4);
+ WPA_PUT_BE32(val, RADIUS_TUNNEL_MEDIUM_TYPE_802);
+
+ len = snprintf(buf, sizeof(buf), "%d", blobmsg_get_u32(cur));
+ val = radius_add_attr(state, 0, RADIUS_ATTR_TUNNEL_PRIVATE_GROUP_ID, len);
+ memcpy(val, buf, len);
+ }
+
+ if ((cur = tb[USER_ATTR_MAX_RATE_UP]) != NULL) {
+ val = radius_add_attr(state, VENDOR_ID_WISPR, 7, 4);
+ WPA_PUT_BE32(val, blobmsg_get_u32(cur));
+ }
+
+ if ((cur = tb[USER_ATTR_MAX_RATE_DOWN]) != NULL) {
+ val = radius_add_attr(state, VENDOR_ID_WISPR, 8, 4);
+ WPA_PUT_BE32(val, blobmsg_get_u32(cur));
+ }
+
+ blobmsg_for_each_attr(cur, data, rem) {
+ struct radius_parse_attr_data *data;
+ void *val;
+ int size;
+
+ data = radius_parse_attr(cur);
+ if (!data)
+ continue;
+
+ val = radius_add_attr(state, data->vendor, data->type, data->size);
+ switch (data->format) {
+ case 's':
+ memcpy(val, data->data, data->size);
+ break;
+ case 'x':
+ hexstr2bin(data->data, val, data->size);
+ break;
+ case 'd':
+ WPA_PUT_BE32(val, atoi(data->data));
+ break;
+ }
+ }
+}
+
+static void
+radius_user_parse_methods(struct eap_user *eap, struct blob_attr *data)
+{
+ struct blob_attr *cur;
+ int rem, n = 0;
+
+ if (!data)
+ return;
+
+ blobmsg_for_each_attr(cur, data, rem) {
+ const char *method;
+
+ if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING)
+ continue;
+
+ if (n == EAP_MAX_METHODS)
+ break;
+
+ method = blobmsg_get_string(cur);
+ eap->methods[n].method = eap_server_get_type(method, &eap->methods[n].vendor);
+ if (eap->methods[n].vendor == EAP_VENDOR_IETF &&
+ eap->methods[n].method == EAP_TYPE_NONE) {
+ if (!strcmp(method, "TTLS-PAP")) {
+ eap->ttls_auth |= EAP_TTLS_AUTH_PAP;
+ continue;
+ }
+ if (!strcmp(method, "TTLS-CHAP")) {
+ eap->ttls_auth |= EAP_TTLS_AUTH_CHAP;
+ continue;
+ }
+ if (!strcmp(method, "TTLS-MSCHAP")) {
+ eap->ttls_auth |= EAP_TTLS_AUTH_MSCHAP;
+ continue;
+ }
+ if (!strcmp(method, "TTLS-MSCHAPV2")) {
+ eap->ttls_auth |= EAP_TTLS_AUTH_MSCHAPV2;
+ continue;
+ }
+ }
+ n++;
+ }
+}
+
+static struct eap_user *
+radius_user_get_state(struct radius_user_data *u, struct blob_attr *data,
+ const char *id)
+{
+ static const struct blobmsg_policy policy[__USER_ATTR_MAX] = {
+ [USER_ATTR_PASSWORD] = { "password", BLOBMSG_TYPE_STRING },
+ [USER_ATTR_HASH] = { "hash", BLOBMSG_TYPE_STRING },
+ [USER_ATTR_SALT] = { "salt", BLOBMSG_TYPE_STRING },
+ [USER_ATTR_METHODS] = { "methods", BLOBMSG_TYPE_ARRAY },
+ [USER_ATTR_RADIUS] = { "radius", BLOBMSG_TYPE_ARRAY },
+ [USER_ATTR_VLAN] = { "vlan-id", BLOBMSG_TYPE_INT32 },
+ [USER_ATTR_MAX_RATE_UP] = { "max-rate-up", BLOBMSG_TYPE_INT32 },
+ [USER_ATTR_MAX_RATE_DOWN] = { "max-rate-down", BLOBMSG_TYPE_INT32 },
+ };
+ struct blob_attr *tb[__USER_ATTR_MAX], *cur;
+ char *password_buf, *salt_buf, *name_buf;
+ struct radius_parse_attr_state astate = {};
+ struct hostapd_radius_attr *attr;
+ struct radius_user_state *state;
+ int pw_len = 0, salt_len = 0;
+ struct eap_user *eap;
+ struct wpabuf *val;
+ size_t attrsize = 0;
+ void *attrdata;
+ int n_attr = 0;
+
+ state = avl_find_element(&u->user_state, id, state, node);
+ if (state)
+ return &state->data;
+
+ blobmsg_parse(policy, __USER_ATTR_MAX, tb, blobmsg_data(data), blobmsg_len(data));
+
+ if ((cur = tb[USER_ATTR_SALT]) != NULL)
+ salt_len = strlen(blobmsg_get_string(cur)) / 2;
+ if ((cur = tb[USER_ATTR_HASH]) != NULL)
+ pw_len = strlen(blobmsg_get_string(cur)) / 2;
+ else if ((cur = tb[USER_ATTR_PASSWORD]) != NULL)
+ pw_len = blobmsg_len(cur) - 1;
+ radius_count_attrs(tb, &n_attr, &attrsize);
+
+ state = calloc_a(sizeof(*state), &name_buf, strlen(id) + 1,
+ &password_buf, pw_len,
+ &salt_buf, salt_len,
+ &astate.attr, n_attr * sizeof(*astate.attr),
+ &astate.buf, n_attr * sizeof(*astate.buf),
+ &astate.attrdata, attrsize);
+ eap = &state->data;
+ eap->salt = salt_len ? salt_buf : NULL;
+ eap->salt_len = salt_len;
+ eap->password = pw_len ? password_buf : NULL;
+ eap->password_len = pw_len;
+ eap->force_version = -1;
+
+ if ((cur = tb[USER_ATTR_SALT]) != NULL)
+ hexstr2bin(blobmsg_get_string(cur), salt_buf, salt_len);
+ if ((cur = tb[USER_ATTR_PASSWORD]) != NULL)
+ memcpy(password_buf, blobmsg_get_string(cur), pw_len);
+ else if ((cur = tb[USER_ATTR_HASH]) != NULL) {
+ hexstr2bin(blobmsg_get_string(cur), password_buf, pw_len);
+ eap->password_hash = 1;
+ }
+ radius_user_parse_methods(eap, tb[USER_ATTR_METHODS]);
+
+ if (n_attr > 0) {
+ cur = tb[USER_ATTR_RADIUS];
+ eap->accept_attr = astate.attr;
+ radius_parse_attrs(tb, &astate);
+ }
+
+ state->node.key = strcpy(name_buf, id);
+ avl_insert(&u->user_state, &state->node);
+
+ return &state->data;
+
+free:
+ free(state);
+ return NULL;
+}
+
+static int radius_get_eap_user(void *ctx, const u8 *identity,
+ size_t identity_len, int phase2,
+ struct eap_user *user)
+{
+ struct radius_state *s = ctx;
+ struct radius_user_data *u = phase2 ? &s->phase2 : &s->phase1;
+ struct blob_attr *entry;
+ struct eap_user *data;
+ char *id;
+
+ if (identity_len > 512)
+ return -1;
+
+ load_userfile(s);
+
+ id = alloca(identity_len + 1);
+ memcpy(id, identity, identity_len);
+ id[identity_len] = 0;
+
+ entry = radius_user_get(u, id);
+ if (!entry)
+ return -1;
+
+ if (!user)
+ return 0;
+
+ data = radius_user_get_state(u, entry, id);
+ if (!data)
+ return -1;
+
+ *user = *data;
+ if (user->password_len > 0)
+ user->password = os_memdup(user->password, user->password_len);
+ if (user->salt_len > 0)
+ user->salt = os_memdup(user->salt, user->salt_len);
+ user->phase2 = phase2;
+
+ return 0;
+}
+
+static int radius_setup(struct radius_state *s, struct radius_config *c)
+{
+ struct eap_config *eap = &s->eap;
+ struct tls_config conf = {
+ .event_cb = radius_tls_event,
+ .tls_flags = TLS_CONN_DISABLE_TLSv1_3,
+ .cb_ctx = s,
+ };
+
+ eap->eap_server = 1;
+ eap->max_auth_rounds = 100;
+ eap->max_auth_rounds_short = 50;
+ eap->ssl_ctx = tls_init(&conf);
+ if (!eap->ssl_ctx) {
+ wpa_printf(MSG_INFO, "TLS init failed\n");
+ return 1;
+ }
+
+ if (tls_global_set_params(eap->ssl_ctx, &c->tls)) {
+ wpa_printf(MSG_INFO, "failed to set TLS parameters\n");
+ return 1;
+ }
+
+ c->radius.eap_cfg = eap;
+ c->radius.conf_ctx = s;
+ c->radius.get_eap_user = radius_get_eap_user;
+ s->radius = radius_server_init(&c->radius);
+ if (!s->radius) {
+ wpa_printf(MSG_INFO, "failed to initialize radius server\n");
+ return 1;
+ }
+
+ return 0;
+}
+
+static int radius_init(struct radius_state *s)
+{
+ memset(s, 0, sizeof(*s));
+ radius_userdata_init(&s->phase1);
+ radius_userdata_init(&s->phase2);
+}
+
+static void radius_deinit(struct radius_state *s)
+{
+ if (s->radius)
+ radius_server_deinit(s->radius);
+
+ if (s->eap.ssl_ctx)
+ tls_deinit(s->eap.ssl_ctx);
+
+ radius_userdata_free(&s->phase1);
+ radius_userdata_free(&s->phase2);
+}
+
+static int usage(const char *progname)
+{
+ fprintf(stderr, "Usage: %s <options>\n",
+ progname);
+}
+
+int radius_main(int argc, char **argv)
+{
+ static struct radius_state state = {};
+ static struct radius_config config = {};
+ const char *progname = argv[0];
+ int ret = 0;
+ int ch;
+
+ wpa_debug_setup_stdout();
+ wpa_debug_level = 0;
+
+ if (eloop_init()) {
+ wpa_printf(MSG_ERROR, "Failed to initialize event loop");
+ return 1;
+ }
+
+ eap_server_register_methods();
+ radius_init(&state);
+
+ while ((ch = getopt(argc, argv, "6C:c:d:i:k:K:p:P:s:u:")) != -1) {
+ switch (ch) {
+ case '6':
+ config.radius.ipv6 = 1;
+ break;
+ case 'C':
+ config.tls.ca_cert = optarg;
+ break;
+ case 'c':
+ if (config.tls.client_cert2)
+ return usage(progname);
+
+ if (config.tls.client_cert)
+ config.tls.client_cert2 = optarg;
+ else
+ config.tls.client_cert = optarg;
+ break;
+ case 'd':
+ config.tls.dh_file = optarg;
+ break;
+ case 'i':
+ state.eap.server_id = optarg;
+ state.eap.server_id_len = strlen(optarg);
+ break;
+ case 'k':
+ if (config.tls.private_key2)
+ return usage(progname);
+
+ if (config.tls.private_key)
+ config.tls.private_key2 = optarg;
+ else
+ config.tls.private_key = optarg;
+ break;
+ case 'K':
+ if (config.tls.private_key_passwd2)
+ return usage(progname);
+
+ if (config.tls.private_key_passwd)
+ config.tls.private_key_passwd2 = optarg;
+ else
+ config.tls.private_key_passwd = optarg;
+ break;
+ case 'p':
+ config.radius.auth_port = atoi(optarg);
+ break;
+ case 'P':
+ config.radius.acct_port = atoi(optarg);
+ break;
+ case 's':
+ config.radius.client_file = optarg;
+ break;
+ case 'u':
+ state.user_file = optarg;
+ break;
+ default:
+ return usage(progname);
+ }
+ }
+
+ if (!config.tls.client_cert || !config.tls.private_key ||
+ !config.radius.client_file || !state.eap.server_id ||
+ !state.user_file) {
+ wpa_printf(MSG_INFO, "missing options\n");
+ goto out;
+ }
+
+ ret = radius_setup(&state, &config);
+ if (ret)
+ goto out;
+
+ load_userfile(&state);
+ eloop_run();
+
+out:
+ radius_deinit(&state);
+ os_program_deinit();
+
+ return ret;
+}
diff --git a/recipes-wifi/hostapd/files/src-2.10.3/src/ap/ubus.c b/recipes-wifi/hostapd/files/src-2.10.3/src/ap/ubus.c
new file mode 100644
index 0000000..a609eb1
--- /dev/null
+++ b/recipes-wifi/hostapd/files/src-2.10.3/src/ap/ubus.c
@@ -0,0 +1,2002 @@
+/*
+ * hostapd / ubus support
+ * Copyright (c) 2013, Felix Fietkau <nbd@nbd.name>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "utils/wpabuf.h"
+#include "common/ieee802_11_defs.h"
+#include "common/hw_features_common.h"
+#include "hostapd.h"
+#include "neighbor_db.h"
+#include "wps_hostapd.h"
+#include "sta_info.h"
+#include "ubus.h"
+#include "ap_drv_ops.h"
+#include "beacon.h"
+#include "rrm.h"
+#include "wnm_ap.h"
+#include "taxonomy.h"
+#include "airtime_policy.h"
+#include "hw_features.h"
+
+static struct ubus_context *ctx;
+static struct blob_buf b;
+static int ctx_ref;
+
+static inline struct hostapd_data *get_hapd_from_object(struct ubus_object *obj)
+{
+ return container_of(obj, struct hostapd_data, ubus.obj);
+}
+
+struct ubus_banned_client {
+ struct avl_node avl;
+ u8 addr[ETH_ALEN];
+};
+
+static void ubus_reconnect_timeout(void *eloop_data, void *user_ctx)
+{
+ if (ubus_reconnect(ctx, NULL)) {
+ eloop_register_timeout(1, 0, ubus_reconnect_timeout, ctx, NULL);
+ return;
+ }
+
+ ubus_add_uloop(ctx);
+}
+
+static void hostapd_ubus_connection_lost(struct ubus_context *ctx)
+{
+ uloop_fd_delete(&ctx->sock);
+ eloop_register_timeout(1, 0, ubus_reconnect_timeout, ctx, NULL);
+}
+
+static bool hostapd_ubus_init(void)
+{
+ if (ctx)
+ return true;
+
+ eloop_add_uloop();
+ ctx = ubus_connect(NULL);
+ if (!ctx)
+ return false;
+
+ ctx->connection_lost = hostapd_ubus_connection_lost;
+ ubus_add_uloop(ctx);
+
+ return true;
+}
+
+static void hostapd_ubus_ref_inc(void)
+{
+ ctx_ref++;
+}
+
+static void hostapd_ubus_ref_dec(void)
+{
+ ctx_ref--;
+ if (!ctx)
+ return;
+
+ if (ctx_ref)
+ return;
+
+ uloop_fd_delete(&ctx->sock);
+ ubus_free(ctx);
+ ctx = NULL;
+}
+
+void hostapd_ubus_add_iface(struct hostapd_iface *iface)
+{
+ if (!hostapd_ubus_init())
+ return;
+}
+
+void hostapd_ubus_free_iface(struct hostapd_iface *iface)
+{
+ if (!ctx)
+ return;
+}
+
+static void hostapd_notify_ubus(struct ubus_object *obj, char *bssname, char *event)
+{
+ char *event_type;
+
+ if (!ctx || !obj)
+ return;
+
+ if (asprintf(&event_type, "bss.%s", event) < 0)
+ return;
+
+ blob_buf_init(&b, 0);
+ blobmsg_add_string(&b, "name", bssname);
+ ubus_notify(ctx, obj, event_type, b.head, -1);
+ free(event_type);
+}
+
+static void
+hostapd_bss_del_ban(void *eloop_data, void *user_ctx)
+{
+ struct ubus_banned_client *ban = eloop_data;
+ struct hostapd_data *hapd = user_ctx;
+
+ avl_delete(&hapd->ubus.banned, &ban->avl);
+ free(ban);
+}
+
+static void
+hostapd_bss_ban_client(struct hostapd_data *hapd, u8 *addr, int time)
+{
+ struct ubus_banned_client *ban;
+
+ if (time < 0)
+ time = 0;
+
+ ban = avl_find_element(&hapd->ubus.banned, addr, ban, avl);
+ if (!ban) {
+ if (!time)
+ return;
+
+ ban = os_zalloc(sizeof(*ban));
+ memcpy(ban->addr, addr, sizeof(ban->addr));
+ ban->avl.key = ban->addr;
+ avl_insert(&hapd->ubus.banned, &ban->avl);
+ } else {
+ eloop_cancel_timeout(hostapd_bss_del_ban, ban, hapd);
+ if (!time) {
+ hostapd_bss_del_ban(ban, hapd);
+ return;
+ }
+ }
+
+ eloop_register_timeout(0, time * 1000, hostapd_bss_del_ban, ban, hapd);
+}
+
+static int
+hostapd_bss_reload(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *req, const char *method,
+ struct blob_attr *msg)
+{
+ struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
+
+ return hostapd_reload_config(hapd->iface, 1);
+}
+
+
+static void
+hostapd_parse_vht_map_blobmsg(uint16_t map)
+{
+ char label[4];
+ int16_t val;
+ int i;
+
+ for (i = 0; i < 8; i++) {
+ snprintf(label, 4, "%dss", i + 1);
+
+ val = (map & (BIT(1) | BIT(0))) + 7;
+ blobmsg_add_u16(&b, label, val == 10 ? -1 : val);
+ map = map >> 2;
+ }
+}
+
+static void
+hostapd_parse_vht_capab_blobmsg(struct ieee80211_vht_capabilities *vhtc)
+{
+ void *supported_mcs;
+ void *map;
+ int i;
+
+ static const struct {
+ const char *name;
+ uint32_t flag;
+ } vht_capas[] = {
+ { "su_beamformee", VHT_CAP_SU_BEAMFORMEE_CAPABLE },
+ { "mu_beamformee", VHT_CAP_MU_BEAMFORMEE_CAPABLE },
+ };
+
+ for (i = 0; i < ARRAY_SIZE(vht_capas); i++)
+ blobmsg_add_u8(&b, vht_capas[i].name,
+ !!(vhtc->vht_capabilities_info & vht_capas[i].flag));
+
+ supported_mcs = blobmsg_open_table(&b, "mcs_map");
+
+ /* RX map */
+ map = blobmsg_open_table(&b, "rx");
+ hostapd_parse_vht_map_blobmsg(le_to_host16(vhtc->vht_supported_mcs_set.rx_map));
+ blobmsg_close_table(&b, map);
+
+ /* TX map */
+ map = blobmsg_open_table(&b, "tx");
+ hostapd_parse_vht_map_blobmsg(le_to_host16(vhtc->vht_supported_mcs_set.tx_map));
+ blobmsg_close_table(&b, map);
+
+ blobmsg_close_table(&b, supported_mcs);
+}
+
+static void
+hostapd_parse_capab_blobmsg(struct sta_info *sta)
+{
+ void *r, *v;
+
+ v = blobmsg_open_table(&b, "capabilities");
+
+ if (sta->vht_capabilities) {
+ r = blobmsg_open_table(&b, "vht");
+ hostapd_parse_vht_capab_blobmsg(sta->vht_capabilities);
+ blobmsg_close_table(&b, r);
+ }
+
+ /* ToDo: Add HT / HE capability parsing */
+
+ blobmsg_close_table(&b, v);
+}
+
+static int
+hostapd_bss_get_clients(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *req, const char *method,
+ struct blob_attr *msg)
+{
+ struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
+ struct hostap_sta_driver_data sta_driver_data;
+ struct sta_info *sta;
+ void *list, *c;
+ char mac_buf[20];
+ static const struct {
+ const char *name;
+ uint32_t flag;
+ } sta_flags[] = {
+ { "auth", WLAN_STA_AUTH },
+ { "assoc", WLAN_STA_ASSOC },
+ { "authorized", WLAN_STA_AUTHORIZED },
+ { "preauth", WLAN_STA_PREAUTH },
+ { "wds", WLAN_STA_WDS },
+ { "wmm", WLAN_STA_WMM },
+ { "ht", WLAN_STA_HT },
+ { "vht", WLAN_STA_VHT },
+ { "he", WLAN_STA_HE },
+ { "wps", WLAN_STA_WPS },
+ { "mfp", WLAN_STA_MFP },
+ };
+
+ blob_buf_init(&b, 0);
+ blobmsg_add_u32(&b, "freq", hapd->iface->freq);
+ list = blobmsg_open_table(&b, "clients");
+ for (sta = hapd->sta_list; sta; sta = sta->next) {
+ void *r;
+ int i;
+
+ sprintf(mac_buf, MACSTR, MAC2STR(sta->addr));
+ c = blobmsg_open_table(&b, mac_buf);
+ for (i = 0; i < ARRAY_SIZE(sta_flags); i++)
+ blobmsg_add_u8(&b, sta_flags[i].name,
+ !!(sta->flags & sta_flags[i].flag));
+
+#ifdef CONFIG_MBO
+ blobmsg_add_u8(&b, "mbo", !!(sta->cell_capa));
+#endif
+
+ r = blobmsg_open_array(&b, "rrm");
+ for (i = 0; i < ARRAY_SIZE(sta->rrm_enabled_capa); i++)
+ blobmsg_add_u32(&b, "", sta->rrm_enabled_capa[i]);
+ blobmsg_close_array(&b, r);
+
+ r = blobmsg_open_array(&b, "extended_capabilities");
+ /* Check if client advertises extended capabilities */
+ if (sta->ext_capability && sta->ext_capability[0] > 0) {
+ for (i = 0; i < sta->ext_capability[0]; i++) {
+ blobmsg_add_u32(&b, "", sta->ext_capability[1 + i]);
+ }
+ }
+ blobmsg_close_array(&b, r);
+
+ blobmsg_add_u32(&b, "aid", sta->aid);
+#ifdef CONFIG_TAXONOMY
+ r = blobmsg_alloc_string_buffer(&b, "signature", 1024);
+ if (retrieve_sta_taxonomy(hapd, sta, r, 1024) > 0)
+ blobmsg_add_string_buffer(&b);
+#endif
+
+ /* Driver information */
+ if (hostapd_drv_read_sta_data(hapd, &sta_driver_data, sta->addr) >= 0) {
+ r = blobmsg_open_table(&b, "bytes");
+ blobmsg_add_u64(&b, "rx", sta_driver_data.rx_bytes);
+ blobmsg_add_u64(&b, "tx", sta_driver_data.tx_bytes);
+ blobmsg_close_table(&b, r);
+ r = blobmsg_open_table(&b, "airtime");
+ blobmsg_add_u64(&b, "rx", sta_driver_data.rx_airtime);
+ blobmsg_add_u64(&b, "tx", sta_driver_data.tx_airtime);
+ blobmsg_close_table(&b, r);
+ r = blobmsg_open_table(&b, "packets");
+ blobmsg_add_u32(&b, "rx", sta_driver_data.rx_packets);
+ blobmsg_add_u32(&b, "tx", sta_driver_data.tx_packets);
+ blobmsg_close_table(&b, r);
+ r = blobmsg_open_table(&b, "rate");
+ /* Rate in kbits */
+ blobmsg_add_u32(&b, "rx", sta_driver_data.current_rx_rate * 100);
+ blobmsg_add_u32(&b, "tx", sta_driver_data.current_tx_rate * 100);
+ blobmsg_close_table(&b, r);
+ blobmsg_add_u32(&b, "signal", sta_driver_data.signal);
+ }
+
+ hostapd_parse_capab_blobmsg(sta);
+
+ blobmsg_close_table(&b, c);
+ }
+ blobmsg_close_array(&b, list);
+ ubus_send_reply(ctx, req, b.head);
+
+ return 0;
+}
+
+static int
+hostapd_bss_get_features(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *req, const char *method,
+ struct blob_attr *msg)
+{
+ struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
+
+ blob_buf_init(&b, 0);
+ blobmsg_add_u8(&b, "ht_supported", ht_supported(hapd->iface->hw_features));
+ blobmsg_add_u8(&b, "vht_supported", vht_supported(hapd->iface->hw_features));
+ ubus_send_reply(ctx, req, b.head);
+
+ return 0;
+}
+
+static int
+hostapd_bss_get_status(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *req, const char *method,
+ struct blob_attr *msg)
+{
+ struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
+ void *airtime_table, *dfs_table, *rrm_table, *wnm_table;
+ struct os_reltime now;
+ char ssid[SSID_MAX_LEN + 1];
+ char phy_name[17];
+ size_t ssid_len = SSID_MAX_LEN;
+ u8 channel = 0, op_class = 0;
+
+ if (hapd->conf->ssid.ssid_len < SSID_MAX_LEN)
+ ssid_len = hapd->conf->ssid.ssid_len;
+
+ ieee80211_freq_to_channel_ext(hapd->iface->freq,
+ hapd->iconf->secondary_channel,
+ hostapd_get_oper_chwidth(hapd->iconf),
+ &op_class, &channel);
+
+ blob_buf_init(&b, 0);
+ blobmsg_add_string(&b, "status", hostapd_state_text(hapd->iface->state));
+ blobmsg_printf(&b, "bssid", MACSTR, MAC2STR(hapd->conf->bssid));
+
+ memset(ssid, 0, SSID_MAX_LEN + 1);
+ memcpy(ssid, hapd->conf->ssid.ssid, ssid_len);
+ blobmsg_add_string(&b, "ssid", ssid);
+
+ blobmsg_add_u32(&b, "freq", hapd->iface->freq);
+ blobmsg_add_u32(&b, "channel", channel);
+ blobmsg_add_u32(&b, "op_class", op_class);
+ blobmsg_add_u32(&b, "beacon_interval", hapd->iconf->beacon_int);
+#ifdef CONFIG_IEEE80211AX
+ blobmsg_add_u32(&b, "bss_color", hapd->iface->conf->he_op.he_bss_color_disabled ? -1 :
+ hapd->iface->conf->he_op.he_bss_color);
+#else
+ blobmsg_add_u32(&b, "bss_color", -1);
+#endif
+
+ snprintf(phy_name, 17, "%s", hapd->iface->phy);
+ blobmsg_add_string(&b, "phy", phy_name);
+
+ /* RRM */
+ rrm_table = blobmsg_open_table(&b, "rrm");
+ blobmsg_add_u64(&b, "neighbor_report_tx", hapd->openwrt_stats.rrm.neighbor_report_tx);
+ blobmsg_close_table(&b, rrm_table);
+
+ /* WNM */
+ wnm_table = blobmsg_open_table(&b, "wnm");
+ blobmsg_add_u64(&b, "bss_transition_query_rx", hapd->openwrt_stats.wnm.bss_transition_query_rx);
+ blobmsg_add_u64(&b, "bss_transition_request_tx", hapd->openwrt_stats.wnm.bss_transition_request_tx);
+ blobmsg_add_u64(&b, "bss_transition_response_rx", hapd->openwrt_stats.wnm.bss_transition_response_rx);
+ blobmsg_close_table(&b, wnm_table);
+
+ /* Airtime */
+ airtime_table = blobmsg_open_table(&b, "airtime");
+ blobmsg_add_u64(&b, "time", hapd->iface->last_channel_time);
+ blobmsg_add_u64(&b, "time_busy", hapd->iface->last_channel_time_busy);
+ blobmsg_add_u16(&b, "utilization", hapd->iface->channel_utilization);
+ blobmsg_close_table(&b, airtime_table);
+
+ /* DFS */
+ dfs_table = blobmsg_open_table(&b, "dfs");
+ blobmsg_add_u32(&b, "cac_seconds", hapd->iface->dfs_cac_ms / 1000);
+ blobmsg_add_u8(&b, "cac_active", !!(hapd->iface->cac_started));
+ os_reltime_age(&hapd->iface->dfs_cac_start, &now);
+ blobmsg_add_u32(&b, "cac_seconds_left",
+ hapd->iface->cac_started ? hapd->iface->dfs_cac_ms / 1000 - now.sec : 0);
+ blobmsg_close_table(&b, dfs_table);
+
+ ubus_send_reply(ctx, req, b.head);
+
+ return 0;
+}
+
+enum {
+ NOTIFY_RESPONSE,
+ __NOTIFY_MAX
+};
+
+static const struct blobmsg_policy notify_policy[__NOTIFY_MAX] = {
+ [NOTIFY_RESPONSE] = { "notify_response", BLOBMSG_TYPE_INT32 },
+};
+
+static int
+hostapd_notify_response(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *req, const char *method,
+ struct blob_attr *msg)
+{
+ struct blob_attr *tb[__NOTIFY_MAX];
+ struct hostapd_data *hapd = get_hapd_from_object(obj);
+ struct wpabuf *elems;
+ const char *pos;
+ size_t len;
+
+ blobmsg_parse(notify_policy, __NOTIFY_MAX, tb,
+ blob_data(msg), blob_len(msg));
+
+ if (!tb[NOTIFY_RESPONSE])
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
+ hapd->ubus.notify_response = blobmsg_get_u32(tb[NOTIFY_RESPONSE]);
+
+ return UBUS_STATUS_OK;
+}
+
+enum {
+ DEL_CLIENT_ADDR,
+ DEL_CLIENT_REASON,
+ DEL_CLIENT_DEAUTH,
+ DEL_CLIENT_BAN_TIME,
+ __DEL_CLIENT_MAX
+};
+
+static const struct blobmsg_policy del_policy[__DEL_CLIENT_MAX] = {
+ [DEL_CLIENT_ADDR] = { "addr", BLOBMSG_TYPE_STRING },
+ [DEL_CLIENT_REASON] = { "reason", BLOBMSG_TYPE_INT32 },
+ [DEL_CLIENT_DEAUTH] = { "deauth", BLOBMSG_TYPE_INT8 },
+ [DEL_CLIENT_BAN_TIME] = { "ban_time", BLOBMSG_TYPE_INT32 },
+};
+
+static int
+hostapd_bss_del_client(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *req, const char *method,
+ struct blob_attr *msg)
+{
+ struct blob_attr *tb[__DEL_CLIENT_MAX];
+ struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
+ struct sta_info *sta;
+ bool deauth = false;
+ int reason;
+ u8 addr[ETH_ALEN];
+
+ blobmsg_parse(del_policy, __DEL_CLIENT_MAX, tb, blob_data(msg), blob_len(msg));
+
+ if (!tb[DEL_CLIENT_ADDR])
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
+ if (hwaddr_aton(blobmsg_data(tb[DEL_CLIENT_ADDR]), addr))
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
+ if (tb[DEL_CLIENT_REASON])
+ reason = blobmsg_get_u32(tb[DEL_CLIENT_REASON]);
+
+ if (tb[DEL_CLIENT_DEAUTH])
+ deauth = blobmsg_get_bool(tb[DEL_CLIENT_DEAUTH]);
+
+ sta = ap_get_sta(hapd, addr);
+ if (sta) {
+ if (deauth) {
+ hostapd_drv_sta_deauth(hapd, addr, reason);
+ ap_sta_deauthenticate(hapd, sta, reason);
+ } else {
+ hostapd_drv_sta_disassoc(hapd, addr, reason);
+ ap_sta_disassociate(hapd, sta, reason);
+ }
+ }
+
+ if (tb[DEL_CLIENT_BAN_TIME])
+ hostapd_bss_ban_client(hapd, addr, blobmsg_get_u32(tb[DEL_CLIENT_BAN_TIME]));
+
+ return 0;
+}
+
+static void
+blobmsg_add_macaddr(struct blob_buf *buf, const char *name, const u8 *addr)
+{
+ char *s;
+
+ s = blobmsg_alloc_string_buffer(buf, name, 20);
+ sprintf(s, MACSTR, MAC2STR(addr));
+ blobmsg_add_string_buffer(buf);
+}
+
+static int
+hostapd_bss_list_bans(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *req, const char *method,
+ struct blob_attr *msg)
+{
+ struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
+ struct ubus_banned_client *ban;
+ void *c;
+
+ blob_buf_init(&b, 0);
+ c = blobmsg_open_array(&b, "clients");
+ avl_for_each_element(&hapd->ubus.banned, ban, avl)
+ blobmsg_add_macaddr(&b, NULL, ban->addr);
+ blobmsg_close_array(&b, c);
+ ubus_send_reply(ctx, req, b.head);
+
+ return 0;
+}
+
+#ifdef CONFIG_WPS
+static int
+hostapd_bss_wps_start(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *req, const char *method,
+ struct blob_attr *msg)
+{
+ int rc;
+ struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
+
+ rc = hostapd_wps_button_pushed(hapd, NULL);
+
+ if (rc != 0)
+ return UBUS_STATUS_NOT_SUPPORTED;
+
+ return 0;
+}
+
+
+static const char * pbc_status_enum_str(enum pbc_status status)
+{
+ switch (status) {
+ case WPS_PBC_STATUS_DISABLE:
+ return "Disabled";
+ case WPS_PBC_STATUS_ACTIVE:
+ return "Active";
+ case WPS_PBC_STATUS_TIMEOUT:
+ return "Timed-out";
+ case WPS_PBC_STATUS_OVERLAP:
+ return "Overlap";
+ default:
+ return "Unknown";
+ }
+}
+
+static int
+hostapd_bss_wps_status(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *req, const char *method,
+ struct blob_attr *msg)
+{
+ int rc;
+ struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
+
+ blob_buf_init(&b, 0);
+
+ blobmsg_add_string(&b, "pbc_status", pbc_status_enum_str(hapd->wps_stats.pbc_status));
+ blobmsg_add_string(&b, "last_wps_result",
+ (hapd->wps_stats.status == WPS_STATUS_SUCCESS ?
+ "Success":
+ (hapd->wps_stats.status == WPS_STATUS_FAILURE ?
+ "Failed" : "None")));
+
+ /* If status == Failure - Add possible Reasons */
+ if(hapd->wps_stats.status == WPS_STATUS_FAILURE &&
+ hapd->wps_stats.failure_reason > 0)
+ blobmsg_add_string(&b, "reason", wps_ei_str(hapd->wps_stats.failure_reason));
+
+ if (hapd->wps_stats.status)
+ blobmsg_printf(&b, "peer_address", MACSTR, MAC2STR(hapd->wps_stats.peer_addr));
+
+ ubus_send_reply(ctx, req, b.head);
+
+ return 0;
+}
+
+static int
+hostapd_bss_wps_cancel(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *req, const char *method,
+ struct blob_attr *msg)
+{
+ int rc;
+ struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
+
+ rc = hostapd_wps_cancel(hapd);
+
+ if (rc != 0)
+ return UBUS_STATUS_NOT_SUPPORTED;
+
+ return 0;
+}
+#endif /* CONFIG_WPS */
+
+static int
+hostapd_bss_update_beacon(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *req, const char *method,
+ struct blob_attr *msg)
+{
+ int rc;
+ struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
+
+ rc = ieee802_11_set_beacon(hapd);
+
+ if (rc != 0)
+ return UBUS_STATUS_NOT_SUPPORTED;
+
+ return 0;
+}
+
+enum {
+ CONFIG_IFACE,
+ CONFIG_FILE,
+ __CONFIG_MAX
+};
+
+enum {
+ CSA_FREQ,
+ CSA_BCN_COUNT,
+ CSA_CENTER_FREQ1,
+ CSA_CENTER_FREQ2,
+ CSA_BANDWIDTH,
+ CSA_SEC_CHANNEL_OFFSET,
+ CSA_HT,
+ CSA_VHT,
+ CSA_HE,
+ CSA_BLOCK_TX,
+ CSA_FORCE,
+ __CSA_MAX
+};
+
+static const struct blobmsg_policy csa_policy[__CSA_MAX] = {
+ [CSA_FREQ] = { "freq", BLOBMSG_TYPE_INT32 },
+ [CSA_BCN_COUNT] = { "bcn_count", BLOBMSG_TYPE_INT32 },
+ [CSA_CENTER_FREQ1] = { "center_freq1", BLOBMSG_TYPE_INT32 },
+ [CSA_CENTER_FREQ2] = { "center_freq2", BLOBMSG_TYPE_INT32 },
+ [CSA_BANDWIDTH] = { "bandwidth", BLOBMSG_TYPE_INT32 },
+ [CSA_SEC_CHANNEL_OFFSET] = { "sec_channel_offset", BLOBMSG_TYPE_INT32 },
+ [CSA_HT] = { "ht", BLOBMSG_TYPE_BOOL },
+ [CSA_VHT] = { "vht", BLOBMSG_TYPE_BOOL },
+ [CSA_HE] = { "he", BLOBMSG_TYPE_BOOL },
+ [CSA_BLOCK_TX] = { "block_tx", BLOBMSG_TYPE_BOOL },
+ [CSA_FORCE] = { "force", BLOBMSG_TYPE_BOOL },
+};
+
+
+static void switch_chan_fallback_cb(void *eloop_data, void *user_ctx)
+{
+ struct hostapd_iface *iface = eloop_data;
+ struct hostapd_freq_params *freq_params = user_ctx;
+
+ hostapd_switch_channel_fallback(iface, freq_params);
+}
+
+#ifdef NEED_AP_MLME
+static int
+hostapd_switch_chan(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *req, const char *method,
+ struct blob_attr *msg)
+{
+ struct blob_attr *tb[__CSA_MAX];
+ struct hostapd_data *hapd = get_hapd_from_object(obj);
+ struct hostapd_config *iconf = hapd->iface->conf;
+ struct hostapd_freq_params *freq_params;
+ struct hostapd_hw_modes *mode = hapd->iface->current_mode;
+ struct csa_settings css = {
+ .freq_params = {
+ .ht_enabled = iconf->ieee80211n,
+ .vht_enabled = iconf->ieee80211ac,
+ .he_enabled = iconf->ieee80211ax,
+ .sec_channel_offset = iconf->secondary_channel,
+ }
+ };
+ u8 chwidth = hostapd_get_oper_chwidth(iconf);
+ u8 seg0 = 0, seg1 = 0;
+ int ret = UBUS_STATUS_OK;
+ int i;
+
+ blobmsg_parse(csa_policy, __CSA_MAX, tb, blob_data(msg), blob_len(msg));
+
+ if (!tb[CSA_FREQ])
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
+ switch (iconf->vht_oper_chwidth) {
+ case CHANWIDTH_USE_HT:
+ if (iconf->secondary_channel)
+ css.freq_params.bandwidth = 40;
+ else
+ css.freq_params.bandwidth = 20;
+ break;
+ case CHANWIDTH_160MHZ:
+ css.freq_params.bandwidth = 160;
+ break;
+ default:
+ css.freq_params.bandwidth = 80;
+ break;
+ }
+
+ css.freq_params.freq = blobmsg_get_u32(tb[CSA_FREQ]);
+
+#define SET_CSA_SETTING(name, field, type) \
+ do { \
+ if (tb[name]) \
+ css.field = blobmsg_get_ ## type(tb[name]); \
+ } while(0)
+
+ SET_CSA_SETTING(CSA_BCN_COUNT, cs_count, u32);
+ SET_CSA_SETTING(CSA_CENTER_FREQ1, freq_params.center_freq1, u32);
+ SET_CSA_SETTING(CSA_CENTER_FREQ2, freq_params.center_freq2, u32);
+ SET_CSA_SETTING(CSA_BANDWIDTH, freq_params.bandwidth, u32);
+ SET_CSA_SETTING(CSA_SEC_CHANNEL_OFFSET, freq_params.sec_channel_offset, u32);
+ SET_CSA_SETTING(CSA_HT, freq_params.ht_enabled, bool);
+ SET_CSA_SETTING(CSA_VHT, freq_params.vht_enabled, bool);
+ SET_CSA_SETTING(CSA_HE, freq_params.he_enabled, bool);
+ SET_CSA_SETTING(CSA_BLOCK_TX, block_tx, bool);
+
+ css.freq_params.channel = hostapd_hw_get_channel(hapd, css.freq_params.freq);
+ if (!css.freq_params.channel)
+ return UBUS_STATUS_NOT_SUPPORTED;
+
+ switch (css.freq_params.bandwidth) {
+ case 160:
+ chwidth = CHANWIDTH_160MHZ;
+ break;
+ case 80:
+ chwidth = css.freq_params.center_freq2 ? CHANWIDTH_80P80MHZ : CHANWIDTH_80MHZ;
+ break;
+ default:
+ chwidth = CHANWIDTH_USE_HT;
+ break;
+ }
+
+ hostapd_set_freq_params(&css.freq_params, iconf->hw_mode,
+ css.freq_params.freq,
+ css.freq_params.channel, iconf->enable_edmg,
+ iconf->edmg_channel,
+ css.freq_params.ht_enabled,
+ css.freq_params.vht_enabled,
+ css.freq_params.he_enabled,
+ css.freq_params.eht_enabled,
+ css.freq_params.sec_channel_offset,
+ chwidth, seg0, seg1,
+ iconf->vht_capab,
+ mode ? &mode->he_capab[IEEE80211_MODE_AP] :
+ NULL,
+ mode ? &mode->eht_capab[IEEE80211_MODE_AP] :
+ NULL);
+
+ for (i = 0; i < hapd->iface->num_bss; i++) {
+ struct hostapd_data *bss = hapd->iface->bss[i];
+
+ if (hostapd_switch_channel(bss, &css) != 0)
+ ret = UBUS_STATUS_NOT_SUPPORTED;
+ }
+
+ if (!ret || !tb[CSA_FORCE] || !blobmsg_get_bool(tb[CSA_FORCE]))
+ return ret;
+
+ freq_params = malloc(sizeof(*freq_params));
+ memcpy(freq_params, &css.freq_params, sizeof(*freq_params));
+ eloop_register_timeout(0, 1, switch_chan_fallback_cb,
+ hapd->iface, freq_params);
+
+ return 0;
+#undef SET_CSA_SETTING
+}
+#endif
+
+enum {
+ VENDOR_ELEMENTS,
+ __VENDOR_ELEMENTS_MAX
+};
+
+static const struct blobmsg_policy ve_policy[__VENDOR_ELEMENTS_MAX] = {
+ /* vendor elements are provided as hex-string */
+ [VENDOR_ELEMENTS] = { "vendor_elements", BLOBMSG_TYPE_STRING },
+};
+
+static int
+hostapd_vendor_elements(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *req, const char *method,
+ struct blob_attr *msg)
+{
+ struct blob_attr *tb[__VENDOR_ELEMENTS_MAX];
+ struct hostapd_data *hapd = get_hapd_from_object(obj);
+ struct hostapd_bss_config *bss = hapd->conf;
+ struct wpabuf *elems;
+ const char *pos;
+ size_t len;
+
+ blobmsg_parse(ve_policy, __VENDOR_ELEMENTS_MAX, tb,
+ blob_data(msg), blob_len(msg));
+
+ if (!tb[VENDOR_ELEMENTS])
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
+ pos = blobmsg_data(tb[VENDOR_ELEMENTS]);
+ len = os_strlen(pos);
+ if (len & 0x01)
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
+ len /= 2;
+ if (len == 0) {
+ wpabuf_free(bss->vendor_elements);
+ bss->vendor_elements = NULL;
+ return 0;
+ }
+
+ elems = wpabuf_alloc(len);
+ if (elems == NULL)
+ return 1;
+
+ if (hexstr2bin(pos, wpabuf_put(elems, len), len)) {
+ wpabuf_free(elems);
+ return UBUS_STATUS_INVALID_ARGUMENT;
+ }
+
+ wpabuf_free(bss->vendor_elements);
+ bss->vendor_elements = elems;
+
+ /* update beacons if vendor elements were set successfully */
+ if (ieee802_11_update_beacons(hapd->iface) != 0)
+ return UBUS_STATUS_NOT_SUPPORTED;
+ return UBUS_STATUS_OK;
+}
+
+static void
+hostapd_rrm_print_nr(struct hostapd_neighbor_entry *nr)
+{
+ const u8 *data;
+ char *str;
+ int len;
+
+ blobmsg_printf(&b, "", MACSTR, MAC2STR(nr->bssid));
+
+ str = blobmsg_alloc_string_buffer(&b, "", nr->ssid.ssid_len + 1);
+ memcpy(str, nr->ssid.ssid, nr->ssid.ssid_len);
+ str[nr->ssid.ssid_len] = 0;
+ blobmsg_add_string_buffer(&b);
+
+ len = wpabuf_len(nr->nr);
+ str = blobmsg_alloc_string_buffer(&b, "", 2 * len + 1);
+ wpa_snprintf_hex(str, 2 * len + 1, wpabuf_head_u8(nr->nr), len);
+ blobmsg_add_string_buffer(&b);
+}
+
+enum {
+ BSS_MGMT_EN_NEIGHBOR,
+ BSS_MGMT_EN_BEACON,
+ BSS_MGMT_EN_LINK_MEASUREMENT,
+#ifdef CONFIG_WNM_AP
+ BSS_MGMT_EN_BSS_TRANSITION,
+#endif
+ __BSS_MGMT_EN_MAX
+};
+
+static bool
+__hostapd_bss_mgmt_enable_f(struct hostapd_data *hapd, int flag)
+{
+ struct hostapd_bss_config *bss = hapd->conf;
+ uint32_t flags;
+
+ switch (flag) {
+ case BSS_MGMT_EN_NEIGHBOR:
+ if (bss->radio_measurements[0] &
+ WLAN_RRM_CAPS_NEIGHBOR_REPORT)
+ return false;
+
+ bss->radio_measurements[0] |=
+ WLAN_RRM_CAPS_NEIGHBOR_REPORT;
+ hostapd_neighbor_set_own_report(hapd);
+ return true;
+ case BSS_MGMT_EN_BEACON:
+ flags = WLAN_RRM_CAPS_BEACON_REPORT_PASSIVE |
+ WLAN_RRM_CAPS_BEACON_REPORT_ACTIVE |
+ WLAN_RRM_CAPS_BEACON_REPORT_TABLE;
+
+ if (bss->radio_measurements[0] & flags == flags)
+ return false;
+
+ bss->radio_measurements[0] |= (u8) flags;
+ return true;
+ case BSS_MGMT_EN_LINK_MEASUREMENT:
+ flags = WLAN_RRM_CAPS_LINK_MEASUREMENT;
+
+ if (bss->radio_measurements[0] & flags == flags)
+ return false;
+
+ bss->radio_measurements[0] |= (u8) flags;
+ return true;
+#ifdef CONFIG_WNM_AP
+ case BSS_MGMT_EN_BSS_TRANSITION:
+ if (bss->bss_transition)
+ return false;
+
+ bss->bss_transition = 1;
+ return true;
+#endif
+ }
+}
+
+static void
+__hostapd_bss_mgmt_enable(struct hostapd_data *hapd, uint32_t flags)
+{
+ bool update = false;
+ int i;
+
+ for (i = 0; i < __BSS_MGMT_EN_MAX; i++) {
+ if (!(flags & (1 << i)))
+ continue;
+
+ update |= __hostapd_bss_mgmt_enable_f(hapd, i);
+ }
+
+ if (update)
+ ieee802_11_update_beacons(hapd->iface);
+}
+
+
+static const struct blobmsg_policy bss_mgmt_enable_policy[__BSS_MGMT_EN_MAX] = {
+ [BSS_MGMT_EN_NEIGHBOR] = { "neighbor_report", BLOBMSG_TYPE_BOOL },
+ [BSS_MGMT_EN_BEACON] = { "beacon_report", BLOBMSG_TYPE_BOOL },
+ [BSS_MGMT_EN_LINK_MEASUREMENT] = { "link_measurement", BLOBMSG_TYPE_BOOL },
+#ifdef CONFIG_WNM_AP
+ [BSS_MGMT_EN_BSS_TRANSITION] = { "bss_transition", BLOBMSG_TYPE_BOOL },
+#endif
+};
+
+static int
+hostapd_bss_mgmt_enable(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *req, const char *method,
+ struct blob_attr *msg)
+
+{
+ struct hostapd_data *hapd = get_hapd_from_object(obj);
+ struct blob_attr *tb[__BSS_MGMT_EN_MAX];
+ struct blob_attr *cur;
+ uint32_t flags = 0;
+ int i;
+ bool neigh = false, beacon = false;
+
+ blobmsg_parse(bss_mgmt_enable_policy, __BSS_MGMT_EN_MAX, tb, blob_data(msg), blob_len(msg));
+
+ for (i = 0; i < ARRAY_SIZE(tb); i++) {
+ if (!tb[i] || !blobmsg_get_bool(tb[i]))
+ continue;
+
+ flags |= (1 << i);
+ }
+
+ __hostapd_bss_mgmt_enable(hapd, flags);
+
+ return 0;
+}
+
+
+static void
+hostapd_rrm_nr_enable(struct hostapd_data *hapd)
+{
+ __hostapd_bss_mgmt_enable(hapd, 1 << BSS_MGMT_EN_NEIGHBOR);
+}
+
+static int
+hostapd_rrm_nr_get_own(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *req, const char *method,
+ struct blob_attr *msg)
+{
+ struct hostapd_data *hapd = get_hapd_from_object(obj);
+ struct hostapd_neighbor_entry *nr;
+ void *c;
+
+ hostapd_rrm_nr_enable(hapd);
+
+ nr = hostapd_neighbor_get(hapd, hapd->own_addr, NULL);
+ if (!nr)
+ return UBUS_STATUS_NOT_FOUND;
+
+ blob_buf_init(&b, 0);
+
+ c = blobmsg_open_array(&b, "value");
+ hostapd_rrm_print_nr(nr);
+ blobmsg_close_array(&b, c);
+
+ ubus_send_reply(ctx, req, b.head);
+
+ return 0;
+}
+
+static int
+hostapd_rrm_nr_list(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *req, const char *method,
+ struct blob_attr *msg)
+{
+ struct hostapd_data *hapd = get_hapd_from_object(obj);
+ struct hostapd_neighbor_entry *nr;
+ void *c;
+
+ hostapd_rrm_nr_enable(hapd);
+ blob_buf_init(&b, 0);
+
+ c = blobmsg_open_array(&b, "list");
+ dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry, list) {
+ void *cur;
+
+ if (!memcmp(nr->bssid, hapd->own_addr, ETH_ALEN))
+ continue;
+
+ cur = blobmsg_open_array(&b, NULL);
+ hostapd_rrm_print_nr(nr);
+ blobmsg_close_array(&b, cur);
+ }
+ blobmsg_close_array(&b, c);
+
+ ubus_send_reply(ctx, req, b.head);
+
+ return 0;
+}
+
+enum {
+ NR_SET_LIST,
+ __NR_SET_LIST_MAX
+};
+
+static const struct blobmsg_policy nr_set_policy[__NR_SET_LIST_MAX] = {
+ [NR_SET_LIST] = { "list", BLOBMSG_TYPE_ARRAY },
+};
+
+
+static void
+hostapd_rrm_nr_clear(struct hostapd_data *hapd)
+{
+ struct hostapd_neighbor_entry *nr;
+
+restart:
+ dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry, list) {
+ if (!memcmp(nr->bssid, hapd->own_addr, ETH_ALEN))
+ continue;
+
+ hostapd_neighbor_remove(hapd, nr->bssid, &nr->ssid);
+ goto restart;
+ }
+}
+
+static int
+hostapd_rrm_nr_set(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *req, const char *method,
+ struct blob_attr *msg)
+{
+ static const struct blobmsg_policy nr_e_policy[] = {
+ { .type = BLOBMSG_TYPE_STRING },
+ { .type = BLOBMSG_TYPE_STRING },
+ { .type = BLOBMSG_TYPE_STRING },
+ };
+ struct hostapd_data *hapd = get_hapd_from_object(obj);
+ struct blob_attr *tb_l[__NR_SET_LIST_MAX];
+ struct blob_attr *tb[ARRAY_SIZE(nr_e_policy)];
+ struct blob_attr *cur;
+ int rem;
+
+ hostapd_rrm_nr_enable(hapd);
+
+ blobmsg_parse(nr_set_policy, __NR_SET_LIST_MAX, tb_l, blob_data(msg), blob_len(msg));
+ if (!tb_l[NR_SET_LIST])
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
+ hostapd_rrm_nr_clear(hapd);
+ blobmsg_for_each_attr(cur, tb_l[NR_SET_LIST], rem) {
+ struct wpa_ssid_value ssid;
+ struct wpabuf *data;
+ u8 bssid[ETH_ALEN];
+ char *s, *nr_s;
+
+ blobmsg_parse_array(nr_e_policy, ARRAY_SIZE(nr_e_policy), tb, blobmsg_data(cur), blobmsg_data_len(cur));
+ if (!tb[0] || !tb[1] || !tb[2])
+ goto invalid;
+
+ /* Neighbor Report binary */
+ nr_s = blobmsg_get_string(tb[2]);
+ data = wpabuf_parse_bin(nr_s);
+ if (!data)
+ goto invalid;
+
+ /* BSSID */
+ s = blobmsg_get_string(tb[0]);
+ if (strlen(s) == 0) {
+ /* Copy BSSID from neighbor report */
+ if (hwaddr_compact_aton(nr_s, bssid))
+ goto invalid;
+ } else if (hwaddr_aton(s, bssid)) {
+ goto invalid;
+ }
+
+ /* SSID */
+ s = blobmsg_get_string(tb[1]);
+ if (strlen(s) == 0) {
+ /* Copy SSID from hostapd BSS conf */
+ memcpy(&ssid, &hapd->conf->ssid, sizeof(ssid));
+ } else {
+ ssid.ssid_len = strlen(s);
+ if (ssid.ssid_len > sizeof(ssid.ssid))
+ goto invalid;
+
+ memcpy(&ssid, s, ssid.ssid_len);
+ }
+
+ hostapd_neighbor_set(hapd, bssid, &ssid, data, NULL, NULL, 0, 0);
+ wpabuf_free(data);
+ continue;
+
+invalid:
+ return UBUS_STATUS_INVALID_ARGUMENT;
+ }
+
+ return 0;
+}
+
+enum {
+ BEACON_REQ_ADDR,
+ BEACON_REQ_MODE,
+ BEACON_REQ_OP_CLASS,
+ BEACON_REQ_CHANNEL,
+ BEACON_REQ_DURATION,
+ BEACON_REQ_BSSID,
+ BEACON_REQ_SSID,
+ __BEACON_REQ_MAX,
+};
+
+static const struct blobmsg_policy beacon_req_policy[__BEACON_REQ_MAX] = {
+ [BEACON_REQ_ADDR] = { "addr", BLOBMSG_TYPE_STRING },
+ [BEACON_REQ_OP_CLASS] { "op_class", BLOBMSG_TYPE_INT32 },
+ [BEACON_REQ_CHANNEL] { "channel", BLOBMSG_TYPE_INT32 },
+ [BEACON_REQ_DURATION] { "duration", BLOBMSG_TYPE_INT32 },
+ [BEACON_REQ_MODE] { "mode", BLOBMSG_TYPE_INT32 },
+ [BEACON_REQ_BSSID] { "bssid", BLOBMSG_TYPE_STRING },
+ [BEACON_REQ_SSID] { "ssid", BLOBMSG_TYPE_STRING },
+};
+
+static int
+hostapd_rrm_beacon_req(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *ureq, const char *method,
+ struct blob_attr *msg)
+{
+ struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
+ struct blob_attr *tb[__BEACON_REQ_MAX];
+ struct blob_attr *cur;
+ struct wpabuf *req;
+ u8 bssid[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+ u8 addr[ETH_ALEN];
+ int mode, rem, ret;
+ int buf_len = 13;
+
+ blobmsg_parse(beacon_req_policy, __BEACON_REQ_MAX, tb, blob_data(msg), blob_len(msg));
+
+ if (!tb[BEACON_REQ_ADDR] || !tb[BEACON_REQ_MODE] || !tb[BEACON_REQ_DURATION] ||
+ !tb[BEACON_REQ_OP_CLASS] || !tb[BEACON_REQ_CHANNEL])
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
+ if (tb[BEACON_REQ_SSID])
+ buf_len += blobmsg_data_len(tb[BEACON_REQ_SSID]) + 2 - 1;
+
+ mode = blobmsg_get_u32(tb[BEACON_REQ_MODE]);
+ if (hwaddr_aton(blobmsg_data(tb[BEACON_REQ_ADDR]), addr))
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
+ if (tb[BEACON_REQ_BSSID] &&
+ hwaddr_aton(blobmsg_data(tb[BEACON_REQ_BSSID]), bssid))
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
+ req = wpabuf_alloc(buf_len);
+ if (!req)
+ return UBUS_STATUS_UNKNOWN_ERROR;
+
+ /* 1: regulatory class */
+ wpabuf_put_u8(req, blobmsg_get_u32(tb[BEACON_REQ_OP_CLASS]));
+
+ /* 2: channel number */
+ wpabuf_put_u8(req, blobmsg_get_u32(tb[BEACON_REQ_CHANNEL]));
+
+ /* 3-4: randomization interval */
+ wpabuf_put_le16(req, 0);
+
+ /* 5-6: duration */
+ wpabuf_put_le16(req, blobmsg_get_u32(tb[BEACON_REQ_DURATION]));
+
+ /* 7: mode */
+ wpabuf_put_u8(req, blobmsg_get_u32(tb[BEACON_REQ_MODE]));
+
+ /* 8-13: BSSID */
+ wpabuf_put_data(req, bssid, ETH_ALEN);
+
+ if ((cur = tb[BEACON_REQ_SSID]) != NULL) {
+ wpabuf_put_u8(req, WLAN_EID_SSID);
+ wpabuf_put_u8(req, blobmsg_data_len(cur) - 1);
+ wpabuf_put_data(req, blobmsg_data(cur), blobmsg_data_len(cur) - 1);
+ }
+
+ ret = hostapd_send_beacon_req(hapd, addr, 0, req);
+ if (ret < 0)
+ return -ret;
+
+ return 0;
+}
+
+enum {
+ LM_REQ_ADDR,
+ LM_REQ_TX_POWER_USED,
+ LM_REQ_TX_POWER_MAX,
+ __LM_REQ_MAX,
+};
+
+static const struct blobmsg_policy lm_req_policy[__LM_REQ_MAX] = {
+ [LM_REQ_ADDR] = { "addr", BLOBMSG_TYPE_STRING },
+ [LM_REQ_TX_POWER_USED] = { "tx-power-used", BLOBMSG_TYPE_INT32 },
+ [LM_REQ_TX_POWER_MAX] = { "tx-power-max", BLOBMSG_TYPE_INT32 },
+};
+
+static int
+hostapd_rrm_lm_req(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *ureq, const char *method,
+ struct blob_attr *msg)
+{
+ struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
+ struct blob_attr *tb[__LM_REQ_MAX];
+ struct wpabuf *buf;
+ u8 addr[ETH_ALEN];
+ int ret;
+ int8_t txp_used, txp_max;
+
+ txp_used = 0;
+ txp_max = 0;
+
+ blobmsg_parse(lm_req_policy, __LM_REQ_MAX, tb, blob_data(msg), blob_len(msg));
+
+ if (!tb[LM_REQ_ADDR])
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
+ if (tb[LM_REQ_TX_POWER_USED])
+ txp_used = (int8_t) blobmsg_get_u32(tb[LM_REQ_TX_POWER_USED]);
+
+ if (tb[LM_REQ_TX_POWER_MAX])
+ txp_max = (int8_t) blobmsg_get_u32(tb[LM_REQ_TX_POWER_MAX]);
+
+ if (hwaddr_aton(blobmsg_data(tb[LM_REQ_ADDR]), addr))
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
+ buf = wpabuf_alloc(5);
+ if (!buf)
+ return UBUS_STATUS_UNKNOWN_ERROR;
+
+ wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT);
+ wpabuf_put_u8(buf, WLAN_RRM_LINK_MEASUREMENT_REQUEST);
+ wpabuf_put_u8(buf, 1);
+ /* TX-Power used */
+ wpabuf_put_u8(buf, txp_used);
+ /* Max TX Power */
+ wpabuf_put_u8(buf, txp_max);
+
+ ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr,
+ wpabuf_head(buf), wpabuf_len(buf));
+
+ wpabuf_free(buf);
+ if (ret < 0)
+ return -ret;
+
+ return 0;
+}
+
+
+void hostapd_ubus_handle_link_measurement(struct hostapd_data *hapd, const u8 *data, size_t len)
+{
+ const struct ieee80211_mgmt *mgmt = (const struct ieee80211_mgmt *) data;
+ const u8 *pos, *end;
+ u8 token;
+
+ end = data + len;
+ token = mgmt->u.action.u.rrm.dialog_token;
+ pos = mgmt->u.action.u.rrm.variable;
+
+ if (end - pos < 8)
+ return;
+
+ if (!hapd->ubus.obj.has_subscribers)
+ return;
+
+ blob_buf_init(&b, 0);
+ blobmsg_add_macaddr(&b, "address", mgmt->sa);
+ blobmsg_add_u16(&b, "dialog-token", token);
+ blobmsg_add_u16(&b, "rx-antenna-id", pos[4]);
+ blobmsg_add_u16(&b, "tx-antenna-id", pos[5]);
+ blobmsg_add_u16(&b, "rcpi", pos[6]);
+ blobmsg_add_u16(&b, "rsni", pos[7]);
+
+ ubus_notify(ctx, &hapd->ubus.obj, "link-measurement-report", b.head, -1);
+}
+
+
+#ifdef CONFIG_WNM_AP
+
+static int
+hostapd_bss_tr_send(struct hostapd_data *hapd, u8 *addr, bool disassoc_imminent, bool abridged,
+ u16 disassoc_timer, u8 validity_period, u8 dialog_token,
+ struct blob_attr *neighbors, u8 mbo_reason, u8 cell_pref, u8 reassoc_delay)
+{
+ struct blob_attr *cur;
+ struct sta_info *sta;
+ int nr_len = 0;
+ int rem;
+ u8 *nr = NULL;
+ u8 req_mode = 0;
+ u8 mbo[10];
+ size_t mbo_len = 0;
+
+ sta = ap_get_sta(hapd, addr);
+ if (!sta)
+ return UBUS_STATUS_NOT_FOUND;
+
+ if (neighbors) {
+ u8 *nr_cur;
+
+ if (blobmsg_check_array(neighbors,
+ BLOBMSG_TYPE_STRING) < 0)
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
+ blobmsg_for_each_attr(cur, neighbors, rem) {
+ int len = strlen(blobmsg_get_string(cur));
+
+ if (len % 2)
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
+ nr_len += (len / 2) + 2;
+ }
+
+ if (nr_len) {
+ nr = os_zalloc(nr_len);
+ if (!nr)
+ return UBUS_STATUS_UNKNOWN_ERROR;
+ }
+
+ nr_cur = nr;
+ blobmsg_for_each_attr(cur, neighbors, rem) {
+ int len = strlen(blobmsg_get_string(cur)) / 2;
+
+ *nr_cur++ = WLAN_EID_NEIGHBOR_REPORT;
+ *nr_cur++ = (u8) len;
+ if (hexstr2bin(blobmsg_data(cur), nr_cur, len)) {
+ free(nr);
+ return UBUS_STATUS_INVALID_ARGUMENT;
+ }
+
+ nr_cur += len;
+ }
+ }
+
+ if (nr)
+ req_mode |= WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED;
+
+ if (abridged)
+ req_mode |= WNM_BSS_TM_REQ_ABRIDGED;
+
+ if (disassoc_imminent)
+ req_mode |= WNM_BSS_TM_REQ_DISASSOC_IMMINENT;
+
+#ifdef CONFIG_MBO
+ u8 *mbo_pos = mbo;
+
+ if (mbo_reason > MBO_TRANSITION_REASON_PREMIUM_AP)
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
+ if (cell_pref != 0 && cell_pref != 1 && cell_pref != 255)
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
+ if (reassoc_delay > 65535 || (reassoc_delay && !disassoc_imminent))
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
+ *mbo_pos++ = MBO_ATTR_ID_TRANSITION_REASON;
+ *mbo_pos++ = 1;
+ *mbo_pos++ = mbo_reason;
+ *mbo_pos++ = MBO_ATTR_ID_CELL_DATA_PREF;
+ *mbo_pos++ = 1;
+ *mbo_pos++ = cell_pref;
+
+ if (reassoc_delay) {
+ *mbo_pos++ = MBO_ATTR_ID_ASSOC_RETRY_DELAY;
+ *mbo_pos++ = 2;
+ WPA_PUT_LE16(mbo_pos, reassoc_delay);
+ mbo_pos += 2;
+ }
+
+ mbo_len = mbo_pos - mbo;
+#endif
+
+ if (wnm_send_bss_tm_req(hapd, sta, req_mode, disassoc_timer, validity_period, NULL,
+ dialog_token, NULL, nr, nr_len, mbo_len ? mbo : NULL, mbo_len))
+ return UBUS_STATUS_UNKNOWN_ERROR;
+
+ return 0;
+}
+
+enum {
+ BSS_TR_ADDR,
+ BSS_TR_DA_IMMINENT,
+ BSS_TR_DA_TIMER,
+ BSS_TR_VALID_PERIOD,
+ BSS_TR_NEIGHBORS,
+ BSS_TR_ABRIDGED,
+ BSS_TR_DIALOG_TOKEN,
+#ifdef CONFIG_MBO
+ BSS_TR_MBO_REASON,
+ BSS_TR_CELL_PREF,
+ BSS_TR_REASSOC_DELAY,
+#endif
+ __BSS_TR_DISASSOC_MAX
+};
+
+static const struct blobmsg_policy bss_tr_policy[__BSS_TR_DISASSOC_MAX] = {
+ [BSS_TR_ADDR] = { "addr", BLOBMSG_TYPE_STRING },
+ [BSS_TR_DA_IMMINENT] = { "disassociation_imminent", BLOBMSG_TYPE_BOOL },
+ [BSS_TR_DA_TIMER] = { "disassociation_timer", BLOBMSG_TYPE_INT32 },
+ [BSS_TR_VALID_PERIOD] = { "validity_period", BLOBMSG_TYPE_INT32 },
+ [BSS_TR_NEIGHBORS] = { "neighbors", BLOBMSG_TYPE_ARRAY },
+ [BSS_TR_ABRIDGED] = { "abridged", BLOBMSG_TYPE_BOOL },
+ [BSS_TR_DIALOG_TOKEN] = { "dialog_token", BLOBMSG_TYPE_INT32 },
+#ifdef CONFIG_MBO
+ [BSS_TR_MBO_REASON] = { "mbo_reason", BLOBMSG_TYPE_INT32 },
+ [BSS_TR_CELL_PREF] = { "cell_pref", BLOBMSG_TYPE_INT32 },
+ [BSS_TR_REASSOC_DELAY] = { "reassoc_delay", BLOBMSG_TYPE_INT32 },
+#endif
+};
+
+static int
+hostapd_bss_transition_request(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *ureq, const char *method,
+ struct blob_attr *msg)
+{
+ struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
+ struct blob_attr *tb[__BSS_TR_DISASSOC_MAX];
+ struct sta_info *sta;
+ u32 da_timer = 0;
+ u32 valid_period = 0;
+ u8 addr[ETH_ALEN];
+ u32 dialog_token = 1;
+ bool abridged;
+ bool da_imminent;
+ u8 mbo_reason;
+ u8 cell_pref;
+ u8 reassoc_delay;
+
+ blobmsg_parse(bss_tr_policy, __BSS_TR_DISASSOC_MAX, tb, blob_data(msg), blob_len(msg));
+
+ if (!tb[BSS_TR_ADDR])
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
+ if (hwaddr_aton(blobmsg_data(tb[BSS_TR_ADDR]), addr))
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
+ if (tb[BSS_TR_DA_TIMER])
+ da_timer = blobmsg_get_u32(tb[BSS_TR_DA_TIMER]);
+
+ if (tb[BSS_TR_VALID_PERIOD])
+ valid_period = blobmsg_get_u32(tb[BSS_TR_VALID_PERIOD]);
+
+ if (tb[BSS_TR_DIALOG_TOKEN])
+ dialog_token = blobmsg_get_u32(tb[BSS_TR_DIALOG_TOKEN]);
+
+ da_imminent = !!(tb[BSS_TR_DA_IMMINENT] && blobmsg_get_bool(tb[BSS_TR_DA_IMMINENT]));
+ abridged = !!(tb[BSS_TR_ABRIDGED] && blobmsg_get_bool(tb[BSS_TR_ABRIDGED]));
+
+#ifdef CONFIG_MBO
+ if (tb[BSS_TR_MBO_REASON])
+ mbo_reason = blobmsg_get_u32(tb[BSS_TR_MBO_REASON]);
+
+ if (tb[BSS_TR_CELL_PREF])
+ cell_pref = blobmsg_get_u32(tb[BSS_TR_CELL_PREF]);
+
+ if (tb[BSS_TR_REASSOC_DELAY])
+ reassoc_delay = blobmsg_get_u32(tb[BSS_TR_REASSOC_DELAY]);
+#endif
+
+ return hostapd_bss_tr_send(hapd, addr, da_imminent, abridged, da_timer, valid_period,
+ dialog_token, tb[BSS_TR_NEIGHBORS], mbo_reason, cell_pref, reassoc_delay);
+}
+#endif
+
+#ifdef CONFIG_AIRTIME_POLICY
+enum {
+ UPDATE_AIRTIME_STA,
+ UPDATE_AIRTIME_WEIGHT,
+ __UPDATE_AIRTIME_MAX,
+};
+
+
+static const struct blobmsg_policy airtime_policy[__UPDATE_AIRTIME_MAX] = {
+ [UPDATE_AIRTIME_STA] = { "sta", BLOBMSG_TYPE_STRING },
+ [UPDATE_AIRTIME_WEIGHT] = { "weight", BLOBMSG_TYPE_INT32 },
+};
+
+static int
+hostapd_bss_update_airtime(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *ureq, const char *method,
+ struct blob_attr *msg)
+{
+ struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
+ struct blob_attr *tb[__UPDATE_AIRTIME_MAX];
+ struct sta_info *sta = NULL;
+ u8 addr[ETH_ALEN];
+ int weight;
+
+ blobmsg_parse(airtime_policy, __UPDATE_AIRTIME_MAX, tb, blob_data(msg), blob_len(msg));
+
+ if (!tb[UPDATE_AIRTIME_WEIGHT])
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
+ weight = blobmsg_get_u32(tb[UPDATE_AIRTIME_WEIGHT]);
+
+ if (!tb[UPDATE_AIRTIME_STA]) {
+ if (!weight)
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
+ hapd->conf->airtime_weight = weight;
+ return 0;
+ }
+
+ if (hwaddr_aton(blobmsg_data(tb[UPDATE_AIRTIME_STA]), addr))
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
+ sta = ap_get_sta(hapd, addr);
+ if (!sta)
+ return UBUS_STATUS_NOT_FOUND;
+
+ sta->dyn_airtime_weight = weight;
+ airtime_policy_new_sta(hapd, sta);
+
+ return 0;
+}
+#endif
+
+#ifdef CONFIG_TAXONOMY
+static const struct blobmsg_policy addr_policy[] = {
+ { "address", BLOBMSG_TYPE_STRING }
+};
+
+static bool
+hostapd_add_b64_data(const char *name, const struct wpabuf *buf)
+{
+ char *str;
+
+ if (!buf)
+ return false;
+
+ str = blobmsg_alloc_string_buffer(&b, name, B64_ENCODE_LEN(wpabuf_len(buf)));
+ b64_encode(wpabuf_head(buf), wpabuf_len(buf), str, B64_ENCODE_LEN(wpabuf_len(buf)));
+ blobmsg_add_string_buffer(&b);
+
+ return true;
+}
+
+static int
+hostapd_bss_get_sta_ies(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *req, const char *method,
+ struct blob_attr *msg)
+{
+ struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
+ struct blob_attr *tb;
+ struct sta_info *sta;
+ u8 addr[ETH_ALEN];
+
+ blobmsg_parse(addr_policy, 1, &tb, blobmsg_data(msg), blobmsg_len(msg));
+
+ if (!tb || hwaddr_aton(blobmsg_data(tb), addr))
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
+ sta = ap_get_sta(hapd, addr);
+ if (!sta || (!sta->probe_ie_taxonomy && !sta->assoc_ie_taxonomy))
+ return UBUS_STATUS_NOT_FOUND;
+
+ blob_buf_init(&b, 0);
+ hostapd_add_b64_data("probe_ie", sta->probe_ie_taxonomy);
+ hostapd_add_b64_data("assoc_ie", sta->assoc_ie_taxonomy);
+ ubus_send_reply(ctx, req, b.head);
+
+ return 0;
+}
+#endif
+
+
+static const struct ubus_method bss_methods[] = {
+ UBUS_METHOD_NOARG("reload", hostapd_bss_reload),
+ UBUS_METHOD_NOARG("get_clients", hostapd_bss_get_clients),
+#ifdef CONFIG_TAXONOMY
+ UBUS_METHOD("get_sta_ies", hostapd_bss_get_sta_ies, addr_policy),
+#endif
+ UBUS_METHOD_NOARG("get_status", hostapd_bss_get_status),
+ UBUS_METHOD("del_client", hostapd_bss_del_client, del_policy),
+#ifdef CONFIG_AIRTIME_POLICY
+ UBUS_METHOD("update_airtime", hostapd_bss_update_airtime, airtime_policy),
+#endif
+ UBUS_METHOD_NOARG("list_bans", hostapd_bss_list_bans),
+#ifdef CONFIG_WPS
+ UBUS_METHOD_NOARG("wps_start", hostapd_bss_wps_start),
+ UBUS_METHOD_NOARG("wps_status", hostapd_bss_wps_status),
+ UBUS_METHOD_NOARG("wps_cancel", hostapd_bss_wps_cancel),
+#endif
+ UBUS_METHOD_NOARG("update_beacon", hostapd_bss_update_beacon),
+ UBUS_METHOD_NOARG("get_features", hostapd_bss_get_features),
+#ifdef NEED_AP_MLME
+ UBUS_METHOD("switch_chan", hostapd_switch_chan, csa_policy),
+#endif
+ UBUS_METHOD("set_vendor_elements", hostapd_vendor_elements, ve_policy),
+ UBUS_METHOD("notify_response", hostapd_notify_response, notify_policy),
+ UBUS_METHOD("bss_mgmt_enable", hostapd_bss_mgmt_enable, bss_mgmt_enable_policy),
+ UBUS_METHOD_NOARG("rrm_nr_get_own", hostapd_rrm_nr_get_own),
+ UBUS_METHOD_NOARG("rrm_nr_list", hostapd_rrm_nr_list),
+ UBUS_METHOD("rrm_nr_set", hostapd_rrm_nr_set, nr_set_policy),
+ UBUS_METHOD("rrm_beacon_req", hostapd_rrm_beacon_req, beacon_req_policy),
+ UBUS_METHOD("link_measurement_req", hostapd_rrm_lm_req, lm_req_policy),
+#ifdef CONFIG_WNM_AP
+ UBUS_METHOD("bss_transition_request", hostapd_bss_transition_request, bss_tr_policy),
+#endif
+};
+
+static struct ubus_object_type bss_object_type =
+ UBUS_OBJECT_TYPE("hostapd_bss", bss_methods);
+
+static int avl_compare_macaddr(const void *k1, const void *k2, void *ptr)
+{
+ return memcmp(k1, k2, ETH_ALEN);
+}
+
+void hostapd_ubus_add_bss(struct hostapd_data *hapd)
+{
+ struct ubus_object *obj = &hapd->ubus.obj;
+ char *name;
+ int ret;
+
+#ifdef CONFIG_MESH
+ if (hapd->conf->mesh & MESH_ENABLED)
+ return;
+#endif
+
+ if (!hostapd_ubus_init())
+ return;
+
+ if (asprintf(&name, "hostapd.%s", hapd->conf->iface) < 0)
+ return;
+
+ avl_init(&hapd->ubus.banned, avl_compare_macaddr, false, NULL);
+ obj->name = name;
+ obj->type = &bss_object_type;
+ obj->methods = bss_object_type.methods;
+ obj->n_methods = bss_object_type.n_methods;
+ ret = ubus_add_object(ctx, obj);
+ hostapd_ubus_ref_inc();
+}
+
+void hostapd_ubus_free_bss(struct hostapd_data *hapd)
+{
+ struct ubus_object *obj = &hapd->ubus.obj;
+ char *name = (char *) obj->name;
+
+#ifdef CONFIG_MESH
+ if (hapd->conf->mesh & MESH_ENABLED)
+ return;
+#endif
+
+ if (!ctx)
+ return;
+
+ if (obj->id) {
+ ubus_remove_object(ctx, obj);
+ hostapd_ubus_ref_dec();
+ }
+
+ free(name);
+}
+
+static void
+hostapd_ubus_vlan_action(struct hostapd_data *hapd, struct hostapd_vlan *vlan,
+ const char *action)
+{
+ struct vlan_description *desc = &vlan->vlan_desc;
+ void *c;
+ int i;
+
+ if (!hapd->ubus.obj.has_subscribers)
+ return;
+
+ blob_buf_init(&b, 0);
+ blobmsg_add_string(&b, "ifname", vlan->ifname);
+ blobmsg_add_string(&b, "bridge", vlan->bridge);
+ blobmsg_add_u32(&b, "vlan_id", vlan->vlan_id);
+
+ if (desc->notempty) {
+ blobmsg_add_u32(&b, "untagged", desc->untagged);
+ c = blobmsg_open_array(&b, "tagged");
+ for (i = 0; i < ARRAY_SIZE(desc->tagged) && desc->tagged[i]; i++)
+ blobmsg_add_u32(&b, "", desc->tagged[i]);
+ blobmsg_close_array(&b, c);
+ }
+
+ ubus_notify(ctx, &hapd->ubus.obj, action, b.head, -1);
+}
+
+void hostapd_ubus_add_vlan(struct hostapd_data *hapd, struct hostapd_vlan *vlan)
+{
+ hostapd_ubus_vlan_action(hapd, vlan, "vlan_add");
+}
+
+void hostapd_ubus_remove_vlan(struct hostapd_data *hapd, struct hostapd_vlan *vlan)
+{
+ hostapd_ubus_vlan_action(hapd, vlan, "vlan_remove");
+}
+
+struct ubus_event_req {
+ struct ubus_notify_request nreq;
+ int resp;
+};
+
+static void
+ubus_event_cb(struct ubus_notify_request *req, int idx, int ret)
+{
+ struct ubus_event_req *ureq = container_of(req, struct ubus_event_req, nreq);
+
+ ureq->resp = ret;
+}
+
+int hostapd_ubus_handle_event(struct hostapd_data *hapd, struct hostapd_ubus_request *req)
+{
+ struct ubus_banned_client *ban;
+ const char *types[HOSTAPD_UBUS_TYPE_MAX] = {
+ [HOSTAPD_UBUS_PROBE_REQ] = "probe",
+ [HOSTAPD_UBUS_AUTH_REQ] = "auth",
+ [HOSTAPD_UBUS_ASSOC_REQ] = "assoc",
+ };
+ const char *type = "mgmt";
+ struct ubus_event_req ureq = {};
+ const u8 *addr;
+
+ if (req->mgmt_frame)
+ addr = req->mgmt_frame->sa;
+ else
+ addr = req->addr;
+
+ ban = avl_find_element(&hapd->ubus.banned, addr, ban, avl);
+ if (ban)
+ return WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
+
+ if (!hapd->ubus.obj.has_subscribers)
+ return WLAN_STATUS_SUCCESS;
+
+ if (req->type < ARRAY_SIZE(types))
+ type = types[req->type];
+
+ blob_buf_init(&b, 0);
+ blobmsg_add_macaddr(&b, "address", addr);
+ if (req->mgmt_frame)
+ blobmsg_add_macaddr(&b, "target", req->mgmt_frame->da);
+ if (req->ssi_signal)
+ blobmsg_add_u32(&b, "signal", req->ssi_signal);
+ blobmsg_add_u32(&b, "freq", hapd->iface->freq);
+
+ if (req->elems) {
+ if(req->elems->ht_capabilities)
+ {
+ struct ieee80211_ht_capabilities *ht_capabilities;
+ void *ht_cap, *ht_cap_mcs_set, *mcs_set;
+
+
+ ht_capabilities = (struct ieee80211_ht_capabilities*) req->elems->ht_capabilities;
+ ht_cap = blobmsg_open_table(&b, "ht_capabilities");
+ blobmsg_add_u16(&b, "ht_capabilities_info", ht_capabilities->ht_capabilities_info);
+ ht_cap_mcs_set = blobmsg_open_table(&b, "supported_mcs_set");
+ blobmsg_add_u16(&b, "a_mpdu_params", ht_capabilities->a_mpdu_params);
+ blobmsg_add_u16(&b, "ht_extended_capabilities", ht_capabilities->ht_extended_capabilities);
+ blobmsg_add_u32(&b, "tx_bf_capability_info", ht_capabilities->tx_bf_capability_info);
+ blobmsg_add_u16(&b, "asel_capabilities", ht_capabilities->asel_capabilities);
+ mcs_set = blobmsg_open_array(&b, "supported_mcs_set");
+ for (int i = 0; i < 16; i++) {
+ blobmsg_add_u16(&b, NULL, (u16) ht_capabilities->supported_mcs_set[i]);
+ }
+ blobmsg_close_array(&b, mcs_set);
+ blobmsg_close_table(&b, ht_cap_mcs_set);
+ blobmsg_close_table(&b, ht_cap);
+ }
+ if(req->elems->vht_capabilities)
+ {
+ struct ieee80211_vht_capabilities *vht_capabilities;
+ void *vht_cap, *vht_cap_mcs_set;
+
+ vht_capabilities = (struct ieee80211_vht_capabilities*) req->elems->vht_capabilities;
+ vht_cap = blobmsg_open_table(&b, "vht_capabilities");
+ blobmsg_add_u32(&b, "vht_capabilities_info", vht_capabilities->vht_capabilities_info);
+ vht_cap_mcs_set = blobmsg_open_table(&b, "vht_supported_mcs_set");
+ blobmsg_add_u16(&b, "rx_map", vht_capabilities->vht_supported_mcs_set.rx_map);
+ blobmsg_add_u16(&b, "rx_highest", vht_capabilities->vht_supported_mcs_set.rx_highest);
+ blobmsg_add_u16(&b, "tx_map", vht_capabilities->vht_supported_mcs_set.tx_map);
+ blobmsg_add_u16(&b, "tx_highest", vht_capabilities->vht_supported_mcs_set.tx_highest);
+ blobmsg_close_table(&b, vht_cap_mcs_set);
+ blobmsg_close_table(&b, vht_cap);
+ }
+ }
+
+ if (!hapd->ubus.notify_response) {
+ ubus_notify(ctx, &hapd->ubus.obj, type, b.head, -1);
+ return WLAN_STATUS_SUCCESS;
+ }
+
+ if (ubus_notify_async(ctx, &hapd->ubus.obj, type, b.head, &ureq.nreq))
+ return WLAN_STATUS_SUCCESS;
+
+ ureq.nreq.status_cb = ubus_event_cb;
+ ubus_complete_request(ctx, &ureq.nreq.req, 100);
+
+ if (ureq.resp)
+ return ureq.resp;
+
+ return WLAN_STATUS_SUCCESS;
+}
+
+void hostapd_ubus_notify(struct hostapd_data *hapd, const char *type, const u8 *addr)
+{
+ if (!hapd->ubus.obj.has_subscribers)
+ return;
+
+ if (!addr)
+ return;
+
+ blob_buf_init(&b, 0);
+ blobmsg_add_macaddr(&b, "address", addr);
+
+ ubus_notify(ctx, &hapd->ubus.obj, type, b.head, -1);
+}
+
+void hostapd_ubus_notify_authorized(struct hostapd_data *hapd, struct sta_info *sta,
+ const char *auth_alg)
+{
+ if (!hapd->ubus.obj.has_subscribers)
+ return;
+
+ blob_buf_init(&b, 0);
+ blobmsg_add_macaddr(&b, "address", sta->addr);
+ if (auth_alg)
+ blobmsg_add_string(&b, "auth-alg", auth_alg);
+
+ ubus_notify(ctx, &hapd->ubus.obj, "sta-authorized", b.head, -1);
+}
+
+void hostapd_ubus_notify_beacon_report(
+ struct hostapd_data *hapd, const u8 *addr, u8 token, u8 rep_mode,
+ struct rrm_measurement_beacon_report *rep, size_t len)
+{
+ if (!hapd->ubus.obj.has_subscribers)
+ return;
+
+ if (!addr || !rep)
+ return;
+
+ blob_buf_init(&b, 0);
+ blobmsg_add_macaddr(&b, "address", addr);
+ blobmsg_add_u16(&b, "op-class", rep->op_class);
+ blobmsg_add_u16(&b, "channel", rep->channel);
+ blobmsg_add_u64(&b, "start-time", rep->start_time);
+ blobmsg_add_u16(&b, "duration", rep->duration);
+ blobmsg_add_u16(&b, "report-info", rep->report_info);
+ blobmsg_add_u16(&b, "rcpi", rep->rcpi);
+ blobmsg_add_u16(&b, "rsni", rep->rsni);
+ blobmsg_add_macaddr(&b, "bssid", rep->bssid);
+ blobmsg_add_u16(&b, "antenna-id", rep->antenna_id);
+ blobmsg_add_u16(&b, "parent-tsf", rep->parent_tsf);
+ blobmsg_add_u16(&b, "rep-mode", rep_mode);
+
+ ubus_notify(ctx, &hapd->ubus.obj, "beacon-report", b.head, -1);
+}
+
+void hostapd_ubus_notify_radar_detected(struct hostapd_iface *iface, int frequency,
+ int chan_width, int cf1, int cf2)
+{
+ struct hostapd_data *hapd;
+ int i;
+
+ blob_buf_init(&b, 0);
+ blobmsg_add_u16(&b, "frequency", frequency);
+ blobmsg_add_u16(&b, "width", chan_width);
+ blobmsg_add_u16(&b, "center1", cf1);
+ blobmsg_add_u16(&b, "center2", cf2);
+
+ for (i = 0; i < iface->num_bss; i++) {
+ hapd = iface->bss[i];
+ ubus_notify(ctx, &hapd->ubus.obj, "radar-detected", b.head, -1);
+ }
+}
+
+#ifdef CONFIG_WNM_AP
+static void hostapd_ubus_notify_bss_transition_add_candidate_list(
+ const u8 *candidate_list, u16 candidate_list_len)
+{
+ char *cl_str;
+ int i;
+
+ if (candidate_list_len == 0)
+ return;
+
+ cl_str = blobmsg_alloc_string_buffer(&b, "candidate-list", candidate_list_len * 2 + 1);
+ for (i = 0; i < candidate_list_len; i++)
+ snprintf(&cl_str[i*2], 3, "%02X", candidate_list[i]);
+ blobmsg_add_string_buffer(&b);
+
+}
+#endif
+
+void hostapd_ubus_notify_bss_transition_response(
+ struct hostapd_data *hapd, const u8 *addr, u8 dialog_token, u8 status_code,
+ u8 bss_termination_delay, const u8 *target_bssid,
+ const u8 *candidate_list, u16 candidate_list_len)
+{
+#ifdef CONFIG_WNM_AP
+ u16 i;
+
+ if (!hapd->ubus.obj.has_subscribers)
+ return;
+
+ if (!addr)
+ return;
+
+ blob_buf_init(&b, 0);
+ blobmsg_add_macaddr(&b, "address", addr);
+ blobmsg_add_u8(&b, "dialog-token", dialog_token);
+ blobmsg_add_u8(&b, "status-code", status_code);
+ blobmsg_add_u8(&b, "bss-termination-delay", bss_termination_delay);
+ if (target_bssid)
+ blobmsg_add_macaddr(&b, "target-bssid", target_bssid);
+
+ hostapd_ubus_notify_bss_transition_add_candidate_list(candidate_list, candidate_list_len);
+
+ ubus_notify(ctx, &hapd->ubus.obj, "bss-transition-response", b.head, -1);
+#endif
+}
+
+int hostapd_ubus_notify_bss_transition_query(
+ struct hostapd_data *hapd, const u8 *addr, u8 dialog_token, u8 reason,
+ const u8 *candidate_list, u16 candidate_list_len)
+{
+#ifdef CONFIG_WNM_AP
+ struct ubus_event_req ureq = {};
+ char *cl_str;
+ u16 i;
+
+ if (!hapd->ubus.obj.has_subscribers)
+ return 0;
+
+ if (!addr)
+ return 0;
+
+ blob_buf_init(&b, 0);
+ blobmsg_add_macaddr(&b, "address", addr);
+ blobmsg_add_u8(&b, "dialog-token", dialog_token);
+ blobmsg_add_u8(&b, "reason", reason);
+ hostapd_ubus_notify_bss_transition_add_candidate_list(candidate_list, candidate_list_len);
+
+ if (!hapd->ubus.notify_response) {
+ ubus_notify(ctx, &hapd->ubus.obj, "bss-transition-query", b.head, -1);
+ return 0;
+ }
+
+ if (ubus_notify_async(ctx, &hapd->ubus.obj, "bss-transition-query", b.head, &ureq.nreq))
+ return 0;
+
+ ureq.nreq.status_cb = ubus_event_cb;
+ ubus_complete_request(ctx, &ureq.nreq.req, 100);
+
+ return ureq.resp;
+#endif
+}
diff --git a/recipes-wifi/hostapd/files/src-2.10.3/src/ap/ubus.h b/recipes-wifi/hostapd/files/src-2.10.3/src/ap/ubus.h
new file mode 100644
index 0000000..b0f7c44
--- /dev/null
+++ b/recipes-wifi/hostapd/files/src-2.10.3/src/ap/ubus.h
@@ -0,0 +1,154 @@
+/*
+ * hostapd / ubus support
+ * Copyright (c) 2013, Felix Fietkau <nbd@nbd.name>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+#ifndef __HOSTAPD_UBUS_H
+#define __HOSTAPD_UBUS_H
+
+enum hostapd_ubus_event_type {
+ HOSTAPD_UBUS_PROBE_REQ,
+ HOSTAPD_UBUS_AUTH_REQ,
+ HOSTAPD_UBUS_ASSOC_REQ,
+ HOSTAPD_UBUS_TYPE_MAX
+};
+
+struct hostapd_ubus_request {
+ enum hostapd_ubus_event_type type;
+ const struct ieee80211_mgmt *mgmt_frame;
+ const struct ieee802_11_elems *elems;
+ int ssi_signal; /* dBm */
+ const u8 *addr;
+};
+
+struct hostapd_iface;
+struct hostapd_data;
+struct hapd_interfaces;
+struct rrm_measurement_beacon_report;
+
+#ifdef UBUS_SUPPORT
+
+#include <libubox/avl.h>
+#include <libubus.h>
+
+struct hostapd_ubus_bss {
+ struct ubus_object obj;
+ struct avl_tree banned;
+ int notify_response;
+};
+
+void hostapd_ubus_add_iface(struct hostapd_iface *iface);
+void hostapd_ubus_free_iface(struct hostapd_iface *iface);
+void hostapd_ubus_add_bss(struct hostapd_data *hapd);
+void hostapd_ubus_free_bss(struct hostapd_data *hapd);
+void hostapd_ubus_add_vlan(struct hostapd_data *hapd, struct hostapd_vlan *vlan);
+void hostapd_ubus_remove_vlan(struct hostapd_data *hapd, struct hostapd_vlan *vlan);
+
+int hostapd_ubus_handle_event(struct hostapd_data *hapd, struct hostapd_ubus_request *req);
+void hostapd_ubus_handle_link_measurement(struct hostapd_data *hapd, const u8 *data, size_t len);
+void hostapd_ubus_notify(struct hostapd_data *hapd, const char *type, const u8 *mac);
+void hostapd_ubus_notify_beacon_report(struct hostapd_data *hapd,
+ const u8 *addr, u8 token, u8 rep_mode,
+ struct rrm_measurement_beacon_report *rep,
+ size_t len);
+void hostapd_ubus_notify_radar_detected(struct hostapd_iface *iface, int frequency,
+ int chan_width, int cf1, int cf2);
+
+void hostapd_ubus_notify_bss_transition_response(
+ struct hostapd_data *hapd, const u8 *addr, u8 dialog_token, u8 status_code,
+ u8 bss_termination_delay, const u8 *target_bssid,
+ const u8 *candidate_list, u16 candidate_list_len);
+void hostapd_ubus_add(struct hapd_interfaces *interfaces);
+void hostapd_ubus_free(struct hapd_interfaces *interfaces);
+int hostapd_ubus_notify_bss_transition_query(
+ struct hostapd_data *hapd, const u8 *addr, u8 dialog_token, u8 reason,
+ const u8 *candidate_list, u16 candidate_list_len);
+void hostapd_ubus_notify_authorized(struct hostapd_data *hapd, struct sta_info *sta,
+ const char *auth_alg);
+
+#else
+
+struct hostapd_ubus_bss {};
+
+static inline void hostapd_ubus_add_iface(struct hostapd_iface *iface)
+{
+}
+
+static inline void hostapd_ubus_free_iface(struct hostapd_iface *iface)
+{
+}
+
+static inline void hostapd_ubus_add_bss(struct hostapd_data *hapd)
+{
+}
+
+static inline void hostapd_ubus_free_bss(struct hostapd_data *hapd)
+{
+}
+
+static inline void hostapd_ubus_add_vlan(struct hostapd_data *hapd, struct hostapd_vlan *vlan)
+{
+}
+
+static inline void hostapd_ubus_remove_vlan(struct hostapd_data *hapd, struct hostapd_vlan *vlan)
+{
+}
+
+static inline int hostapd_ubus_handle_event(struct hostapd_data *hapd, struct hostapd_ubus_request *req)
+{
+ return 0;
+}
+
+static inline void hostapd_ubus_handle_link_measurement(struct hostapd_data *hapd, const u8 *data, size_t len)
+{
+}
+
+static inline void hostapd_ubus_notify(struct hostapd_data *hapd, const char *type, const u8 *mac)
+{
+}
+
+static inline void hostapd_ubus_notify_beacon_report(struct hostapd_data *hapd,
+ const u8 *addr, u8 token,
+ u8 rep_mode,
+ struct rrm_measurement_beacon_report *rep,
+ size_t len)
+{
+}
+static inline void hostapd_ubus_notify_radar_detected(struct hostapd_iface *iface, int frequency,
+ int chan_width, int cf1, int cf2)
+{
+}
+
+static inline void hostapd_ubus_notify_bss_transition_response(
+ struct hostapd_data *hapd, const u8 *addr, u8 dialog_token, u8 status_code,
+ u8 bss_termination_delay, const u8 *target_bssid,
+ const u8 *candidate_list, u16 candidate_list_len)
+{
+}
+
+static inline void hostapd_ubus_add(struct hapd_interfaces *interfaces)
+{
+}
+
+static inline void hostapd_ubus_free(struct hapd_interfaces *interfaces)
+{
+}
+
+static inline int hostapd_ubus_notify_bss_transition_query(
+ struct hostapd_data *hapd, const u8 *addr, u8 dialog_token, u8 reason,
+ const u8 *candidate_list, u16 candidate_list_len)
+{
+ return 0;
+}
+
+static inline void
+hostapd_ubus_notify_authorized(struct hostapd_data *hapd, struct sta_info *sta,
+ const char *auth_alg)
+{
+}
+
+#endif
+
+#endif
diff --git a/recipes-wifi/hostapd/files/src-2.10.3/src/ap/ucode.c b/recipes-wifi/hostapd/files/src-2.10.3/src/ap/ucode.c
new file mode 100644
index 0000000..137cb81
--- /dev/null
+++ b/recipes-wifi/hostapd/files/src-2.10.3/src/ap/ucode.c
@@ -0,0 +1,394 @@
+#include <sys/un.h>
+
+#include "utils/includes.h"
+#include "utils/common.h"
+#include "utils/ucode.h"
+#include "hostapd.h"
+#include "ap_drv_ops.h"
+#include <libubox/uloop.h>
+
+static uc_resource_type_t *global_type, *bss_type, *iface_type;
+static struct hapd_interfaces *interfaces;
+static uc_value_t *global, *bss_registry, *iface_registry;
+static uc_vm_t *vm;
+
+static uc_value_t *
+hostapd_ucode_bss_get_uval(struct hostapd_data *hapd)
+{
+ uc_value_t *val;
+
+ if (hapd->ucode.idx)
+ return wpa_ucode_registry_get(bss_registry, hapd->ucode.idx);
+
+ val = uc_resource_new(bss_type, hapd);
+ wpa_ucode_registry_add(bss_registry, val, &hapd->ucode.idx);
+
+ return val;
+}
+
+static uc_value_t *
+hostapd_ucode_iface_get_uval(struct hostapd_iface *hapd)
+{
+ uc_value_t *val;
+
+ if (hapd->ucode.idx)
+ return wpa_ucode_registry_get(iface_registry, hapd->ucode.idx);
+
+ val = uc_resource_new(iface_type, hapd);
+ wpa_ucode_registry_add(iface_registry, val, &hapd->ucode.idx);
+
+ return val;
+}
+
+static void
+hostapd_ucode_update_bss_list(struct hostapd_iface *iface)
+{
+ uc_value_t *ifval, *list;
+ int i;
+
+ list = ucv_array_new(vm);
+ for (i = 0; i < iface->num_bss; i++) {
+ struct hostapd_data *hapd = iface->bss[i];
+ uc_value_t *val = hostapd_ucode_bss_get_uval(hapd);
+ uc_value_t *proto = ucv_prototype_get(val);
+
+ ucv_object_add(proto, "name", ucv_get(ucv_string_new(hapd->conf->iface)));
+ ucv_object_add(proto, "index", ucv_int64_new(i));
+ ucv_array_set(list, i, ucv_get(val));
+ }
+
+ ifval = hostapd_ucode_iface_get_uval(iface);
+ ucv_object_add(ucv_prototype_get(ifval), "bss", ucv_get(list));
+}
+
+static void
+hostapd_ucode_update_interfaces(void)
+{
+ uc_value_t *ifs = ucv_object_new(vm);
+ int i;
+
+ for (i = 0; i < interfaces->count; i++) {
+ struct hostapd_iface *iface = interfaces->iface[i];
+
+ ucv_object_add(ifs, iface->phy, ucv_get(hostapd_ucode_iface_get_uval(iface)));
+ hostapd_ucode_update_bss_list(iface);
+ }
+
+ ucv_object_add(ucv_prototype_get(global), "interfaces", ucv_get(ifs));
+ ucv_gc(vm);
+}
+
+static uc_value_t *
+uc_hostapd_add_iface(uc_vm_t *vm, size_t nargs)
+{
+ uc_value_t *iface = uc_fn_arg(0);
+ int ret;
+
+ if (ucv_type(iface) != UC_STRING)
+ return ucv_int64_new(-1);
+
+ ret = hostapd_add_iface(interfaces, ucv_string_get(iface));
+ hostapd_ucode_update_interfaces();
+
+ return ucv_int64_new(ret);
+}
+
+static uc_value_t *
+uc_hostapd_remove_iface(uc_vm_t *vm, size_t nargs)
+{
+ uc_value_t *iface = uc_fn_arg(0);
+
+ if (ucv_type(iface) != UC_STRING)
+ return NULL;
+
+ hostapd_remove_iface(interfaces, ucv_string_get(iface));
+ hostapd_ucode_update_interfaces();
+
+ return NULL;
+}
+
+static uc_value_t *
+uc_hostapd_bss_set_config(uc_vm_t *vm, size_t nargs)
+{
+ struct hostapd_data *hapd = uc_fn_thisval("hostapd.bss");
+ struct hostapd_bss_config *old_bss;
+ struct hostapd_iface *iface;
+ struct hostapd_config *conf;
+ uc_value_t *file = uc_fn_arg(0);
+ uc_value_t *index = uc_fn_arg(1);
+ unsigned int i, idx = 0;
+ int ret = -1;
+
+ if (!hapd || ucv_type(file) != UC_STRING)
+ goto out;
+
+ if (ucv_type(index) == UC_INTEGER)
+ idx = ucv_int64_get(index);
+
+ iface = hapd->iface;
+ conf = interfaces->config_read_cb(ucv_string_get(file));
+ if (!conf || idx > conf->num_bss || !conf->bss[idx])
+ goto out;
+
+ hostapd_bss_deinit_no_free(hapd);
+ hostapd_drv_stop_ap(hapd);
+ hostapd_free_hapd_data(hapd);
+
+ old_bss = hapd->conf;
+ for (i = 0; i < iface->conf->num_bss; i++)
+ if (iface->conf->bss[i] == hapd->conf)
+ iface->conf->bss[i] = conf->bss[idx];
+ hapd->conf = conf->bss[idx];
+ conf->bss[idx] = old_bss;
+ hostapd_config_free(conf);
+
+ hostapd_setup_bss(hapd, hapd == iface->bss[0], !iface->conf->mbssid);
+
+ ret = 0;
+
+out:
+ return ucv_int64_new(ret);
+}
+
+static void
+hostapd_remove_iface_bss_conf(struct hostapd_config *iconf,
+ struct hostapd_bss_config *conf)
+{
+ int i;
+
+ for (i = 0; i < iconf->num_bss; i++)
+ if (iconf->bss[i] == conf)
+ break;
+
+ if (i == iconf->num_bss)
+ return;
+
+ for (i++; i < iconf->num_bss; i++)
+ iconf->bss[i - 1] = iconf->bss[i];
+ iconf->num_bss--;
+}
+
+
+static uc_value_t *
+uc_hostapd_bss_delete(uc_vm_t *vm, size_t nargs)
+{
+ struct hostapd_data *hapd = uc_fn_thisval("hostapd.bss");
+ struct hostapd_iface *iface;
+ int i, idx;
+
+ if (!hapd || hapd == hapd->iface->bss[0])
+ return NULL;
+
+ iface = hapd->iface;
+ for (idx = 0; idx < iface->num_bss; idx++)
+ if (iface->bss[idx] == hapd)
+ break;
+
+ if (idx == iface->num_bss)
+ return NULL;
+
+ for (i = idx + 1; i < iface->num_bss; i++)
+ iface->bss[i - 1] = iface->bss[i];
+ iface->num_bss--;
+
+ hostapd_drv_stop_ap(hapd);
+ hostapd_bss_deinit(hapd);
+ hostapd_remove_iface_bss_conf(iface->conf, hapd->conf);
+ hostapd_config_free_bss(hapd->conf);
+ os_free(hapd);
+
+ hostapd_ucode_update_bss_list(iface);
+ ucv_gc(vm);
+
+ return NULL;
+}
+
+static uc_value_t *
+uc_hostapd_iface_add_bss(uc_vm_t *vm, size_t nargs)
+{
+ struct hostapd_iface *iface = uc_fn_thisval("hostapd.iface");
+ struct hostapd_bss_config *bss;
+ struct hostapd_config *conf;
+ struct hostapd_data *hapd;
+ uc_value_t *file = uc_fn_arg(0);
+ uc_value_t *index = uc_fn_arg(1);
+ unsigned int idx = 0;
+ uc_value_t *ret = NULL;
+
+ if (!iface || ucv_type(file) != UC_STRING)
+ goto out;
+
+ if (ucv_type(index) == UC_INTEGER)
+ idx = ucv_int64_get(index);
+
+ conf = interfaces->config_read_cb(ucv_string_get(file));
+ if (!conf || idx > conf->num_bss || !conf->bss[idx])
+ goto out;
+
+ bss = conf->bss[idx];
+ hapd = hostapd_alloc_bss_data(iface, iface->conf, bss);
+ if (!hapd)
+ goto out;
+
+ hapd->driver = iface->bss[0]->driver;
+ hapd->drv_priv = iface->bss[0]->drv_priv;
+ if (interfaces->ctrl_iface_init &&
+ interfaces->ctrl_iface_init(hapd) < 0)
+ goto free_hapd;
+
+ if (iface->state == HAPD_IFACE_ENABLED &&
+ hostapd_setup_bss(hapd, -1, true))
+ goto deinit_ctrl;
+
+ iface->bss = os_realloc_array(iface->bss, iface->num_bss + 1,
+ sizeof(*iface->bss));
+ iface->bss[iface->num_bss++] = hapd;
+
+ iface->conf->bss = os_realloc_array(iface->conf->bss,
+ iface->conf->num_bss + 1,
+ sizeof(*iface->conf->bss));
+ iface->conf->bss[iface->conf->num_bss] = bss;
+ conf->bss[idx] = NULL;
+ ret = hostapd_ucode_bss_get_uval(hapd);
+ hostapd_ucode_update_bss_list(iface);
+ goto out;
+
+deinit_ctrl:
+ if (interfaces->ctrl_iface_deinit)
+ interfaces->ctrl_iface_deinit(hapd);
+free_hapd:
+ hostapd_free_hapd_data(hapd);
+ os_free(hapd);
+out:
+ hostapd_config_free(conf);
+ return ret;
+}
+
+static uc_value_t *
+uc_hostapd_bss_ctrl(uc_vm_t *vm, size_t nargs)
+{
+ struct hostapd_data *hapd = uc_fn_thisval("hostapd.bss");
+ uc_value_t *arg = uc_fn_arg(0);
+ struct sockaddr_storage from = {};
+ static char reply[4096];
+ int reply_len;
+
+ if (!hapd || !interfaces->ctrl_iface_recv ||
+ ucv_type(arg) != UC_STRING)
+ return NULL;
+
+ reply_len = interfaces->ctrl_iface_recv(hapd, ucv_string_get(arg),
+ reply, sizeof(reply),
+ &from, sizeof(from));
+ if (reply_len < 0)
+ return NULL;
+
+ if (reply_len && reply[reply_len - 1] == '\n')
+ reply_len--;
+
+ return ucv_string_new_length(reply, reply_len);
+}
+
+int hostapd_ucode_init(struct hapd_interfaces *ifaces)
+{
+ static const uc_function_list_t global_fns[] = {
+ { "printf", uc_wpa_printf },
+ { "getpid", uc_wpa_getpid },
+ { "sha1", uc_wpa_sha1 },
+ { "add_iface", uc_hostapd_add_iface },
+ { "remove_iface", uc_hostapd_remove_iface },
+ };
+ static const uc_function_list_t bss_fns[] = {
+ { "ctrl", uc_hostapd_bss_ctrl },
+ { "set_config", uc_hostapd_bss_set_config },
+ { "delete", uc_hostapd_bss_delete },
+ };
+ static const uc_function_list_t iface_fns[] = {
+ { "add_bss", uc_hostapd_iface_add_bss }
+ };
+ uc_value_t *data, *proto;
+
+ interfaces = ifaces;
+ vm = wpa_ucode_create_vm();
+
+ global_type = uc_type_declare(vm, "hostapd.global", global_fns, NULL);
+ bss_type = uc_type_declare(vm, "hostapd.bss", bss_fns, NULL);
+ iface_type = uc_type_declare(vm, "hostapd.iface", iface_fns, NULL);
+
+ bss_registry = ucv_array_new(vm);
+ uc_vm_registry_set(vm, "hostap.bss_registry", bss_registry);
+
+ iface_registry = ucv_array_new(vm);
+ uc_vm_registry_set(vm, "hostap.iface_registry", iface_registry);
+
+ global = wpa_ucode_global_init("hostapd", global_type);
+
+ if (wpa_ucode_run(HOSTAPD_UC_PATH "hostapd.uc"))
+ goto free_vm;
+ ucv_gc(vm);
+
+ return 0;
+
+free_vm:
+ wpa_ucode_free_vm();
+ return -1;
+}
+
+void hostapd_ucode_free(void)
+{
+ if (wpa_ucode_call_prepare("shutdown") == 0)
+ ucv_put(wpa_ucode_call(0));
+ wpa_ucode_free_vm();
+}
+
+void hostapd_ucode_free_iface(struct hostapd_iface *iface)
+{
+ wpa_ucode_registry_remove(iface_registry, iface->ucode.idx);
+}
+
+void hostapd_ucode_add_bss(struct hostapd_data *hapd)
+{
+ uc_value_t *val;
+
+ if (wpa_ucode_call_prepare("bss_add"))
+ return;
+
+ val = hostapd_ucode_bss_get_uval(hapd);
+ uc_value_push(ucv_get(ucv_string_new(hapd->conf->iface)));
+ uc_value_push(ucv_get(val));
+ ucv_put(wpa_ucode_call(2));
+ ucv_gc(vm);
+}
+
+void hostapd_ucode_reload_bss(struct hostapd_data *hapd, int reconf)
+{
+ uc_value_t *val;
+
+ if (wpa_ucode_call_prepare("bss_reload"))
+ return;
+
+ val = hostapd_ucode_bss_get_uval(hapd);
+ uc_value_push(ucv_get(ucv_string_new(hapd->conf->iface)));
+ uc_value_push(ucv_get(val));
+ uc_value_push(ucv_int64_new(reconf));
+ ucv_put(wpa_ucode_call(3));
+ ucv_gc(vm);
+}
+
+void hostapd_ucode_free_bss(struct hostapd_data *hapd)
+{
+ uc_value_t *val;
+
+ val = wpa_ucode_registry_remove(bss_registry, hapd->ucode.idx);
+ if (!val)
+ return;
+
+ hapd->ucode.idx = 0;
+ if (wpa_ucode_call_prepare("bss_remove"))
+ return;
+
+ uc_value_push(ucv_string_new(hapd->conf->iface));
+ uc_value_push(ucv_get(val));
+ ucv_put(wpa_ucode_call(2));
+ ucv_gc(vm);
+}
diff --git a/recipes-wifi/hostapd/files/src-2.10.3/src/ap/ucode.h b/recipes-wifi/hostapd/files/src-2.10.3/src/ap/ucode.h
new file mode 100644
index 0000000..dbc49e6
--- /dev/null
+++ b/recipes-wifi/hostapd/files/src-2.10.3/src/ap/ucode.h
@@ -0,0 +1,54 @@
+#ifndef __HOSTAPD_AP_UCODE_H
+#define __HOSTAPD_AP_UCODE_H
+
+#include "utils/ucode.h"
+
+struct hostapd_data;
+
+struct hostapd_ucode_bss {
+#ifdef UCODE_SUPPORT
+ int idx;
+#endif
+};
+
+struct hostapd_ucode_iface {
+#ifdef UCODE_SUPPORT
+ int idx;
+#endif
+};
+
+#ifdef UCODE_SUPPORT
+
+int hostapd_ucode_init(struct hapd_interfaces *ifaces);
+
+void hostapd_ucode_free(void);
+void hostapd_ucode_free_iface(struct hostapd_iface *iface);
+void hostapd_ucode_add_bss(struct hostapd_data *hapd);
+void hostapd_ucode_free_bss(struct hostapd_data *hapd);
+void hostapd_ucode_reload_bss(struct hostapd_data *hapd, int reconf);
+
+#else
+
+static inline int hostapd_ucode_init(struct hapd_interfaces *ifaces)
+{
+ return -EINVAL;
+}
+static inline void hostapd_ucode_free(void)
+{
+}
+static inline void hostapd_ucode_free_iface(struct hostapd_iface *iface)
+{
+}
+static inline void hostapd_ucode_reload_bss(struct hostapd_data *hapd, int reconf)
+{
+}
+static inline void hostapd_ucode_add_bss(struct hostapd_data *hapd)
+{
+}
+static inline void hostapd_ucode_free_bss(struct hostapd_data *hapd)
+{
+}
+
+#endif
+
+#endif
diff --git a/recipes-wifi/hostapd/files/src-2.10.3/src/utils/build_features.h b/recipes-wifi/hostapd/files/src-2.10.3/src/utils/build_features.h
new file mode 100644
index 0000000..553769e
--- /dev/null
+++ b/recipes-wifi/hostapd/files/src-2.10.3/src/utils/build_features.h
@@ -0,0 +1,65 @@
+#ifndef BUILD_FEATURES_H
+#define BUILD_FEATURES_H
+
+static inline int has_feature(const char *feat)
+{
+#if defined(IEEE8021X_EAPOL) || (defined(HOSTAPD) && !defined(CONFIG_NO_RADIUS))
+ if (!strcmp(feat, "eap"))
+ return 1;
+#endif
+#ifdef CONFIG_IEEE80211AC
+ if (!strcmp(feat, "11ac"))
+ return 1;
+#endif
+#ifdef CONFIG_IEEE80211AX
+ if (!strcmp(feat, "11ax"))
+ return 1;
+#endif
+#ifdef CONFIG_IEEE80211R
+ if (!strcmp(feat, "11r"))
+ return 1;
+#endif
+#ifdef CONFIG_ACS
+ if (!strcmp(feat, "acs"))
+ return 1;
+#endif
+#ifdef CONFIG_SAE
+ if (!strcmp(feat, "sae"))
+ return 1;
+#endif
+#ifdef CONFIG_OWE
+ if (!strcmp(feat, "owe"))
+ return 1;
+#endif
+#ifdef CONFIG_SUITEB192
+ if (!strcmp(feat, "suiteb192"))
+ return 1;
+#endif
+#ifdef CONFIG_WEP
+ if (!strcmp(feat, "wep"))
+ return 1;
+#endif
+#ifdef CONFIG_HS20
+ if (!strcmp(feat, "hs20"))
+ return 1;
+#endif
+#ifdef CONFIG_WPS
+ if (!strcmp(feat, "wps"))
+ return 1;
+#endif
+#ifdef CONFIG_FILS
+ if (!strcmp(feat, "fils"))
+ return 1;
+#endif
+#ifdef CONFIG_OCV
+ if (!strcmp(feat, "ocv"))
+ return 1;
+#endif
+#ifdef CONFIG_MESH
+ if (!strcmp(feat, "mesh"))
+ return 1;
+#endif
+ return 0;
+}
+
+#endif /* BUILD_FEATURES_H */
diff --git a/recipes-wifi/hostapd/files/src-2.10.3/src/utils/ucode.c b/recipes-wifi/hostapd/files/src-2.10.3/src/utils/ucode.c
new file mode 100644
index 0000000..a92913a
--- /dev/null
+++ b/recipes-wifi/hostapd/files/src-2.10.3/src/utils/ucode.c
@@ -0,0 +1,251 @@
+#include <unistd.h>
+#include "ucode.h"
+#include "utils/eloop.h"
+#include "crypto/crypto.h"
+#include "crypto/sha1.h"
+#include <libubox/uloop.h>
+#include <ucode/compiler.h>
+
+static uc_value_t *registry;
+static uc_vm_t vm;
+static struct uloop_timeout gc_timer;
+
+static void uc_gc_timer(struct uloop_timeout *timeout)
+{
+ ucv_gc(&vm);
+}
+
+uc_value_t *uc_wpa_printf(uc_vm_t *vm, size_t nargs)
+{
+ uc_value_t *level = uc_fn_arg(0);
+ uc_value_t *ret, **args;
+ uc_cfn_ptr_t _sprintf;
+ int l = MSG_INFO;
+ int i, start = 0;
+
+ _sprintf = uc_stdlib_function("sprintf");
+ if (!sprintf)
+ return NULL;
+
+ if (ucv_type(level) == UC_INTEGER) {
+ l = ucv_int64_get(level);
+ start++;
+ }
+
+ if (nargs <= start)
+ return NULL;
+
+ ret = _sprintf(vm, nargs - start);
+ if (ucv_type(ret) != UC_STRING)
+ return NULL;
+
+ wpa_printf(l, "%s", ucv_string_get(ret));
+ ucv_put(ret);
+
+ return NULL;
+}
+
+uc_value_t *uc_wpa_getpid(uc_vm_t *vm, size_t nargs)
+{
+ return ucv_int64_new(getpid());
+}
+
+uc_value_t *uc_wpa_sha1(uc_vm_t *vm, size_t nargs)
+{
+ u8 hash[SHA1_MAC_LEN];
+ char hash_hex[2 * ARRAY_SIZE(hash) + 1];
+ uc_value_t *val;
+ size_t *lens;
+ const u8 **args;
+ int i;
+
+ if (!nargs)
+ return NULL;
+
+ args = alloca(nargs * sizeof(*args));
+ lens = alloca(nargs * sizeof(*lens));
+ for (i = 0; i < nargs; i++) {
+ val = uc_fn_arg(i);
+ if (ucv_type(val) != UC_STRING)
+ return NULL;
+
+ args[i] = ucv_string_get(val);
+ lens[i] = ucv_string_length(val);
+ }
+
+ if (sha1_vector(nargs, args, lens, hash))
+ return NULL;
+
+ for (i = 0; i < ARRAY_SIZE(hash); i++)
+ sprintf(hash_hex + 2 * i, "%02x", hash[i]);
+
+ return ucv_string_new_length(hash_hex, 2 * ARRAY_SIZE(hash));
+}
+
+uc_vm_t *wpa_ucode_create_vm(void)
+{
+ static uc_parse_config_t config = {
+ .strict_declarations = true,
+ .lstrip_blocks = true,
+ .trim_blocks = true,
+ .raw_mode = true
+ };
+
+ uc_search_path_init(&config.module_search_path);
+ uc_search_path_add(&config.module_search_path, HOSTAPD_UC_PATH "*.so");
+ uc_search_path_add(&config.module_search_path, HOSTAPD_UC_PATH "*.uc");
+
+ uc_vm_init(&vm, &config);
+
+ uc_stdlib_load(uc_vm_scope_get(&vm));
+ eloop_add_uloop();
+ gc_timer.cb = uc_gc_timer;
+
+ return &vm;
+}
+
+int wpa_ucode_run(const char *script)
+{
+ uc_source_t *source;
+ uc_program_t *prog;
+ uc_value_t *ops;
+ char *err;
+ int ret;
+
+ source = uc_source_new_file(script);
+ if (!source)
+ return -1;
+
+ prog = uc_compile(vm.config, source, &err);
+ uc_source_put(source);
+ if (!prog) {
+ wpa_printf(MSG_ERROR, "Error loading ucode: %s\n", err);
+ return -1;
+ }
+
+ ret = uc_vm_execute(&vm, prog, &ops);
+ uc_program_put(prog);
+ if (ret || !ops)
+ return -1;
+
+ registry = ucv_array_new(&vm);
+ uc_vm_registry_set(&vm, "hostap.registry", registry);
+ ucv_array_set(registry, 0, ucv_get(ops));
+
+ return 0;
+}
+
+int wpa_ucode_call_prepare(const char *fname)
+{
+ uc_value_t *obj, *func;
+
+ if (!registry)
+ return -1;
+
+ obj = ucv_array_get(registry, 0);
+ if (!obj)
+ return -1;
+
+ func = ucv_object_get(obj, fname, NULL);
+ if (!ucv_is_callable(func))
+ return -1;
+
+ uc_vm_stack_push(&vm, ucv_get(obj));
+ uc_vm_stack_push(&vm, ucv_get(func));
+
+ return 0;
+}
+
+uc_value_t *wpa_ucode_global_init(const char *name, uc_resource_type_t *global_type)
+{
+ uc_value_t *global = uc_resource_new(global_type, NULL);
+ uc_value_t *proto;
+
+ uc_vm_registry_set(&vm, "hostap.global", global);
+ proto = ucv_prototype_get(global);
+ ucv_object_add(proto, "data", ucv_get(ucv_object_new(&vm)));
+
+#define ADD_CONST(x) ucv_object_add(proto, #x, ucv_int64_new(x))
+ ADD_CONST(MSG_EXCESSIVE);
+ ADD_CONST(MSG_MSGDUMP);
+ ADD_CONST(MSG_DEBUG);
+ ADD_CONST(MSG_INFO);
+ ADD_CONST(MSG_WARNING);
+ ADD_CONST(MSG_ERROR);
+#undef ADD_CONST
+
+ ucv_object_add(uc_vm_scope_get(&vm), name, ucv_get(global));
+
+ return global;
+}
+
+static uc_value_t *wpa_ucode_prototype_clone(uc_value_t *uval)
+{
+ uc_value_t *proto, *proto_new;
+
+ proto = ucv_prototype_get(uval);
+ proto_new = ucv_object_new(&vm);
+
+ ucv_object_foreach(proto, key, val)
+ ucv_object_add(proto_new, key, ucv_get(val));
+ ucv_prototype_set(uval, ucv_get(proto));
+
+ return proto;
+}
+
+void wpa_ucode_registry_add(uc_value_t *reg, uc_value_t *val, int *idx)
+{
+ uc_value_t *data;
+ int i = 0;
+
+ while (ucv_array_get(reg, i))
+ i++;
+
+ ucv_array_set(reg, i, ucv_get(val));
+
+ data = ucv_object_new(&vm);
+ ucv_object_add(wpa_ucode_prototype_clone(val), "data", ucv_get(data));
+
+ *idx = i + 1;
+}
+
+uc_value_t *wpa_ucode_registry_get(uc_value_t *reg, int idx)
+{
+ if (!idx)
+ return NULL;
+
+ return ucv_array_get(reg, idx - 1);
+}
+
+uc_value_t *wpa_ucode_registry_remove(uc_value_t *reg, int idx)
+{
+ uc_value_t *val = wpa_ucode_registry_get(reg, idx);
+
+ if (val)
+ ucv_array_set(reg, idx - 1, NULL);
+
+ return val;
+}
+
+
+uc_value_t *wpa_ucode_call(size_t nargs)
+{
+ if (uc_vm_call(&vm, true, nargs) != EXCEPTION_NONE)
+ return NULL;
+
+ if (!gc_timer.pending)
+ uloop_timeout_set(&gc_timer, 10);
+
+ return uc_vm_stack_pop(&vm);
+}
+
+void wpa_ucode_free_vm(void)
+{
+ if (!vm.config)
+ return;
+
+ uc_search_path_free(&vm.config->module_search_path);
+ uc_vm_free(&vm);
+ registry = NULL;
+ vm = (uc_vm_t){};
+}
diff --git a/recipes-wifi/hostapd/files/src-2.10.3/src/utils/ucode.h b/recipes-wifi/hostapd/files/src-2.10.3/src/utils/ucode.h
new file mode 100644
index 0000000..4caf8ad
--- /dev/null
+++ b/recipes-wifi/hostapd/files/src-2.10.3/src/utils/ucode.h
@@ -0,0 +1,28 @@
+#ifndef __HOSTAPD_UTILS_UCODE_H
+#define __HOSTAPD_UTILS_UCODE_H
+
+#include "utils/includes.h"
+#include "utils/common.h"
+#include <ucode/lib.h>
+#include <ucode/vm.h>
+
+#define HOSTAPD_UC_PATH "/usr/share/hostap/"
+
+extern uc_value_t *uc_registry;
+uc_vm_t *wpa_ucode_create_vm(void);
+int wpa_ucode_run(const char *script);
+int wpa_ucode_call_prepare(const char *fname);
+uc_value_t *wpa_ucode_call(size_t nargs);
+void wpa_ucode_free_vm(void);
+
+uc_value_t *wpa_ucode_global_init(const char *name, uc_resource_type_t *global_type);
+
+void wpa_ucode_registry_add(uc_value_t *reg, uc_value_t *val, int *idx);
+uc_value_t *wpa_ucode_registry_get(uc_value_t *reg, int idx);
+uc_value_t *wpa_ucode_registry_remove(uc_value_t *reg, int idx);
+
+uc_value_t *uc_wpa_printf(uc_vm_t *vm, size_t nargs);
+uc_value_t *uc_wpa_getpid(uc_vm_t *vm, size_t nargs);
+uc_value_t *uc_wpa_sha1(uc_vm_t *vm, size_t nargs);
+
+#endif
diff --git a/recipes-wifi/hostapd/files/src-2.10.3/wpa_supplicant/ubus.c b/recipes-wifi/hostapd/files/src-2.10.3/wpa_supplicant/ubus.c
new file mode 100644
index 0000000..1c477f0
--- /dev/null
+++ b/recipes-wifi/hostapd/files/src-2.10.3/wpa_supplicant/ubus.c
@@ -0,0 +1,280 @@
+/*
+ * wpa_supplicant / ubus support
+ * Copyright (c) 2018, Daniel Golle <daniel@makrotopia.org>
+ * Copyright (c) 2013, Felix Fietkau <nbd@nbd.name>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "utils/wpabuf.h"
+#include "common/ieee802_11_defs.h"
+#include "wpa_supplicant_i.h"
+#include "wps_supplicant.h"
+#include "ubus.h"
+
+static struct ubus_context *ctx;
+static struct blob_buf b;
+static int ctx_ref;
+
+static inline struct wpa_global *get_wpa_global_from_object(struct ubus_object *obj)
+{
+ return container_of(obj, struct wpa_global, ubus_global);
+}
+
+static inline struct wpa_supplicant *get_wpas_from_object(struct ubus_object *obj)
+{
+ return container_of(obj, struct wpa_supplicant, ubus.obj);
+}
+
+static void ubus_reconnect_timeout(void *eloop_data, void *user_ctx)
+{
+ if (ubus_reconnect(ctx, NULL)) {
+ eloop_register_timeout(1, 0, ubus_reconnect_timeout, ctx, NULL);
+ return;
+ }
+
+ ubus_add_uloop(ctx);
+}
+
+static void wpas_ubus_connection_lost(struct ubus_context *ctx)
+{
+ uloop_fd_delete(&ctx->sock);
+ eloop_register_timeout(1, 0, ubus_reconnect_timeout, ctx, NULL);
+}
+
+static bool wpas_ubus_init(void)
+{
+ if (ctx)
+ return true;
+
+ eloop_add_uloop();
+ ctx = ubus_connect(NULL);
+ if (!ctx)
+ return false;
+
+ ctx->connection_lost = wpas_ubus_connection_lost;
+ ubus_add_uloop(ctx);
+
+ return true;
+}
+
+static void wpas_ubus_ref_inc(void)
+{
+ ctx_ref++;
+}
+
+static void wpas_ubus_ref_dec(void)
+{
+ ctx_ref--;
+ if (!ctx)
+ return;
+
+ if (ctx_ref)
+ return;
+
+ uloop_fd_delete(&ctx->sock);
+ ubus_free(ctx);
+ ctx = NULL;
+}
+
+static int
+wpas_bss_get_features(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *req, const char *method,
+ struct blob_attr *msg)
+{
+ struct wpa_supplicant *wpa_s = get_wpas_from_object(obj);
+
+ blob_buf_init(&b, 0);
+ blobmsg_add_u8(&b, "ht_supported", ht_supported(wpa_s->hw.modes));
+ blobmsg_add_u8(&b, "vht_supported", vht_supported(wpa_s->hw.modes));
+ ubus_send_reply(ctx, req, b.head);
+
+ return 0;
+}
+
+static int
+wpas_bss_reload(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *req, const char *method,
+ struct blob_attr *msg)
+{
+ struct wpa_supplicant *wpa_s = get_wpas_from_object(obj);
+
+ if (wpa_supplicant_reload_configuration(wpa_s))
+ return UBUS_STATUS_UNKNOWN_ERROR;
+ else
+ return 0;
+}
+
+#ifdef CONFIG_WPS
+enum {
+ WPS_START_MULTI_AP,
+ __WPS_START_MAX
+};
+
+static const struct blobmsg_policy wps_start_policy[] = {
+ [WPS_START_MULTI_AP] = { "multi_ap", BLOBMSG_TYPE_BOOL },
+};
+
+static int
+wpas_bss_wps_start(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *req, const char *method,
+ struct blob_attr *msg)
+{
+ int rc;
+ struct wpa_supplicant *wpa_s = get_wpas_from_object(obj);
+ struct blob_attr *tb[__WPS_START_MAX], *cur;
+ int multi_ap = 0;
+
+ blobmsg_parse(wps_start_policy, __WPS_START_MAX, tb, blobmsg_data(msg), blobmsg_data_len(msg));
+
+ if (tb[WPS_START_MULTI_AP])
+ multi_ap = blobmsg_get_bool(tb[WPS_START_MULTI_AP]);
+
+ rc = wpas_wps_start_pbc(wpa_s, NULL, 0, multi_ap);
+
+ if (rc != 0)
+ return UBUS_STATUS_NOT_SUPPORTED;
+
+ return 0;
+}
+
+static int
+wpas_bss_wps_cancel(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *req, const char *method,
+ struct blob_attr *msg)
+{
+ int rc;
+ struct wpa_supplicant *wpa_s = get_wpas_from_object(obj);
+
+ rc = wpas_wps_cancel(wpa_s);
+
+ if (rc != 0)
+ return UBUS_STATUS_NOT_SUPPORTED;
+
+ return 0;
+}
+#endif
+
+static const struct ubus_method bss_methods[] = {
+ UBUS_METHOD_NOARG("reload", wpas_bss_reload),
+ UBUS_METHOD_NOARG("get_features", wpas_bss_get_features),
+#ifdef CONFIG_WPS
+ UBUS_METHOD_NOARG("wps_start", wpas_bss_wps_start),
+ UBUS_METHOD_NOARG("wps_cancel", wpas_bss_wps_cancel),
+#endif
+};
+
+static struct ubus_object_type bss_object_type =
+ UBUS_OBJECT_TYPE("wpas_bss", bss_methods);
+
+void wpas_ubus_add_bss(struct wpa_supplicant *wpa_s)
+{
+ struct ubus_object *obj = &wpa_s->ubus.obj;
+ char *name;
+ int ret;
+
+ if (!wpas_ubus_init())
+ return;
+
+ if (asprintf(&name, "wpa_supplicant.%s", wpa_s->ifname) < 0)
+ return;
+
+ obj->name = name;
+ obj->type = &bss_object_type;
+ obj->methods = bss_object_type.methods;
+ obj->n_methods = bss_object_type.n_methods;
+ ret = ubus_add_object(ctx, obj);
+ wpas_ubus_ref_inc();
+}
+
+void wpas_ubus_free_bss(struct wpa_supplicant *wpa_s)
+{
+ struct ubus_object *obj = &wpa_s->ubus.obj;
+ char *name = (char *) obj->name;
+
+ if (!ctx)
+ return;
+
+ if (obj->id) {
+ ubus_remove_object(ctx, obj);
+ wpas_ubus_ref_dec();
+ }
+
+ free(name);
+}
+
+#ifdef CONFIG_WPS
+void wpas_ubus_notify(struct wpa_supplicant *wpa_s, const struct wps_credential *cred)
+{
+ u16 auth_type;
+ char *ifname, *encryption, *ssid, *key;
+ size_t ifname_len;
+
+ if (!cred)
+ return;
+
+ auth_type = cred->auth_type;
+
+ if (auth_type == (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK))
+ auth_type = WPS_AUTH_WPA2PSK;
+
+ if (auth_type != WPS_AUTH_OPEN &&
+ auth_type != WPS_AUTH_WPAPSK &&
+ auth_type != WPS_AUTH_WPA2PSK) {
+ wpa_printf(MSG_DEBUG, "WPS: Ignored credentials for "
+ "unsupported authentication type 0x%x",
+ auth_type);
+ return;
+ }
+
+ if (auth_type == WPS_AUTH_WPAPSK || auth_type == WPS_AUTH_WPA2PSK) {
+ if (cred->key_len < 8 || cred->key_len > 2 * PMK_LEN) {
+ wpa_printf(MSG_ERROR, "WPS: Reject PSK credential with "
+ "invalid Network Key length %lu",
+ (unsigned long) cred->key_len);
+ return;
+ }
+ }
+
+ blob_buf_init(&b, 0);
+
+ ifname_len = strlen(wpa_s->ifname);
+ ifname = blobmsg_alloc_string_buffer(&b, "ifname", ifname_len + 1);
+ memcpy(ifname, wpa_s->ifname, ifname_len + 1);
+ ifname[ifname_len] = '\0';
+ blobmsg_add_string_buffer(&b);
+
+ switch (auth_type) {
+ case WPS_AUTH_WPA2PSK:
+ encryption = "psk2";
+ break;
+ case WPS_AUTH_WPAPSK:
+ encryption = "psk";
+ break;
+ default:
+ encryption = "none";
+ break;
+ }
+
+ blobmsg_add_string(&b, "encryption", encryption);
+
+ ssid = blobmsg_alloc_string_buffer(&b, "ssid", cred->ssid_len + 1);
+ memcpy(ssid, cred->ssid, cred->ssid_len);
+ ssid[cred->ssid_len] = '\0';
+ blobmsg_add_string_buffer(&b);
+
+ if (cred->key_len > 0) {
+ key = blobmsg_alloc_string_buffer(&b, "key", cred->key_len + 1);
+ memcpy(key, cred->key, cred->key_len);
+ key[cred->key_len] = '\0';
+ blobmsg_add_string_buffer(&b);
+ }
+
+// ubus_notify(ctx, &wpa_s->ubus.obj, "wps_credentials", b.head, -1);
+ ubus_send_event(ctx, "wps_credentials", b.head);
+}
+#endif /* CONFIG_WPS */
diff --git a/recipes-wifi/hostapd/files/src-2.10.3/wpa_supplicant/ubus.h b/recipes-wifi/hostapd/files/src-2.10.3/wpa_supplicant/ubus.h
new file mode 100644
index 0000000..f6681cb
--- /dev/null
+++ b/recipes-wifi/hostapd/files/src-2.10.3/wpa_supplicant/ubus.h
@@ -0,0 +1,55 @@
+/*
+ * wpa_supplicant / ubus support
+ * Copyright (c) 2018, Daniel Golle <daniel@makrotopia.org>
+ * Copyright (c) 2013, Felix Fietkau <nbd@nbd.name>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+#ifndef __WPAS_UBUS_H
+#define __WPAS_UBUS_H
+
+struct wpa_supplicant;
+struct wpa_global;
+
+#include "wps_supplicant.h"
+
+#ifdef UBUS_SUPPORT
+#include <libubus.h>
+
+struct wpas_ubus_bss {
+ struct ubus_object obj;
+};
+
+void wpas_ubus_add_bss(struct wpa_supplicant *wpa_s);
+void wpas_ubus_free_bss(struct wpa_supplicant *wpa_s);
+
+#ifdef CONFIG_WPS
+void wpas_ubus_notify(struct wpa_supplicant *wpa_s, const struct wps_credential *cred);
+#endif
+
+#else
+struct wpas_ubus_bss {};
+
+static inline void wpas_ubus_add_bss(struct wpa_supplicant *wpa_s)
+{
+}
+
+static inline void wpas_ubus_free_bss(struct wpa_supplicant *wpa_s)
+{
+}
+
+static inline void wpas_ubus_notify(struct wpa_supplicant *wpa_s, struct wps_credential *cred)
+{
+}
+
+static inline void wpas_ubus_add(struct wpa_global *global)
+{
+}
+
+static inline void wpas_ubus_free(struct wpa_global *global)
+{
+}
+#endif
+
+#endif
diff --git a/recipes-wifi/hostapd/files/src-2.10.3/wpa_supplicant/ucode.c b/recipes-wifi/hostapd/files/src-2.10.3/wpa_supplicant/ucode.c
new file mode 100644
index 0000000..eec3980
--- /dev/null
+++ b/recipes-wifi/hostapd/files/src-2.10.3/wpa_supplicant/ucode.c
@@ -0,0 +1,177 @@
+#include "utils/includes.h"
+#include "utils/common.h"
+#include "utils/ucode.h"
+#include "wpa_supplicant_i.h"
+#include "wps_supplicant.h"
+#include "ucode.h"
+
+static struct wpa_global *wpa_global;
+static uc_resource_type_t *global_type, *iface_type;
+static uc_value_t *global, *iface_registry;
+static uc_vm_t *vm;
+
+static uc_value_t *
+wpas_ucode_iface_get_uval(struct wpa_supplicant *wpa_s)
+{
+ uc_value_t *val;
+
+ if (wpa_s->ucode.idx)
+ return wpa_ucode_registry_get(iface_registry, wpa_s->ucode.idx);
+
+ val = uc_resource_new(iface_type, wpa_s);
+ wpa_ucode_registry_add(iface_registry, val, &wpa_s->ucode.idx);
+
+ return val;
+}
+
+static void
+wpas_ucode_update_interfaces(void)
+{
+ uc_value_t *ifs = ucv_object_new(vm);
+ struct wpa_supplicant *wpa_s;
+ int i;
+
+ for (wpa_s = wpa_global->ifaces; wpa_s; wpa_s = wpa_s->next)
+ ucv_object_add(ifs, wpa_s->ifname, ucv_get(wpas_ucode_iface_get_uval(wpa_s)));
+
+ ucv_object_add(ucv_prototype_get(global), "interfaces", ucv_get(ifs));
+ ucv_gc(vm);
+}
+
+void wpas_ucode_add_bss(struct wpa_supplicant *wpa_s)
+{
+ uc_value_t *val;
+
+ if (wpa_ucode_call_prepare("iface_add"))
+ return;
+
+ uc_value_push(ucv_get(ucv_string_new(wpa_s->ifname)));
+ uc_value_push(ucv_get(wpas_ucode_iface_get_uval(wpa_s)));
+ ucv_put(wpa_ucode_call(2));
+ ucv_gc(vm);
+}
+
+void wpas_ucode_free_bss(struct wpa_supplicant *wpa_s)
+{
+ uc_value_t *val;
+
+ val = wpa_ucode_registry_remove(iface_registry, wpa_s->ucode.idx);
+ if (!val)
+ return;
+
+ wpa_s->ucode.idx = 0;
+ if (wpa_ucode_call_prepare("iface_remove"))
+ return;
+
+ uc_value_push(ucv_get(ucv_string_new(wpa_s->ifname)));
+ uc_value_push(ucv_get(val));
+ ucv_put(wpa_ucode_call(2));
+ ucv_gc(vm);
+}
+
+static const char *obj_stringval(uc_value_t *obj, const char *name)
+{
+ uc_value_t *val = ucv_object_get(obj, name, NULL);
+
+ return ucv_string_get(val);
+}
+
+static uc_value_t *
+uc_wpas_add_iface(uc_vm_t *vm, size_t nargs)
+{
+ uc_value_t *info = uc_fn_arg(0);
+ uc_value_t *ifname = ucv_object_get(info, "iface", NULL);
+ uc_value_t *bridge = ucv_object_get(info, "bridge", NULL);
+ uc_value_t *config = ucv_object_get(info, "config", NULL);
+ uc_value_t *ctrl = ucv_object_get(info, "ctrl", NULL);
+ uc_value_t *hapd_ctrl = ucv_object_get(info, "hostapd_ctrl", NULL);
+ struct wpa_interface iface;
+ int ret = -1;
+
+ if (ucv_type(info) != UC_OBJECT)
+ goto out;
+
+ iface = (struct wpa_interface){
+ .driver = "nl80211",
+ .ifname = ucv_string_get(ifname),
+ .bridge_ifname = ucv_string_get(bridge),
+ .confname = ucv_string_get(config),
+ .ctrl_interface = ucv_string_get(ctrl),
+ .hostapd_ctrl = ucv_string_get(hapd_ctrl),
+ };
+
+ if (!iface.ifname || !iface.confname)
+ goto out;
+
+ ret = wpa_supplicant_add_iface(wpa_global, &iface, 0) ? 0 : -1;
+ wpas_ucode_update_interfaces();
+
+out:
+ return ucv_int64_new(ret);
+}
+
+static uc_value_t *
+uc_wpas_remove_iface(uc_vm_t *vm, size_t nargs)
+{
+ struct wpa_supplicant *wpa_s = NULL;
+ uc_value_t *ifname_arg = uc_fn_arg(0);
+ const char *ifname = ucv_string_get(ifname_arg);
+ int ret = -1;
+
+ if (!ifname)
+ goto out;
+
+ for (wpa_s = wpa_global->ifaces; wpa_s; wpa_s = wpa_s->next)
+ if (!strcmp(wpa_s->ifname, ifname))
+ break;
+
+ if (!wpa_s)
+ goto out;
+
+ ret = wpa_supplicant_remove_iface(wpa_global, wpa_s, 0);
+ wpas_ucode_update_interfaces();
+
+out:
+ return ucv_int64_new(ret);
+}
+
+int wpas_ucode_init(struct wpa_global *gl)
+{
+ static const uc_function_list_t global_fns[] = {
+ { "printf", uc_wpa_printf },
+ { "getpid", uc_wpa_getpid },
+ { "add_iface", uc_wpas_add_iface },
+ { "remove_iface", uc_wpas_remove_iface },
+ };
+ static const uc_function_list_t iface_fns[] = {
+ };
+ uc_value_t *data, *proto;
+
+ wpa_global = gl;
+ vm = wpa_ucode_create_vm();
+
+ global_type = uc_type_declare(vm, "wpas.global", global_fns, NULL);
+ iface_type = uc_type_declare(vm, "hostapd.iface", iface_fns, NULL);
+
+ iface_registry = ucv_array_new(vm);
+ uc_vm_registry_set(vm, "hostap.iface_registry", iface_registry);
+
+ global = wpa_ucode_global_init("wpas", global_type);
+
+ if (wpa_ucode_run(HOSTAPD_UC_PATH "wpa_supplicant.uc"))
+ goto free_vm;
+
+ ucv_gc(vm);
+ return 0;
+
+free_vm:
+ wpa_ucode_free_vm();
+ return -1;
+}
+
+void wpas_ucode_free(void)
+{
+ if (wpa_ucode_call_prepare("shutdown") == 0)
+ ucv_put(wpa_ucode_call(0));
+ wpa_ucode_free_vm();
+}
diff --git a/recipes-wifi/hostapd/files/src-2.10.3/wpa_supplicant/ucode.h b/recipes-wifi/hostapd/files/src-2.10.3/wpa_supplicant/ucode.h
new file mode 100644
index 0000000..fcd2313
--- /dev/null
+++ b/recipes-wifi/hostapd/files/src-2.10.3/wpa_supplicant/ucode.h
@@ -0,0 +1,38 @@
+#ifndef __WPAS_UCODE_H
+#define __WPAS_UCODE_H
+
+#include "utils/ucode.h"
+
+struct wpa_global;
+struct wpa_supplicant;
+
+struct wpas_ucode_bss {
+#ifdef UCODE_SUPPORT
+ unsigned int idx;
+#endif
+};
+
+#ifdef UCODE_SUPPORT
+int wpas_ucode_init(struct wpa_global *gl);
+void wpas_ucode_free(void);
+void wpas_ucode_add_bss(struct wpa_supplicant *wpa_s);
+void wpas_ucode_free_bss(struct wpa_supplicant *wpa_s);
+#else
+static inline int wpas_ucode_init(struct wpa_global *gl)
+{
+ return -EINVAL;
+}
+static inline void wpas_ucode_free(void)
+{
+}
+static inline void wpas_ucode_add_bss(struct wpa_supplicant *wpa_s)
+{
+}
+
+static inline void wpas_ucode_free_bss(struct wpa_supplicant *wpa_s)
+{
+}
+
+#endif
+
+#endif
diff --git a/recipes-wifi/hostapd/files/wdev.uc b/recipes-wifi/hostapd/files/wdev.uc
new file mode 100644
index 0000000..5b32142
--- /dev/null
+++ b/recipes-wifi/hostapd/files/wdev.uc
@@ -0,0 +1,156 @@
+#!/usr/bin/env ucode
+'use strict';
+import { vlist_new, is_equal, wdev_create, wdev_remove } from "/usr/share/hostap/common.uc";
+import { readfile, writefile, basename, readlink, glob } from "fs";
+
+let keep_devices = {};
+let phy = shift(ARGV);
+let new_config = shift(ARGV);
+const mesh_params = [
+ "mesh_retry_timeout", "mesh_confirm_timeout", "mesh_holding_timeout", "mesh_max_peer_links",
+ "mesh_max_retries", "mesh_ttl", "mesh_element_ttl", "mesh_hwmp_max_preq_retries",
+ "mesh_path_refresh_time", "mesh_min_discovery_timeout", "mesh_hwmp_active_path_timeout",
+ "mesh_hwmp_preq_min_interval", "mesh_hwmp_net_diameter_traversal_time", "mesh_hwmp_rootmode",
+ "mesh_hwmp_rann_interval", "mesh_gate_announcements", "mesh_sync_offset_max_neighor",
+ "mesh_rssi_threshold", "mesh_hwmp_active_path_to_root_timeout", "mesh_hwmp_root_interval",
+ "mesh_hwmp_confirmation_interval", "mesh_awake_window", "mesh_plink_timeout",
+ "mesh_auto_open_plinks", "mesh_fwding", "mesh_power_mode"
+];
+
+function iface_stop(wdev)
+{
+ if (keep_devices[wdev.ifname])
+ return;
+
+ wdev_remove(wdev.ifname);
+}
+
+function iface_start(wdev)
+{
+ let ifname = wdev.ifname;
+
+ if (readfile(`/sys/class/net/${ifname}/ifindex`)) {
+ system([ "ip", "link", "set", "dev", ifname, "down" ]);
+ wdev_remove(ifname);
+ }
+ wdev_create(phy, ifname, wdev);
+ system([ "ip", "link", "set", "dev", ifname, "up" ]);
+ if (wdev.freq)
+ system(`iw dev ${ifname} set freq ${wdev.freq} ${wdev.htmode}`);
+ if (wdev.mode == "adhoc") {
+ let cmd = ["iw", "dev", ifname, "ibss", "join", wdev.ssid, wdev.freq, wdev.htmode, "fixed-freq" ];
+ if (wdev.bssid)
+ push(cmd, wdev.bssid);
+ for (let key in [ "beacon-interval", "basic-rates", "mcast-rate", "keys" ])
+ if (wdev[key])
+ push(cmd, key, wdev[key]);
+ system(cmd);
+ } else if (wdev.mode == "mesh") {
+ let cmd = [ "iw", "dev", ifname, "mesh", "join", wdev.ssid, "freq", wdev.freq, wdev.htmode ];
+ for (let key in [ "beacon-interval", "mcast-rate" ])
+ if (wdev[key])
+ push(cmd, key, wdev[key]);
+ system(cmd);
+
+ cmd = ["iw", "dev", ifname, "set", "mesh_param" ];
+ let len = length(cmd);
+
+ for (let param in mesh_params)
+ if (wdev[param])
+ push(cmd, param, wdev[param]);
+
+ if (len == length(cmd))
+ return;
+
+ system(cmd);
+ }
+
+}
+
+function iface_cb(new_if, old_if)
+{
+ if (old_if && new_if && is_equal(old_if, new_if))
+ return;
+
+ if (old_if)
+ iface_stop(old_if);
+ if (new_if)
+ iface_start(new_if);
+}
+
+function drop_inactive(config)
+{
+ for (let key in config) {
+ if (!readfile(`/sys/class/net/${key}/ifindex`))
+ delete config[key];
+ }
+}
+
+function add_ifname(config)
+{
+ for (let key in config)
+ config[key].ifname = key;
+}
+
+function delete_ifname(config)
+{
+ for (let key in config)
+ delete config[key].ifname;
+}
+
+function add_existing(phy, config)
+{
+ let wdevs = glob(`/sys/class/ieee80211/${phy}/device/net/*`);
+ wdevs = map(wdevs, (arg) => basename(arg));
+ for (let wdev in wdevs) {
+ if (config[wdev])
+ continue;
+
+ if (basename(readlink(`/sys/class/net/${wdev}/phy80211`)) != phy)
+ continue;
+
+ if (trim(readfile(`/sys/class/net/${wdev}/operstate`)) == "down")
+ config[wdev] = {};
+ }
+}
+
+
+let statefile = `/var/run/wdev-${phy}.json`;
+
+for (let dev in ARGV)
+ keep_devices[dev] = true;
+
+if (!phy || !new_config) {
+ warn(`Usage: ${basename(sourcepath())} <phy> <config> [<device]...]\n`);
+ exit(1);
+}
+
+if (!readfile(`/sys/class/ieee80211/${phy}/index`)) {
+ warn(`PHY ${phy} does not exist\n`);
+ exit(1);
+}
+
+new_config = json(new_config);
+if (!new_config) {
+ warn("Invalid configuration\n");
+ exit(1);
+}
+
+let old_config = readfile(statefile);
+if (old_config)
+ old_config = json(old_config);
+
+let config = vlist_new(iface_cb);
+if (type(old_config) == "object")
+ config.data = old_config;
+
+add_existing(phy, config.data);
+add_ifname(config.data);
+drop_inactive(config.data);
+
+add_ifname(new_config);
+config.update(new_config);
+
+drop_inactive(config.data);
+delete_ifname(config.data);
+writefile(statefile, sprintf("%J", config.data));
diff --git a/recipes-wifi/hostapd/hostapd_2.10.3.bb b/recipes-wifi/hostapd/hostapd_2.10.3.bb
index 906d89a..cc9809a 100644
--- a/recipes-wifi/hostapd/hostapd_2.10.3.bb
+++ b/recipes-wifi/hostapd/hostapd_2.10.3.bb
@@ -4,10 +4,10 @@
LICENSE = "BSD-3-Clause"
LIC_FILES_CHKSUM = "file://hostapd/README;md5=c905478466c90f1cefc0df987c40e172"
-DEPENDS = "libnl openssl ubus"
+DEPENDS = "libnl openssl ubus ucode"
DEPENDS_append = " ${@bb.utils.contains('DISTRO_FEATURES', 'telemetry2_0', 'telemetry', '', d)}"
LDFLAGS_append = " ${@bb.utils.contains('DISTRO_FEATURES', 'telemetry2_0', ' -ltelemetry_msgsender ', '', d)}"
-RDEPENDS_${PN} += "gawk"
+RDEPENDS_${PN} += "gawk ucode"
FILESEXTRAPATHS_prepend := "${THISDIR}/files:"
FILESEXTRAPATHS_prepend := "${THISDIR}/files/patches-${PV}:"
@@ -25,8 +25,11 @@
file://hostapd-init.sh \
file://mac80211-EHT.sh \
file://init-uci-config.service \
- file://src \
- file://001-rdkb-remove-ubus-support.patch;apply=no \
+ file://hostapd.uc \
+ file://common.uc \
+ file://wdev.uc \
+ file://src-${PV} \
+ file://002-rdkb-add-ucode-support.patch;apply=no \
"
require files/patches-${PV}/patches.inc
@@ -39,13 +42,13 @@
SYSTEMD_AUTO_ENABLE_${PN} = "enable"
SYSTEMD_SERVICE_${PN} = "hostapd.service"
SYSTEMD_SERVICE_${PN} += " init-uci-config.service"
-
+INSANE_SKIP_${PN} += "file-rdeps"
do_unpack_append() {
bb.build.exec_func('do_copy_openwrt_src', d)
}
do_copy_openwrt_src() {
- cp -Rfp ${WORKDIR}/src/* ${S}/
+ cp -Rfp ${WORKDIR}/src-${PV}/* ${S}/
}
do_configure_append() {
@@ -69,12 +72,13 @@
echo "CONFIG_FILS=y" >> ${B}/.config
echo "CONFIG_IEEE80211BE=y" >> ${B}/.config
echo "CONFIG_TESTING_OPTIONS=y" >> ${B}/.config
+ echo "CONFIG_UCODE=y" >> ${B}/.config
}
do_filogic_patches() {
cd ${S}
if [ ! -e patch_applied ]; then
- patch -p1 < ${WORKDIR}/001-rdkb-remove-ubus-support.patch
+ patch -p1 < ${WORKDIR}/002-rdkb-add-ucode-support.patch
touch patch_applied
fi
}
@@ -88,7 +92,7 @@
}
do_install() {
- install -d ${D}${sbindir} ${D}${sysconfdir} ${D}${systemd_unitdir}/system/ ${D}${base_libdir}/rdk
+ install -d ${D}${sbindir} ${D}${sysconfdir} ${D}${systemd_unitdir}/system/ ${D}${base_libdir}/rdk ${D}${datadir}/hostap
install -m 0755 ${B}/hostapd ${D}${sbindir}
install -m 0755 ${B}/hostapd_cli ${D}${sbindir}
install -m 0644 ${WORKDIR}/hostapd-2G-EHT.conf ${D}${sysconfdir}/hostapd-2G.conf
@@ -100,6 +104,9 @@
install -m 0755 ${WORKDIR}/hostapd-init.sh ${D}${base_libdir}/rdk
install -m 0644 ${WORKDIR}/init-uci-config.service ${D}${systemd_unitdir}/system
install -m 0755 ${WORKDIR}/mac80211-EHT.sh ${D}${sbindir}/mac80211.sh
+ install -m 0755 ${WORKDIR}/hostapd.uc ${D}${datadir}/hostap
+ install -m 0755 ${WORKDIR}/wdev.uc ${D}${datadir}/hostap
+ install -m 0755 ${WORKDIR}/common.uc ${D}${datadir}/hostap
}
FILES_${PN} += " \
@@ -111,4 +118,7 @@
${sysconfdir}/hostapd-5G-7916.conf \
${base_libdir}/rdk/hostapd-init.sh \
${systemd_unitdir}/system/init-uci-config.service \
+ ${datadir}/hostap/hostapd.uc \
+ ${datadir}/hostap/wdev.uc \
+ ${datadir}/hostap/common.uc \
"
diff --git a/recipes-wifi/json-c/json-c/CVE-2020-12762.patch b/recipes-wifi/json-c/json-c/CVE-2020-12762.patch
new file mode 100644
index 0000000..50674f0
--- /dev/null
+++ b/recipes-wifi/json-c/json-c/CVE-2020-12762.patch
@@ -0,0 +1,231 @@
+From 865b5a65199973bb63dff8e47a2f57e04fec9736 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Bj=C3=B6rn=20Esser?= <besser82@fedoraproject.org>
+Date: Thu, 14 May 2020 12:32:30 +0200
+Subject: [PATCH] Fix CVE-2020-12762.
+
+This commit is a squashed backport of the following commits
+on the master branch:
+
+ * 099016b7e8d70a6d5dd814e788bba08d33d48426
+ * 77d935b7ae7871a1940cd827e850e6063044ec45
+ * d07b91014986900a3a75f306d302e13e005e9d67
+ * 519dfe1591d85432986f9762d41d1a883198c157
+ * a59d5acfab4485d5133114df61785b1fc633e0c6
+---
+CVE: CVE-2020-12762
+Upstream-Status: Backport [https://github.com/json-c/json-c/commit/865b5a65199973bb63dff8e47a2f57e04fec9736]
+Signed-off-by: Khem Raj <raj.khem@gmail.com>
+
+ arraylist.c | 3 +++
+ linkhash.c | 21 ++++++++++++++-------
+ printbuf.c | 38 ++++++++++++++++++++++++++------------
+ tests/test4.c | 30 +++++++++++++++++++++++++++++-
+ tests/test4.expected | 1 +
+ 5 files changed, 73 insertions(+), 20 deletions(-)
+
+diff --git a/arraylist.c b/arraylist.c
+index ddeb8d4eb4..e737052e32 100644
+--- a/arraylist.c
++++ b/arraylist.c
+@@ -135,6 +135,9 @@ array_list_del_idx( struct array_list *arr, size_t idx, size_t count )
+ {
+ size_t i, stop;
+
++ /* Avoid overflow in calculation with large indices. */
++ if (idx > SIZE_T_MAX - count)
++ return -1;
+ stop = idx + count;
+ if ( idx >= arr->length || stop > arr->length ) return -1;
+ for ( i = idx; i < stop; ++i ) {
+diff --git a/linkhash.c b/linkhash.c
+index 5497061a8a..6435a154ac 100644
+--- a/linkhash.c
++++ b/linkhash.c
+@@ -12,12 +12,13 @@
+
+ #include "config.h"
+
+-#include <stdio.h>
+-#include <string.h>
+-#include <stdlib.h>
++#include <assert.h>
++#include <limits.h>
+ #include <stdarg.h>
+ #include <stddef.h>
+-#include <limits.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
+
+ #ifdef HAVE_ENDIAN_H
+ # include <endian.h> /* attempt to define endianness */
+@@ -28,8 +29,8 @@
+ # include <windows.h> /* Get InterlockedCompareExchange */
+ #endif
+
+-#include "random_seed.h"
+ #include "linkhash.h"
++#include "random_seed.h"
+
+ /* hash functions */
+ static unsigned long lh_char_hash(const void *k);
+@@ -498,7 +499,9 @@ struct lh_table* lh_table_new(int size,
+ int i;
+ struct lh_table *t;
+
+- t = (struct lh_table*)calloc(1, sizeof(struct lh_table));
++ /* Allocate space for elements to avoid divisions by zero. */
++ assert(size > 0);
++ t = (struct lh_table *)calloc(1, sizeof(struct lh_table));
+ if (!t)
+ return NULL;
+
+@@ -577,8 +580,12 @@ int lh_table_insert_w_hash(struct lh_table *t, const void *k, const void *v, con
+ unsigned long n;
+
+ if (t->count >= t->size * LH_LOAD_FACTOR)
+- if (lh_table_resize(t, t->size * 2) != 0)
++ {
++ /* Avoid signed integer overflow with large tables. */
++ int new_size = (t->size > INT_MAX / 2) ? INT_MAX : (t->size * 2);
++ if (t->size == INT_MAX || lh_table_resize(t, new_size) != 0)
+ return -1;
++ }
+
+ n = h % t->size;
+
+diff --git a/printbuf.c b/printbuf.c
+index 6c77b5defd..6fc56de455 100644
+--- a/printbuf.c
++++ b/printbuf.c
+@@ -15,6 +15,7 @@
+
+ #include "config.h"
+
++#include <limits.h>
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
+@@ -64,10 +65,16 @@ static int printbuf_extend(struct printbuf *p, int min_size)
+
+ if (p->size >= min_size)
+ return 0;
+-
+- new_size = p->size * 2;
+- if (new_size < min_size + 8)
+- new_size = min_size + 8;
++ /* Prevent signed integer overflows with large buffers. */
++ if (min_size > INT_MAX - 8)
++ return -1;
++ if (p->size > INT_MAX / 2)
++ new_size = min_size + 8;
++ else {
++ new_size = p->size * 2;
++ if (new_size < min_size + 8)
++ new_size = min_size + 8;
++ }
+ #ifdef PRINTBUF_DEBUG
+ MC_DEBUG("printbuf_memappend: realloc "
+ "bpos=%d min_size=%d old_size=%d new_size=%d\n",
+@@ -82,14 +89,18 @@ static int printbuf_extend(struct printbuf *p, int min_size)
+
+ int printbuf_memappend(struct printbuf *p, const char *buf, int size)
+ {
+- if (p->size <= p->bpos + size + 1) {
+- if (printbuf_extend(p, p->bpos + size + 1) < 0)
+- return -1;
+- }
+- memcpy(p->buf + p->bpos, buf, size);
+- p->bpos += size;
+- p->buf[p->bpos]= '\0';
+- return size;
++ /* Prevent signed integer overflows with large buffers. */
++ if (size > INT_MAX - p->bpos - 1)
++ return -1;
++ if (p->size <= p->bpos + size + 1)
++ {
++ if (printbuf_extend(p, p->bpos + size + 1) < 0)
++ return -1;
++ }
++ memcpy(p->buf + p->bpos, buf, size);
++ p->bpos += size;
++ p->buf[p->bpos] = '\0';
++ return size;
+ }
+
+ int printbuf_memset(struct printbuf *pb, int offset, int charvalue, int len)
+@@ -98,6 +109,9 @@ int printbuf_memset(struct printbuf *pb, int offset, int charvalue, int len)
+
+ if (offset == -1)
+ offset = pb->bpos;
++ /* Prevent signed integer overflows with large buffers. */
++ if (len > INT_MAX - offset)
++ return -1;
+ size_needed = offset + len;
+ if (pb->size < size_needed)
+ {
+diff --git a/tests/test4.c b/tests/test4.c
+index fc8b79dbf4..82d3f494de 100644
+--- a/tests/test4.c
++++ b/tests/test4.c
+@@ -2,9 +2,11 @@
+ * gcc -o utf8 utf8.c -I/home/y/include -L./.libs -ljson
+ */
+
++#include "config.h"
++#include <assert.h>
+ #include <stdio.h>
++#include <stdlib.h>
+ #include <string.h>
+-#include "config.h"
+
+ #include "json_inttypes.h"
+ #include "json_object.h"
+@@ -24,6 +26,29 @@ void print_hex(const char* s)
+ putchar('\n');
+ }
+
++static void test_lot_of_adds(void);
++static void test_lot_of_adds()
++{
++ int ii;
++ char key[50];
++ json_object *jobj = json_object_new_object();
++ assert(jobj != NULL);
++ for (ii = 0; ii < 500; ii++)
++ {
++ snprintf(key, sizeof(key), "k%d", ii);
++ json_object *iobj = json_object_new_int(ii);
++ assert(iobj != NULL);
++ if (json_object_object_add(jobj, key, iobj))
++ {
++ fprintf(stderr, "FAILED to add object #%d\n", ii);
++ abort();
++ }
++ }
++ printf("%s\n", json_object_to_json_string(jobj));
++ assert(json_object_object_length(jobj) == 500);
++ json_object_put(jobj);
++}
++
+ int main(void)
+ {
+ const char *input = "\"\\ud840\\udd26,\\ud840\\udd27,\\ud800\\udd26,\\ud800\\udd27\"";
+@@ -49,5 +74,8 @@ int main(void)
+ retval = 1;
+ }
+ json_object_put(parse_result);
++
++ test_lot_of_adds();
++
+ return retval;
+ }
+diff --git a/tests/test4.expected b/tests/test4.expected
+index 68d4336d90..cb2744012b 100644
+--- a/tests/test4.expected
++++ b/tests/test4.expected
+@@ -1,3 +1,4 @@
+ input: "\ud840\udd26,\ud840\udd27,\ud800\udd26,\ud800\udd27"
+ JSON parse result is correct: 𠄦,𠄧,𐄦,𐄧
+ PASS
++{ "k0": 0, "k1": 1, "k2": 2, "k3": 3, "k4": 4, "k5": 5, "k6": 6, "k7": 7, "k8": 8, "k9": 9, "k10": 10, "k11": 11, "k12": 12, "k13": 13, "k14": 14, "k15": 15, "k16": 16, "k17": 17, "k18": 18, "k19": 19, "k20": 20, "k21": 21, "k22": 22, "k23": 23, "k24": 24, "k25": 25, "k26": 26, "k27": 27, "k28": 28, "k29": 29, "k30": 30, "k31": 31, "k32": 32, "k33": 33, "k34": 34, "k35": 35, "k36": 36, "k37": 37, "k38": 38, "k39": 39, "k40": 40, "k41": 41, "k42": 42, "k43": 43, "k44": 44, "k45": 45, "k46": 46, "k47": 47, "k48": 48, "k49": 49, "k50": 50, "k51": 51, "k52": 52, "k53": 53, "k54": 54, "k55": 55, "k56": 56, "k57": 57, "k58": 58, "k59": 59, "k60": 60, "k61": 61, "k62": 62, "k63": 63, "k64": 64, "k65": 65, "k66": 66, "k67": 67, "k68": 68, "k69": 69, "k70": 70, "k71": 71, "k72": 72, "k73": 73, "k74": 74, "k75": 75, "k76": 76, "k77": 77, "k78": 78, "k79": 79, "k80": 80, "k81": 81, "k82": 82, "k83": 83, "k84": 84, "k85": 85, "k86": 86, "k87": 87, "k88": 88, "k89": 89, "k90": 90, "k91": 91, "k92": 92, "k93": 93, "k94": 94, "k95": 95, "k96": 96, "k97": 97, "k98": 98, "k99": 99, "k100": 100, "k101": 101, "k102": 102, "k103": 103, "k104": 104, "k105": 105, "k106": 106, "k107": 107, "k108": 108, "k109": 109, "k110": 110, "k111": 111, "k112": 112, "k113": 113, "k114": 114, "k115": 115, "k116": 116, "k117": 117, "k118": 118, "k119": 119, "k120": 120, "k121": 121, "k122": 122, "k123": 123, "k124": 124, "k125": 125, "k126": 126, "k127": 127, "k128": 128, "k129": 129, "k130": 130, "k131": 131, "k132": 132, "k133": 133, "k134": 134, "k135": 135, "k136": 136, "k137": 137, "k138": 138, "k139": 139, "k140": 140, "k141": 141, "k142": 142, "k143": 143, "k144": 144, "k145": 145, "k146": 146, "k147": 147, "k148": 148, "k149": 149, "k150": 150, "k151": 151, "k152": 152, "k153": 153, "k154": 154, "k155": 155, "k156": 156, "k157": 157, "k158": 158, "k159": 159, "k160": 160, "k161": 161, "k162": 162, "k163": 163, "k164": 164, "k165": 165, "k166": 166, "k167": 167, "k168": 168, "k169": 169, "k170": 170, "k171": 171, "k172": 172, "k173": 173, "k174": 174, "k175": 175, "k176": 176, "k177": 177, "k178": 178, "k179": 179, "k180": 180, "k181": 181, "k182": 182, "k183": 183, "k184": 184, "k185": 185, "k186": 186, "k187": 187, "k188": 188, "k189": 189, "k190": 190, "k191": 191, "k192": 192, "k193": 193, "k194": 194, "k195": 195, "k196": 196, "k197": 197, "k198": 198, "k199": 199, "k200": 200, "k201": 201, "k202": 202, "k203": 203, "k204": 204, "k205": 205, "k206": 206, "k207": 207, "k208": 208, "k209": 209, "k210": 210, "k211": 211, "k212": 212, "k213": 213, "k214": 214, "k215": 215, "k216": 216, "k217": 217, "k218": 218, "k219": 219, "k220": 220, "k221": 221, "k222": 222, "k223": 223, "k224": 224, "k225": 225, "k226": 226, "k227": 227, "k228": 228, "k229": 229, "k230": 230, "k231": 231, "k232": 232, "k233": 233, "k234": 234, "k235": 235, "k236": 236, "k237": 237, "k238": 238, "k239": 239, "k240": 240, "k241": 241, "k242": 242, "k243": 243, "k244": 244, "k245": 245, "k246": 246, "k247": 247, "k248": 248, "k249": 249, "k250": 250, "k251": 251, "k252": 252, "k253": 253, "k254": 254, "k255": 255, "k256": 256, "k257": 257, "k258": 258, "k259": 259, "k260": 260, "k261": 261, "k262": 262, "k263": 263, "k264": 264, "k265": 265, "k266": 266, "k267": 267, "k268": 268, "k269": 269, "k270": 270, "k271": 271, "k272": 272, "k273": 273, "k274": 274, "k275": 275, "k276": 276, "k277": 277, "k278": 278, "k279": 279, "k280": 280, "k281": 281, "k282": 282, "k283": 283, "k284": 284, "k285": 285, "k286": 286, "k287": 287, "k288": 288, "k289": 289, "k290": 290, "k291": 291, "k292": 292, "k293": 293, "k294": 294, "k295": 295, "k296": 296, "k297": 297, "k298": 298, "k299": 299, "k300": 300, "k301": 301, "k302": 302, "k303": 303, "k304": 304, "k305": 305, "k306": 306, "k307": 307, "k308": 308, "k309": 309, "k310": 310, "k311": 311, "k312": 312, "k313": 313, "k314": 314, "k315": 315, "k316": 316, "k317": 317, "k318": 318, "k319": 319, "k320": 320, "k321": 321, "k322": 322, "k323": 323, "k324": 324, "k325": 325, "k326": 326, "k327": 327, "k328": 328, "k329": 329, "k330": 330, "k331": 331, "k332": 332, "k333": 333, "k334": 334, "k335": 335, "k336": 336, "k337": 337, "k338": 338, "k339": 339, "k340": 340, "k341": 341, "k342": 342, "k343": 343, "k344": 344, "k345": 345, "k346": 346, "k347": 347, "k348": 348, "k349": 349, "k350": 350, "k351": 351, "k352": 352, "k353": 353, "k354": 354, "k355": 355, "k356": 356, "k357": 357, "k358": 358, "k359": 359, "k360": 360, "k361": 361, "k362": 362, "k363": 363, "k364": 364, "k365": 365, "k366": 366, "k367": 367, "k368": 368, "k369": 369, "k370": 370, "k371": 371, "k372": 372, "k373": 373, "k374": 374, "k375": 375, "k376": 376, "k377": 377, "k378": 378, "k379": 379, "k380": 380, "k381": 381, "k382": 382, "k383": 383, "k384": 384, "k385": 385, "k386": 386, "k387": 387, "k388": 388, "k389": 389, "k390": 390, "k391": 391, "k392": 392, "k393": 393, "k394": 394, "k395": 395, "k396": 396, "k397": 397, "k398": 398, "k399": 399, "k400": 400, "k401": 401, "k402": 402, "k403": 403, "k404": 404, "k405": 405, "k406": 406, "k407": 407, "k408": 408, "k409": 409, "k410": 410, "k411": 411, "k412": 412, "k413": 413, "k414": 414, "k415": 415, "k416": 416, "k417": 417, "k418": 418, "k419": 419, "k420": 420, "k421": 421, "k422": 422, "k423": 423, "k424": 424, "k425": 425, "k426": 426, "k427": 427, "k428": 428, "k429": 429, "k430": 430, "k431": 431, "k432": 432, "k433": 433, "k434": 434, "k435": 435, "k436": 436, "k437": 437, "k438": 438, "k439": 439, "k440": 440, "k441": 441, "k442": 442, "k443": 443, "k444": 444, "k445": 445, "k446": 446, "k447": 447, "k448": 448, "k449": 449, "k450": 450, "k451": 451, "k452": 452, "k453": 453, "k454": 454, "k455": 455, "k456": 456, "k457": 457, "k458": 458, "k459": 459, "k460": 460, "k461": 461, "k462": 462, "k463": 463, "k464": 464, "k465": 465, "k466": 466, "k467": 467, "k468": 468, "k469": 469, "k470": 470, "k471": 471, "k472": 472, "k473": 473, "k474": 474, "k475": 475, "k476": 476, "k477": 477, "k478": 478, "k479": 479, "k480": 480, "k481": 481, "k482": 482, "k483": 483, "k484": 484, "k485": 485, "k486": 486, "k487": 487, "k488": 488, "k489": 489, "k490": 490, "k491": 491, "k492": 492, "k493": 493, "k494": 494, "k495": 495, "k496": 496, "k497": 497, "k498": 498, "k499": 499 }
diff --git a/recipes-wifi/json-c/json-c/add-disable-werror-option-to-configure.patch b/recipes-wifi/json-c/json-c/add-disable-werror-option-to-configure.patch
new file mode 100644
index 0000000..0c20c84
--- /dev/null
+++ b/recipes-wifi/json-c/json-c/add-disable-werror-option-to-configure.patch
@@ -0,0 +1,45 @@
+json-c: Backport --disable-werror patch to allow compilation under icecc
+
+icecc preprocesses source files locally before shipping them off to be compiled
+on remote hosts. This preprocessing removes comments, including /* fallthough */
+comments in switch statements that normally prevent an implicit-fallthrough
+warning, see https://github.com/icecc/icecream/issues/419
+
+Rather than turning off -Werror, the upstream project has implemented a
+configure option, --disable-werror, in response to Ross's
+https://github.com/json-c/json-c/issues/489
+
+This patch from
+https://github.com/json-c/json-c/commit/21c886534f8927fdc0fb5f8647394f3e0e0874b8
+
+Upstream-Status: Backport [Not yet released]
+Signed-off-by: Douglas Royds <douglas.royds@taitradio.com>
+
+From 21c886534f8927fdc0fb5f8647394f3e0e0874b8 Mon Sep 17 00:00:00 2001
+From: Pierce Lopez <pierce.lopez@gmail.com>
+Date: Sun, 9 Jun 2019 10:52:08 -0400
+Subject: [PATCH] build: add --disable-werror option to configure
+
+to omit -Werror compiler option
+---
+ configure.ac | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+diff --git a/configure.ac b/configure.ac
+index 272ea6af9c..798fd5b747 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -165,7 +165,12 @@ AS_IF([test "x$enable_Bsymbolic" = "xcheck"],
+ AS_IF([test "x$enable_Bsymbolic" = "xyes"], [JSON_BSYMBOLIC_LDFLAGS=-Wl[,]-Bsymbolic-functions])
+ AC_SUBST(JSON_BSYMBOLIC_LDFLAGS)
+
+-AX_APPEND_COMPILE_FLAGS([-Wall -Werror -Wcast-qual -Wno-error=deprecated-declarations])
++AC_ARG_ENABLE([werror],
++ AS_HELP_STRING([--disable-werror], [avoid treating compiler warnings as fatal errors]))
++
++AS_IF([test "x$enable_werror" != "xno"], [AX_APPEND_COMPILE_FLAGS([-Werror])])
++
++AX_APPEND_COMPILE_FLAGS([-Wall -Wcast-qual -Wno-error=deprecated-declarations])
+ AX_APPEND_COMPILE_FLAGS([-Wextra -Wwrite-string -Wno-unused-parameter])
+ AX_APPEND_COMPILE_FLAGS([-D_GNU_SOURCE])
+
diff --git a/recipes-wifi/json-c/json-c_0.15.bb b/recipes-wifi/json-c/json-c_0.15.bb
new file mode 100644
index 0000000..04a7892
--- /dev/null
+++ b/recipes-wifi/json-c/json-c_0.15.bb
@@ -0,0 +1,21 @@
+SUMMARY = "C bindings for apps which will manipulate JSON data"
+DESCRIPTION = "JSON-C implements a reference counting object model that allows you to easily construct JSON objects in C."
+HOMEPAGE = "https://github.com/json-c/json-c/wiki"
+LICENSE = "MIT"
+LIC_FILES_CHKSUM = "file://COPYING;md5=de54b60fbbc35123ba193fea8ee216f2"
+
+SRC_URI = "https://s3.amazonaws.com/json-c_releases/releases/${BP}.tar.gz \
+ "
+SRC_URI[md5sum] = "55f395745ee1cb3a4a39b41636087501"
+SRC_URI[sha256sum] = "b8d80a1ddb718b3ba7492916237bbf86609e9709fb007e7f7d4322f02341a4c6"
+
+UPSTREAM_CHECK_URI = "https://github.com/${BPN}/${BPN}/releases"
+UPSTREAM_CHECK_REGEX = "json-c-(?P<pver>\d+(\.\d+)+)-\d+"
+
+RPROVIDES_${PN} = "libjson"
+
+inherit cmake
+
+EXTRA_OECONF = "--disable-werror"
+
+BBCLASSEXTEND = "native nativesdk"
diff --git a/recipes-wifi/linux-mac80211/files/patches-6.x/subsys/mtk-0018-cfg80211-mtk-fix-early-return-in-cfg80211_stop_backg.patch b/recipes-wifi/linux-mac80211/files/patches-6.x/subsys/mtk-0018-cfg80211-mtk-fix-early-return-in-cfg80211_stop_backg.patch
new file mode 100644
index 0000000..d57273b
--- /dev/null
+++ b/recipes-wifi/linux-mac80211/files/patches-6.x/subsys/mtk-0018-cfg80211-mtk-fix-early-return-in-cfg80211_stop_backg.patch
@@ -0,0 +1,29 @@
+From 435bf8765d44b694b86a400fb128fcf6d72b8aa6 Mon Sep 17 00:00:00 2001
+From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
+Date: Thu, 27 Jul 2023 10:25:59 +0800
+Subject: [PATCH 18/19] cfg80211: mtk: fix early return in
+ cfg80211_stop_background_radar_detection
+
+Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
+---
+ net/wireless/mlme.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
+index 57b9bde..c2cf8aa 100644
+--- a/net/wireless/mlme.c
++++ b/net/wireless/mlme.c
+@@ -1145,9 +1145,9 @@ void cfg80211_stop_background_radar_detection(struct wireless_dev *wdev)
+ return;
+
+ rdev_set_radar_background(rdev, NULL);
+- rdev->background_radar_wdev = NULL; /* Release offchain ownership */
+
+ __cfg80211_background_cac_event(rdev, wdev,
+ &rdev->background_radar_chandef,
+ NL80211_RADAR_CAC_ABORTED);
++ rdev->background_radar_wdev = NULL; /* Release offchain ownership */
+ }
+--
+2.18.0
+
diff --git a/recipes-wifi/linux-mac80211/files/patches-6.x/subsys/mtk-0019-cfg80211-mtk-add-background-radar-stop-when-backgrou.patch b/recipes-wifi/linux-mac80211/files/patches-6.x/subsys/mtk-0019-cfg80211-mtk-add-background-radar-stop-when-backgrou.patch
new file mode 100644
index 0000000..66d4d10
--- /dev/null
+++ b/recipes-wifi/linux-mac80211/files/patches-6.x/subsys/mtk-0019-cfg80211-mtk-add-background-radar-stop-when-backgrou.patch
@@ -0,0 +1,29 @@
+From 818c8f1d1a9ff9e5423ed0927b052692c282fdf4 Mon Sep 17 00:00:00 2001
+From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
+Date: Thu, 27 Jul 2023 10:27:04 +0800
+Subject: [PATCH 19/19] cfg80211: mtk: add background radar stop when
+ background channel is overlapped with operating channel
+
+Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
+---
+ net/wireless/nl80211.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
+index 53f32c6..ab61f8f 100644
+--- a/net/wireless/nl80211.c
++++ b/net/wireless/nl80211.c
+@@ -9852,6 +9852,10 @@ static int nl80211_start_radar_detection(struct sk_buff *skb,
+ wdev->cac_started = true;
+ wdev->cac_start_time = jiffies;
+ wdev->cac_time_ms = cac_time_ms;
++ if (rdev->background_cac_started &&
++ cfg80211_is_sub_chan(&chandef, rdev->background_radar_chandef.chan, false)) {
++ cfg80211_stop_background_radar_detection(rdev->background_radar_wdev);
++ }
+ }
+ unlock:
+ wiphy_unlock(wiphy);
+--
+2.18.0
+
diff --git a/recipes-wifi/linux-mac80211/files/patches-6.x/subsys/mtk-0020-mac80211-mtk-avoid-kernel-warning-of-check_flush_dep.patch b/recipes-wifi/linux-mac80211/files/patches-6.x/subsys/mtk-0020-mac80211-mtk-avoid-kernel-warning-of-check_flush_dep.patch
new file mode 100644
index 0000000..cc72cf9
--- /dev/null
+++ b/recipes-wifi/linux-mac80211/files/patches-6.x/subsys/mtk-0020-mac80211-mtk-avoid-kernel-warning-of-check_flush_dep.patch
@@ -0,0 +1,26 @@
+From 6e6ceea486d4bd12a2d4118905d8fc0ba5eec6f6 Mon Sep 17 00:00:00 2001
+From: Evelyn Tsai <evelyn.tsai@mediatek.com>
+Date: Thu, 3 Aug 2023 07:17:44 +0800
+Subject: [PATCH 1/7] mac80211: mtk: avoid kernel warning of
+ check_flush_dependency
+
+---
+ net/mac80211/main.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/net/mac80211/main.c b/net/mac80211/main.c
+index 06d111d..8965fff 100644
+--- a/net/mac80211/main.c
++++ b/net/mac80211/main.c
+@@ -1276,7 +1276,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
+ hw->queues = IEEE80211_MAX_QUEUES;
+
+ local->workqueue =
+- alloc_ordered_workqueue("%s", 0, wiphy_name(local->hw.wiphy));
++ alloc_ordered_workqueue("%s", WQ_MEM_RECLAIM, wiphy_name(local->hw.wiphy));
+ if (!local->workqueue) {
+ result = -ENOMEM;
+ goto fail_workqueue;
+--
+2.18.0
+
diff --git a/recipes-wifi/linux-mac80211/files/patches-6.x/subsys/mtk-0021-mac80211-mtk-avoid-calling-switch_vif_chanctx-when-u.patch b/recipes-wifi/linux-mac80211/files/patches-6.x/subsys/mtk-0021-mac80211-mtk-avoid-calling-switch_vif_chanctx-when-u.patch
new file mode 100644
index 0000000..d9fcacf
--- /dev/null
+++ b/recipes-wifi/linux-mac80211/files/patches-6.x/subsys/mtk-0021-mac80211-mtk-avoid-calling-switch_vif_chanctx-when-u.patch
@@ -0,0 +1,40 @@
+From d5104c3407f3f1d476d072a8242ba40cc96ae566 Mon Sep 17 00:00:00 2001
+From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
+Date: Mon, 7 Aug 2023 19:00:53 +0800
+Subject: [PATCH] mac80211: mtk: avoid calling switch_vif_chanctx when
+ use_chanctx is false
+
+Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
+---
+ net/mac80211/chan.c | 14 ++++++++------
+ 1 file changed, 8 insertions(+), 6 deletions(-)
+
+diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
+index dbc34fb..f9d1a8a 100644
+--- a/net/mac80211/chan.c
++++ b/net/mac80211/chan.c
+@@ -1280,13 +1280,15 @@ ieee80211_link_use_reserved_reassign(struct ieee80211_link_data *link)
+ list_del(&link->reserved_chanctx_list);
+ link->reserved_chanctx = NULL;
+
+- err = drv_switch_vif_chanctx(local, vif_chsw, 1,
+- CHANCTX_SWMODE_REASSIGN_VIF);
+- if (err) {
+- if (ieee80211_chanctx_refcount(local, new_ctx) == 0)
+- ieee80211_free_chanctx(local, new_ctx);
++ if (local->use_chanctx) {
++ err = drv_switch_vif_chanctx(local, vif_chsw, 1,
++ CHANCTX_SWMODE_REASSIGN_VIF);
++ if (err) {
++ if (ieee80211_chanctx_refcount(local, new_ctx) == 0)
++ ieee80211_free_chanctx(local, new_ctx);
+
+- goto out;
++ goto out;
++ }
+ }
+
+ list_move(&link->assigned_chanctx_list, &new_ctx->assigned_links);
+--
+2.18.0
+
diff --git a/recipes-wifi/linux-mac80211/files/patches-6.x/subsys/subsys.inc b/recipes-wifi/linux-mac80211/files/patches-6.x/subsys/subsys.inc
index b559a0a..d392140 100644
--- a/recipes-wifi/linux-mac80211/files/patches-6.x/subsys/subsys.inc
+++ b/recipes-wifi/linux-mac80211/files/patches-6.x/subsys/subsys.inc
@@ -69,6 +69,10 @@
file://mtk-0015-mac80211-support-configurable-addba-resp-time.patch \
file://mtk-0016-mac80211-mtk-add-sta-assisted-DFS-state-update-mecha.patch \
file://mtk-0017-nl80211-mtk-Mark-DFS-channel-as-available-for-CSA.patch \
+ file://mtk-0018-cfg80211-mtk-fix-early-return-in-cfg80211_stop_backg.patch \
+ file://mtk-0019-cfg80211-mtk-add-background-radar-stop-when-backgrou.patch \
+ file://mtk-0020-mac80211-mtk-avoid-kernel-warning-of-check_flush_dep.patch \
+ file://mtk-0021-mac80211-mtk-avoid-calling-switch_vif_chanctx-when-u.patch \
file://mtk-1000-mac80211-mtk-add-EHT-BA1024-support.patch \
file://mtk-1001-mac80211-mtk-add-rate-duration-for-EHT-rate.patch \
file://mtk-1002-mac80211-mtk-add-send-bar-action-when-recieve-addba-.patch \
diff --git a/recipes-wifi/linux-mac80211/files/patches/subsys/mtk-0023-mac80211-mtk-avoid-calling-switch_vif_chanctx-when-u.patch b/recipes-wifi/linux-mac80211/files/patches/subsys/mtk-0023-mac80211-mtk-avoid-calling-switch_vif_chanctx-when-u.patch
new file mode 100644
index 0000000..a8a8ded
--- /dev/null
+++ b/recipes-wifi/linux-mac80211/files/patches/subsys/mtk-0023-mac80211-mtk-avoid-calling-switch_vif_chanctx-when-u.patch
@@ -0,0 +1,40 @@
+From 5098ea28917b237691a174020836c5910c1be625 Mon Sep 17 00:00:00 2001
+From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
+Date: Mon, 7 Aug 2023 19:00:53 +0800
+Subject: [PATCH] mac80211: mtk: avoid calling switch_vif_chanctx when
+ use_chanctx is false
+
+Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
+---
+ net/mac80211/chan.c | 14 ++++++++------
+ 1 file changed, 8 insertions(+), 6 deletions(-)
+
+diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
+index 63e15f5..0e4ea5d 100644
+--- a/net/mac80211/chan.c
++++ b/net/mac80211/chan.c
+@@ -1160,13 +1160,15 @@ ieee80211_vif_use_reserved_reassign(struct ieee80211_sub_if_data *sdata)
+ list_del(&sdata->reserved_chanctx_list);
+ sdata->reserved_chanctx = NULL;
+
+- err = drv_switch_vif_chanctx(local, vif_chsw, 1,
+- CHANCTX_SWMODE_REASSIGN_VIF);
+- if (err) {
+- if (ieee80211_chanctx_refcount(local, new_ctx) == 0)
+- ieee80211_free_chanctx(local, new_ctx);
++ if (local->use_chanctx) {
++ err = drv_switch_vif_chanctx(local, vif_chsw, 1,
++ CHANCTX_SWMODE_REASSIGN_VIF);
++ if (err) {
++ if (ieee80211_chanctx_refcount(local, new_ctx) == 0)
++ ieee80211_free_chanctx(local, new_ctx);
+
+- goto out;
++ goto out;
++ }
+ }
+
+ list_move(&sdata->assigned_chanctx_list, &new_ctx->assigned_vifs);
+--
+2.18.0
+
diff --git a/recipes-wifi/linux-mac80211/files/patches/subsys/subsys.inc b/recipes-wifi/linux-mac80211/files/patches/subsys/subsys.inc
index d6d111d..6295da6 100644
--- a/recipes-wifi/linux-mac80211/files/patches/subsys/subsys.inc
+++ b/recipes-wifi/linux-mac80211/files/patches/subsys/subsys.inc
@@ -78,6 +78,7 @@
file://mtk-0020-cfg80211-mtk-fix-early-return-in-cfg80211_stop_backg.patch \
file://mtk-0021-cfg80211-mtk-add-background-radar-stop-when-backgrou.patch \
file://mtk-0022-mac80211-mtk-avoid-kernel-warning-of-check_flush_dep.patch \
+ file://mtk-0023-mac80211-mtk-avoid-calling-switch_vif_chanctx-when-u.patch \
file://mtk-9900-mac80211-mtk-mask-kernel-version-limitation-and-fill.patch \
file://mtk-9901-mac80211-mtk-add-fill-receive-path-ops-to-get-wed-id.patch \
file://mtk-9902-mac80211-mtk-add-support-for-letting-drivers-registe.patch \
diff --git a/recipes-wifi/linux-mt76/files/patches/0008-wifi-mt76-mt7915-fix-tx-emission-issue-during-bootup.patch b/recipes-wifi/linux-mt76/files/patches/0008-wifi-mt76-mt7915-fix-tx-emission-issue-during-bootup.patch
new file mode 100644
index 0000000..322bb3a
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches/0008-wifi-mt76-mt7915-fix-tx-emission-issue-during-bootup.patch
@@ -0,0 +1,30 @@
+From 56916977daae3317294a905950cdc604d048bddb Mon Sep 17 00:00:00 2001
+From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
+Date: Wed, 2 Aug 2023 11:26:14 +0800
+Subject: [PATCH] wifi: mt76: mt7915: fix tx emission issue during bootup after
+ applying pre-cal
+
+Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
+Reviewed-by: Shayne Chen <shayne.chen@mediatek.com>
+Reviewed-by: Evelyn Tsai <evelyn.tsai@mediatek.com>
+---
+ mt7915/mcu.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/mt7915/mcu.c b/mt7915/mcu.c
+index a34b75d..502610f 100644
+--- a/mt7915/mcu.c
++++ b/mt7915/mcu.c
+@@ -2737,7 +2737,8 @@ int mt7915_mcu_set_chan_info(struct mt7915_phy *phy, int cmd)
+
+ if (dev->mt76.hw->conf.flags & IEEE80211_CONF_MONITOR)
+ req.switch_reason = CH_SWITCH_NORMAL;
+- else if (phy->mt76->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)
++ else if (phy->mt76->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL ||
++ phy->mt76->hw->conf.flags & IEEE80211_CONF_IDLE)
+ req.switch_reason = CH_SWITCH_SCAN_BYPASS_DPD;
+ else if (cfg80211_chandef_valid(chandef) &&
+ !cfg80211_reg_can_beacon(phy->mt76->hw->wiphy, chandef,
+--
+2.18.0
+
diff --git a/recipes-wifi/linux-mt76/files/patches/0009-wifi-mt76-mt7915-fix-txpower-issues.patch b/recipes-wifi/linux-mt76/files/patches/0009-wifi-mt76-mt7915-fix-txpower-issues.patch
index 814af74..e62d287 100644
--- a/recipes-wifi/linux-mt76/files/patches/0009-wifi-mt76-mt7915-fix-txpower-issues.patch
+++ b/recipes-wifi/linux-mt76/files/patches/0009-wifi-mt76-mt7915-fix-txpower-issues.patch
@@ -1,4 +1,4 @@
-From 2016d1f146684a17c813c957b5c8bd51bd25b47f Mon Sep 17 00:00:00 2001
+From a769a5232abe1ca70f376ef90efc227c9fd56901 Mon Sep 17 00:00:00 2001
From: Evelyn Tsai <evelyn.tsai@mediatek.com>
Date: Sat, 29 Jul 2023 04:53:47 +0800
Subject: [PATCH] wifi: mt76: mt7915: fix txpower issues
@@ -8,15 +8,15 @@
mac80211.c | 2 +-
mt7915/debugfs.c | 48 ++++++++++++++++++++++++++----------------------
mt7915/init.c | 2 +-
- mt7915/main.c | 3 ++-
+ mt7915/main.c | 1 +
mt7915/mcu.h | 2 +-
- 6 files changed, 33 insertions(+), 28 deletions(-)
+ 6 files changed, 32 insertions(+), 27 deletions(-)
diff --git a/eeprom.c b/eeprom.c
-index ea54b7a..f9f048c 100644
+index 2558788..750e031 100644
--- a/eeprom.c
+++ b/eeprom.c
-@@ -283,7 +283,7 @@ s8 mt76_get_rate_power_limits(struct mt76_phy *phy,
+@@ -338,7 +338,7 @@ s8 mt76_get_rate_power_limits(struct mt76_phy *phy,
u32 ru_rates = ARRAY_SIZE(dest->ru[0]);
char band;
size_t len;
@@ -25,7 +25,7 @@
s8 txs_delta;
if (!mcs_rates)
-@@ -321,7 +321,7 @@ s8 mt76_get_rate_power_limits(struct mt76_phy *phy,
+@@ -376,7 +376,7 @@ s8 mt76_get_rate_power_limits(struct mt76_phy *phy,
if (!np)
return target_power;
@@ -145,19 +145,10 @@
int pwr_delta = mt7915_eeprom_get_power_delta(dev, sband->band);
struct mt76_power_limits limits;
diff --git a/mt7915/main.c b/mt7915/main.c
-index 86f794f..d7dfae8 100644
+index 3381325..a90ac45 100644
--- a/mt7915/main.c
+++ b/mt7915/main.c
-@@ -479,7 +479,7 @@ static int mt7915_config(struct ieee80211_hw *hw, u32 changed)
-
- mutex_lock(&dev->mt76.mutex);
-
-- if (changed & IEEE80211_CONF_CHANGE_MONITOR) {
-+ if (changed & (IEEE80211_CONF_CHANGE_MONITOR | IEEE80211_CONF_CHANGE_CHANNEL)) {
- bool enabled = !!(hw->conf.flags & IEEE80211_CONF_MONITOR);
- bool band = phy->mt76->band_idx;
-
-@@ -1062,6 +1062,7 @@ mt7915_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant)
+@@ -1063,6 +1063,7 @@ mt7915_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant)
mt76_set_stream_caps(phy->mt76, true);
mt7915_set_stream_vht_txbf_caps(phy);
mt7915_set_stream_he_caps(phy);
diff --git a/recipes-wifi/linux-mt76/files/patches/1003-wifi-mt76-mt7915-add-support-for-muru_onoff-via.patch b/recipes-wifi/linux-mt76/files/patches/1003-wifi-mt76-mt7915-add-support-for-muru_onoff-via.patch
index e2f17a1..3473003 100644
--- a/recipes-wifi/linux-mt76/files/patches/1003-wifi-mt76-mt7915-add-support-for-muru_onoff-via.patch
+++ b/recipes-wifi/linux-mt76/files/patches/1003-wifi-mt76-mt7915-add-support-for-muru_onoff-via.patch
@@ -1,31 +1,17 @@
-From dd220c1cfc8ee158895cfa31901ef625ac3a0a4d Mon Sep 17 00:00:00 2001
+From a5abc630e8bf65e4ca21bc1cf1b74db7df6cd6d1 Mon Sep 17 00:00:00 2001
From: Evelyn Tsai <evelyn.tsai@mediatek.com>
Date: Tue, 4 Apr 2023 02:23:57 +0800
Subject: [PATCH 1003/1034] wifi: mt76: mt7915: add support for muru_onoff via
---
- mt7915/init.c | 2 ++
mt7915/mcu.c | 10 ++++++++--
mt7915/mcu.h | 6 ++++++
mt7915/mt7915.h | 2 ++
mt7915/mtk_debugfs.c | 33 +++++++++++++++++++++++++++++++++
- 5 files changed, 51 insertions(+), 2 deletions(-)
+ 4 files changed, 49 insertions(+), 2 deletions(-)
-diff --git a/mt7915/init.c b/mt7915/init.c
-index 0ea2af17..361c3847 100644
---- a/mt7915/init.c
-+++ b/mt7915/init.c
-@@ -470,6 +470,8 @@ mt7915_init_wiphy(struct mt7915_phy *phy)
- mphy->leds.cdev.brightness_set = mt7915_led_set_brightness;
- mphy->leds.cdev.blink_set = mt7915_led_set_blink;
- }
-+
-+ phy->muru_onoff = OFDMA_DL | MUMIMO_UL | MUMIMO_DL;
- }
-
- static void
diff --git a/mt7915/mcu.c b/mt7915/mcu.c
-index 8994ea6a..fdb6bc5f 100644
+index 8994ea6..fdb6bc5 100644
--- a/mt7915/mcu.c
+++ b/mt7915/mcu.c
@@ -873,6 +873,7 @@ mt7915_mcu_sta_muru_tlv(struct mt7915_dev *dev, struct sk_buff *skb,
@@ -58,7 +44,7 @@
muru->mimo_dl.vht_mu_bfee =
!!(sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE);
diff --git a/mt7915/mcu.h b/mt7915/mcu.h
-index 67eac5c9..84c52d9b 100644
+index 67eac5c..84c52d9 100644
--- a/mt7915/mcu.h
+++ b/mt7915/mcu.h
@@ -666,4 +666,10 @@ struct csi_data {
@@ -73,7 +59,7 @@
+
#endif
diff --git a/mt7915/mt7915.h b/mt7915/mt7915.h
-index c733035b..bd5543b5 100644
+index c733035..bd5543b 100644
--- a/mt7915/mt7915.h
+++ b/mt7915/mt7915.h
@@ -252,6 +252,8 @@ struct mt7915_phy {
@@ -86,7 +72,7 @@
struct mt76_channel_state state_ts;
diff --git a/mt7915/mtk_debugfs.c b/mt7915/mtk_debugfs.c
-index e6796bc3..e1758edb 100644
+index e6796bc..e1758ed 100644
--- a/mt7915/mtk_debugfs.c
+++ b/mt7915/mtk_debugfs.c
@@ -2558,6 +2558,38 @@ static int mt7915_token_txd_read(struct seq_file *s, void *data)
@@ -137,5 +123,5 @@
&fops_fw_debug_module);
debugfs_create_file("fw_debug_level", 0600, dir, dev,
--
-2.39.2
+2.39.0
diff --git a/recipes-wifi/linux-mt76/files/patches/1009-wifi-mt76-testmode-additional-supports.patch b/recipes-wifi/linux-mt76/files/patches/1009-wifi-mt76-testmode-additional-supports.patch
index 182f6eb..cb5281c 100644
--- a/recipes-wifi/linux-mt76/files/patches/1009-wifi-mt76-testmode-additional-supports.patch
+++ b/recipes-wifi/linux-mt76/files/patches/1009-wifi-mt76-testmode-additional-supports.patch
@@ -1,7 +1,7 @@
-From 5048f24cdd1ddaa11edd91747a07ba3a7484e49c Mon Sep 17 00:00:00 2001
+From 333678e670a88fe48c859af6dbb357405f084a52 Mon Sep 17 00:00:00 2001
From: Shayne Chen <shayne.chen@mediatek.com>
Date: Thu, 21 Apr 2022 15:43:19 +0800
-Subject: [PATCH 1009/1034] wifi: mt76: testmode: additional supports
+Subject: [PATCH] wifi: mt76: testmode: additional supports
Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
@@ -20,16 +20,16 @@
mt7915/mmio.c | 2 +
mt7915/mt7915.h | 16 +-
mt7915/regs.h | 3 +
- mt7915/testmode.c | 1221 ++++++++++++++++++++++++++++++++++++++++++---
+ mt7915/testmode.c | 1222 ++++++++++++++++++++++++++++++++++++++++++---
mt7915/testmode.h | 278 +++++++++++
testmode.c | 282 +++++++++--
testmode.h | 75 +++
tools/fields.c | 84 +++-
tx.c | 3 +-
- 20 files changed, 2023 insertions(+), 166 deletions(-)
+ 20 files changed, 2024 insertions(+), 166 deletions(-)
diff --git a/dma.c b/dma.c
-index c9d2671d..fc92e391 100644
+index c9d2671..fc92e39 100644
--- a/dma.c
+++ b/dma.c
@@ -574,8 +574,7 @@ free:
@@ -43,7 +43,7 @@
#endif
diff --git a/mac80211.c b/mac80211.c
-index eac90b3e..ed1d659b 100644
+index eac90b3..ed1d659 100644
--- a/mac80211.c
+++ b/mac80211.c
@@ -55,6 +55,13 @@ static const struct ieee80211_channel mt76_channels_5ghz[] = {
@@ -73,7 +73,7 @@
static const struct ieee80211_channel mt76_channels_6ghz[] = {
diff --git a/mt76.h b/mt76.h
-index c2ad06a2..a5908de4 100644
+index c2ad06a..a5908de 100644
--- a/mt76.h
+++ b/mt76.h
@@ -657,6 +657,21 @@ struct mt76_testmode_ops {
@@ -235,7 +235,7 @@
static inline void mt76_testmode_reset(struct mt76_phy *phy, bool disable)
{
diff --git a/mt76_connac_mcu.c b/mt76_connac_mcu.c
-index a558c68c..74b63f0f 100644
+index a558c68..74b63f0 100644
--- a/mt76_connac_mcu.c
+++ b/mt76_connac_mcu.c
@@ -395,6 +395,7 @@ void mt76_connac_mcu_sta_basic_tlv(struct mt76_dev *dev, struct sk_buff *skb,
@@ -257,7 +257,7 @@
return;
diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h
-index 92e0b912..e3980c37 100644
+index 92e0b91..e3980c3 100644
--- a/mt76_connac_mcu.h
+++ b/mt76_connac_mcu.h
@@ -998,6 +998,7 @@ enum {
@@ -277,7 +277,7 @@
MCU_EXT_CMD_CSI_CTRL = 0xc2,
};
diff --git a/mt7915/eeprom.c b/mt7915/eeprom.c
-index 76be7308..f5ab3319 100644
+index 76be730..f5ab331 100644
--- a/mt7915/eeprom.c
+++ b/mt7915/eeprom.c
@@ -131,7 +131,7 @@ static int mt7915_eeprom_load(struct mt7915_dev *dev)
@@ -290,7 +290,7 @@
return ret;
}
diff --git a/mt7915/init.c b/mt7915/init.c
-index 361c3847..6d1c0f71 100644
+index 361c384..6d1c0f7 100644
--- a/mt7915/init.c
+++ b/mt7915/init.c
@@ -730,7 +730,7 @@ static void mt7915_init_work(struct work_struct *work)
@@ -303,7 +303,7 @@
mt7915_txbf_init(dev);
}
diff --git a/mt7915/mac.c b/mt7915/mac.c
-index 7ae34b77..6c9401dd 100644
+index 7ae34b7..6c9401d 100644
--- a/mt7915/mac.c
+++ b/mt7915/mac.c
@@ -604,16 +604,38 @@ mt7915_mac_write_txwi_tm(struct mt7915_phy *phy, __le32 *txwi,
@@ -385,7 +385,7 @@
goto out;
diff --git a/mt7915/main.c b/mt7915/main.c
-index 9b54ba1c..d7bcd5f8 100644
+index 9b54ba1..d7bcd5f 100644
--- a/mt7915/main.c
+++ b/mt7915/main.c
@@ -238,7 +238,7 @@ static int mt7915_add_interface(struct ieee80211_hw *hw,
@@ -398,7 +398,7 @@
mvif->mt76.wmm_idx += 2;
diff --git a/mt7915/mcu.c b/mt7915/mcu.c
-index 1f5f938e..6a5f204c 100644
+index 1f5f938..6a5f204 100644
--- a/mt7915/mcu.c
+++ b/mt7915/mcu.c
@@ -389,6 +389,11 @@ mt7915_mcu_rx_ext_event(struct mt7915_dev *dev, struct sk_buff *skb)
@@ -479,7 +479,7 @@
return 0;
diff --git a/mt7915/mcu.h b/mt7915/mcu.h
-index c15b4b74..99827354 100644
+index c15b4b7..9982735 100644
--- a/mt7915/mcu.h
+++ b/mt7915/mcu.h
@@ -8,10 +8,15 @@
@@ -537,7 +537,7 @@
enum {
diff --git a/mt7915/mmio.c b/mt7915/mmio.c
-index b23679ac..6505d763 100644
+index b23679a..6505d76 100644
--- a/mt7915/mmio.c
+++ b/mt7915/mmio.c
@@ -134,6 +134,7 @@ static const u32 mt7915_offs[] = {
@@ -557,7 +557,7 @@
[AGG_PCR0] = 0x040,
[AGG_ACR0] = 0x054,
diff --git a/mt7915/mt7915.h b/mt7915/mt7915.h
-index bf0f7dee..c91415f7 100644
+index bf0f7de..c91415f 100644
--- a/mt7915/mt7915.h
+++ b/mt7915/mt7915.h
@@ -272,6 +272,9 @@ struct mt7915_phy {
@@ -605,7 +605,7 @@
static inline u16 mt7915_wtbl_size(struct mt7915_dev *dev)
{
diff --git a/mt7915/regs.h b/mt7915/regs.h
-index 038596c3..428f4820 100644
+index 038596c..428f482 100644
--- a/mt7915/regs.h
+++ b/mt7915/regs.h
@@ -62,6 +62,7 @@ enum offs_rev {
@@ -626,7 +626,7 @@
(_n) * 4))
#define MT_AGG_PCR0(_band, _n) MT_WF_AGG(_band, (__OFFS(AGG_PCR0) + \
diff --git a/mt7915/testmode.c b/mt7915/testmode.c
-index 46939191..1e72bf2a 100644
+index 4693919..e5d0ef9 100644
--- a/mt7915/testmode.c
+++ b/mt7915/testmode.c
@@ -9,6 +9,9 @@
@@ -749,7 +749,7 @@
};
return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(ATE_CTRL), &req,
-@@ -182,12 +249,738 @@ mt7915_tm_set_tam_arb(struct mt7915_phy *phy, bool enable, bool mu)
+@@ -182,12 +249,739 @@ mt7915_tm_set_tam_arb(struct mt7915_phy *phy, bool enable, bool mu)
return mt7915_mcu_set_muru_ctrl(dev, MURU_SET_ARB_OP_MODE, op_mode);
}
@@ -1354,6 +1354,7 @@
+mt7915_tm_txbf_profile_update_all(struct mt7915_phy *phy, u16 *val)
+{
+ struct mt76_testmode_data *td = &phy->mt76->test;
++ u8 nss = hweight8(td->tx_antenna_mask);
+ u16 pfmu_idx = val[0];
+ u16 subc_id = val[1];
+ u16 angle11 = val[2];
@@ -1366,9 +1367,9 @@
+ if (subc_id > 63)
+ return -EINVAL;
+
-+ if (td->tx_antenna_mask == 2) {
++ if (nss == 2) {
+ phi11 = (s16)(angle21 - angle11);
-+ } else if (td->tx_antenna_mask == 3) {
++ } else if (nss == 3) {
+ phi11 = (s16)(angle31 - angle11);
+ phi21 = (s16)(angle31 - angle21);
+ } else {
@@ -1490,7 +1491,7 @@
struct edca *e = &req.edca[0];
e->queue = qid + mvif->mt76.wmm_idx * MT76_CONNAC_MAX_WMM_SETS;
-@@ -263,7 +1056,8 @@ done:
+@@ -263,7 +1057,8 @@ done:
return mt7915_tm_set_wmm_qid(phy,
mt76_connac_lmac_mapping(IEEE80211_AC_BE),
@@ -1500,7 +1501,7 @@
}
static int
-@@ -339,7 +1133,7 @@ mt7915_tm_set_tx_len(struct mt7915_phy *phy, u32 tx_time)
+@@ -339,7 +1134,7 @@ mt7915_tm_set_tx_len(struct mt7915_phy *phy, u32 tx_time)
bitrate = cfg80211_calculate_bitrate(&rate);
tx_len = bitrate * tx_time / 10 / 8;
@@ -1509,7 +1510,7 @@
if (ret)
return ret;
-@@ -458,64 +1252,227 @@ mt7915_tm_init(struct mt7915_phy *phy, bool en)
+@@ -458,64 +1253,227 @@ mt7915_tm_init(struct mt7915_phy *phy, bool en)
phy->mt76->test.flag |= MT_TM_FW_RX_COUNT;
@@ -1768,7 +1769,7 @@
mt7915_tm_set_trx(phy, TM_MAC_TX, en);
}
-@@ -544,10 +1501,6 @@ mt7915_tm_get_rx_stats(struct mt7915_phy *phy, bool clear)
+@@ -544,10 +1502,6 @@ mt7915_tm_get_rx_stats(struct mt7915_phy *phy, bool clear)
return ret;
rs_band = (struct mt7915_tm_rx_stat_band *)skb->data;
@@ -1779,7 +1780,7 @@
if (!clear) {
enum mt76_rxq_id q = req.band ? MT_RXQ_BAND1 : MT_RXQ_MAIN;
-@@ -562,13 +1515,61 @@ mt7915_tm_get_rx_stats(struct mt7915_phy *phy, bool clear)
+@@ -562,13 +1516,61 @@ mt7915_tm_get_rx_stats(struct mt7915_phy *phy, bool clear)
return 0;
}
@@ -1842,7 +1843,7 @@
/* read-clear */
mt7915_tm_get_rx_stats(phy, true);
-@@ -576,9 +1577,12 @@ mt7915_tm_set_rx_frames(struct mt7915_phy *phy, bool en)
+@@ -576,9 +1578,12 @@ mt7915_tm_set_rx_frames(struct mt7915_phy *phy, bool en)
/* clear fw count */
mt7915_tm_set_phy_count(phy, 0);
mt7915_tm_set_phy_count(phy, 1);
@@ -1857,7 +1858,7 @@
}
static int
-@@ -617,34 +1621,7 @@ mt7915_tm_set_tx_cont(struct mt7915_phy *phy, bool en)
+@@ -617,34 +1622,7 @@ mt7915_tm_set_tx_cont(struct mt7915_phy *phy, bool en)
tx_cont->tx_ant = td->tx_antenna_mask;
tx_cont->band = band;
@@ -1893,7 +1894,7 @@
if (!en) {
req.op.rf.param.func_data = cpu_to_le32(band);
-@@ -728,6 +1705,12 @@ mt7915_tm_update_params(struct mt7915_phy *phy, u32 changed)
+@@ -728,6 +1706,12 @@ mt7915_tm_update_params(struct mt7915_phy *phy, u32 changed)
mt7915_tm_set_freq_offset(phy, en, en ? td->freq_offset : 0);
if (changed & BIT(TM_CHANGED_TXPOWER))
mt7915_tm_set_tx_power(phy);
@@ -1906,7 +1907,7 @@
}
static int
-@@ -737,6 +1720,11 @@ mt7915_tm_set_state(struct mt76_phy *mphy, enum mt76_testmode_state state)
+@@ -737,6 +1721,11 @@ mt7915_tm_set_state(struct mt76_phy *mphy, enum mt76_testmode_state state)
struct mt7915_phy *phy = mphy->priv;
enum mt76_testmode_state prev_state = td->state;
@@ -1918,7 +1919,7 @@
mphy->test.state = state;
if (prev_state == MT76_TM_STATE_TX_FRAMES ||
-@@ -757,7 +1745,7 @@ mt7915_tm_set_state(struct mt76_phy *mphy, enum mt76_testmode_state state)
+@@ -757,7 +1746,7 @@ mt7915_tm_set_state(struct mt76_phy *mphy, enum mt76_testmode_state state)
(state == MT76_TM_STATE_OFF &&
prev_state == MT76_TM_STATE_IDLE)) {
u32 changed = 0;
@@ -1927,7 +1928,7 @@
for (i = 0; i < ARRAY_SIZE(tm_change_map); i++) {
u16 cur = tm_change_map[i];
-@@ -766,6 +1754,10 @@ mt7915_tm_set_state(struct mt76_phy *mphy, enum mt76_testmode_state state)
+@@ -766,6 +1755,10 @@ mt7915_tm_set_state(struct mt76_phy *mphy, enum mt76_testmode_state state)
changed |= BIT(i);
}
@@ -1938,7 +1939,7 @@
mt7915_tm_update_params(phy, changed);
}
-@@ -778,10 +1770,8 @@ mt7915_tm_set_params(struct mt76_phy *mphy, struct nlattr **tb,
+@@ -778,10 +1771,8 @@ mt7915_tm_set_params(struct mt76_phy *mphy, struct nlattr **tb,
{
struct mt76_testmode_data *td = &mphy->test;
struct mt7915_phy *phy = mphy->priv;
@@ -1951,7 +1952,7 @@
BUILD_BUG_ON(NUM_TM_CHANGED >= 32);
-@@ -789,9 +1779,9 @@ mt7915_tm_set_params(struct mt76_phy *mphy, struct nlattr **tb,
+@@ -789,9 +1780,9 @@ mt7915_tm_set_params(struct mt76_phy *mphy, struct nlattr **tb,
td->state == MT76_TM_STATE_OFF)
return 0;
@@ -1964,7 +1965,7 @@
for (i = 0; i < ARRAY_SIZE(tm_change_map); i++) {
if (tb[tm_change_map[i]])
-@@ -807,6 +1797,7 @@ static int
+@@ -807,6 +1798,7 @@ static int
mt7915_tm_dump_stats(struct mt76_phy *mphy, struct sk_buff *msg)
{
struct mt7915_phy *phy = mphy->priv;
@@ -1972,7 +1973,7 @@
void *rx, *rssi;
int i;
-@@ -852,11 +1843,75 @@ mt7915_tm_dump_stats(struct mt76_phy *mphy, struct sk_buff *msg)
+@@ -852,11 +1844,75 @@ mt7915_tm_dump_stats(struct mt76_phy *mphy, struct sk_buff *msg)
nla_nest_end(msg, rx);
@@ -2049,7 +2050,7 @@
+ .set_eeprom = mt7915_tm_set_eeprom,
};
diff --git a/mt7915/testmode.h b/mt7915/testmode.h
-index a1c54c89..eb0e0432 100644
+index a1c54c8..eb0e043 100644
--- a/mt7915/testmode.h
+++ b/mt7915/testmode.h
@@ -4,6 +4,8 @@
@@ -2364,7 +2365,7 @@
+
#endif
diff --git a/testmode.c b/testmode.c
-index 1b37392c..d2cef5b9 100644
+index 1b37392..d2cef5b 100644
--- a/testmode.c
+++ b/testmode.c
@@ -28,28 +28,16 @@ const struct nla_policy mt76_tm_policy[NUM_MT76_TM_ATTRS] = {
@@ -2837,7 +2838,7 @@
if (mt76_testmode_param_present(td, MT76_TM_ATTR_TX_POWER)) {
diff --git a/testmode.h b/testmode.h
-index 89613266..8c55fa0f 100644
+index 8961326..8c55fa0 100644
--- a/testmode.h
+++ b/testmode.h
@@ -6,6 +6,8 @@
@@ -2942,7 +2943,7 @@
+
#endif
diff --git a/tools/fields.c b/tools/fields.c
-index e3f69089..7e564a3b 100644
+index e3f6908..7e564a3 100644
--- a/tools/fields.c
+++ b/tools/fields.c
@@ -10,6 +10,7 @@ static const char * const testmode_state[] = {
@@ -3083,7 +3084,7 @@
};
diff --git a/tx.c b/tx.c
-index 6cc26cc6..5d7bf340 100644
+index 6cc26cc..5d7bf34 100644
--- a/tx.c
+++ b/tx.c
@@ -259,8 +259,7 @@ void __mt76_tx_complete_skb(struct mt76_dev *dev, u16 wcid_idx, struct sk_buff *
@@ -3097,5 +3098,5 @@
wake_up(&dev->tx_wait);
--
-2.39.2
+2.18.0
diff --git a/recipes-wifi/linux-mt76/files/patches/1013-wifi-mt76-testmode-add-iBF-eBF-cal-and-cert-commands.patch b/recipes-wifi/linux-mt76/files/patches/1013-wifi-mt76-testmode-add-iBF-eBF-cal-and-cert-commands.patch
index eac1cfe..f88823a 100644
--- a/recipes-wifi/linux-mt76/files/patches/1013-wifi-mt76-testmode-add-iBF-eBF-cal-and-cert-commands.patch
+++ b/recipes-wifi/linux-mt76/files/patches/1013-wifi-mt76-testmode-add-iBF-eBF-cal-and-cert-commands.patch
@@ -1,8 +1,8 @@
-From 4bffcebdfcad62a1c6741c2bb7d4c023adf360d2 Mon Sep 17 00:00:00 2001
+From 7598ccc4626d9d41807a59fa8304649a7260b9ed Mon Sep 17 00:00:00 2001
From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
Date: Thu, 15 Dec 2022 19:45:18 +0800
-Subject: [PATCH 1013/1034] wifi: mt76: testmode: add iBF/eBF cal and cert
- commands with golden
+Subject: [PATCH] wifi: mt76: testmode: add iBF/eBF cal and cert commands with
+ golden
Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
---
@@ -17,15 +17,15 @@
mt7915/mtk_debugfs.c | 35 ++++
mt7915/mtk_mcu.c | 246 ++++++++++++++++++++++-
mt7915/regs.h | 4 +
- mt7915/testmode.c | 460 ++++++++++++++++++++++++++++---------------
+ mt7915/testmode.c | 461 ++++++++++++++++++++++++++++---------------
mt7915/testmode.h | 134 +------------
testmode.c | 1 +
testmode.h | 9 +
tools/fields.c | 9 +
- 16 files changed, 856 insertions(+), 324 deletions(-)
+ 16 files changed, 857 insertions(+), 324 deletions(-)
diff --git a/mt76.h b/mt76.h
-index 75b28748..af29bdeb 100644
+index 75b2874..af29bde 100644
--- a/mt76.h
+++ b/mt76.h
@@ -703,6 +703,7 @@ struct mt76_testmode_data {
@@ -47,7 +47,7 @@
u32 tx_pending;
u32 tx_queued;
diff --git a/mt76_connac_mcu.c b/mt76_connac_mcu.c
-index 74b63f0f..e6b468c4 100644
+index 74b63f0..e6b468c 100644
--- a/mt76_connac_mcu.c
+++ b/mt76_connac_mcu.c
@@ -2767,6 +2767,7 @@ int mt76_connac_mcu_bss_basic_tlv(struct sk_buff *skb,
@@ -68,7 +68,7 @@
memcpy(bss->bssid, phy->macaddr, ETH_ALEN);
}
diff --git a/mt7915/mac.c b/mt7915/mac.c
-index 6c9401dd..1e0bee7b 100644
+index 6c9401d..1e0bee7 100644
--- a/mt7915/mac.c
+++ b/mt7915/mac.c
@@ -729,8 +729,10 @@ mt7915_mac_write_txwi_tm(struct mt7915_phy *phy, __le32 *txwi,
@@ -84,7 +84,7 @@
txwi[6] |= cpu_to_le32(val);
#endif
diff --git a/mt7915/main.c b/mt7915/main.c
-index d7bcd5f8..9694bd71 100644
+index d7bcd5f..9694bd7 100644
--- a/mt7915/main.c
+++ b/mt7915/main.c
@@ -205,46 +205,37 @@ static void mt7915_init_bitrate_mask(struct ieee80211_vif *vif)
@@ -175,7 +175,7 @@
return ret;
diff --git a/mt7915/mcu.c b/mt7915/mcu.c
-index 020780d3..c8b97e89 100644
+index 020780d..c8b97e8 100644
--- a/mt7915/mcu.c
+++ b/mt7915/mcu.c
@@ -199,6 +199,7 @@ mt7915_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb,
@@ -254,7 +254,7 @@
return -EINVAL;
}
diff --git a/mt7915/mcu.h b/mt7915/mcu.h
-index f4c3bf4e..c95d9900 100644
+index f4c3bf4..c95d990 100644
--- a/mt7915/mcu.h
+++ b/mt7915/mcu.h
@@ -531,10 +531,12 @@ enum {
@@ -448,7 +448,7 @@
MURU_SET_ARB_OP_MODE = 14,
MURU_SET_PLATFORM_TYPE = 25,
diff --git a/mt7915/mmio.c b/mt7915/mmio.c
-index 6505d763..25c3fe2b 100644
+index 6505d76..25c3fe2 100644
--- a/mt7915/mmio.c
+++ b/mt7915/mmio.c
@@ -133,6 +133,7 @@ static const u32 mt7915_offs[] = {
@@ -468,7 +468,7 @@
[AGG_AALCR0] = 0x028,
[AGG_AWSCR0] = 0x030,
diff --git a/mt7915/mt7915.h b/mt7915/mt7915.h
-index 88e45298..4572066b 100644
+index 88e4529..4572066 100644
--- a/mt7915/mt7915.h
+++ b/mt7915/mt7915.h
@@ -274,7 +274,6 @@ struct mt7915_phy {
@@ -520,7 +520,7 @@
+
#endif
diff --git a/mt7915/mtk_debugfs.c b/mt7915/mtk_debugfs.c
-index 9bb6dd05..6d9d009d 100644
+index 9bb6dd0..6d9d009 100644
--- a/mt7915/mtk_debugfs.c
+++ b/mt7915/mtk_debugfs.c
@@ -2892,6 +2892,36 @@ mt7915_txpower_level_set(void *data, u64 val)
@@ -573,7 +573,7 @@
return 0;
diff --git a/mt7915/mtk_mcu.c b/mt7915/mtk_mcu.c
-index 143dae26..906c8725 100644
+index 143dae2..906c872 100644
--- a/mt7915/mtk_mcu.c
+++ b/mt7915/mtk_mcu.c
@@ -1,9 +1,10 @@
@@ -836,7 +836,7 @@
+}
+#endif
diff --git a/mt7915/regs.h b/mt7915/regs.h
-index 482b3fee..44da7b82 100644
+index 482b3fe..44da7b8 100644
--- a/mt7915/regs.h
+++ b/mt7915/regs.h
@@ -61,6 +61,7 @@ enum offs_rev {
@@ -858,7 +858,7 @@
#define MT_WF_RMAC_BASE(_band) ((_band) ? 0x820f5000 : 0x820e5000)
#define MT_WF_RMAC(_band, ofs) (MT_WF_RMAC_BASE(_band) + (ofs))
diff --git a/mt7915/testmode.c b/mt7915/testmode.c
-index 2e51dcd5..fafe9095 100644
+index e321848..d5c74df 100644
--- a/mt7915/testmode.c
+++ b/mt7915/testmode.c
@@ -53,6 +53,8 @@ struct reg_band {
@@ -1262,7 +1262,7 @@
} else {
tag->t1.row_id1 = 4;
tag->t1.row_id2 = 5;
-@@ -780,6 +876,19 @@ mt7915_tm_txbf_profile_update(struct mt7915_phy *phy, u16 *val, bool ebf)
+@@ -780,6 +876,20 @@ mt7915_tm_txbf_profile_update(struct mt7915_phy *phy, u16 *val, bool ebf)
if (ret)
return ret;
@@ -1273,7 +1273,8 @@
+ mt76_rr(dev, MT_ARB_TQSAXM0(phy->mt76->band_idx)));
+ } else if (!td->ebf && ebf) {
+ /* iBF's ebf profile update */
-+ mt76_set(dev, MT_ARB_TQSAXM0(phy->mt76->band_idx), MT_ARB_IBF_ENABLE);
++ if (!is_mt7915(&dev->mt76) || !dev->dbdc_support)
++ mt76_set(dev, MT_ARB_TQSAXM0(phy->mt76->band_idx), MT_ARB_IBF_ENABLE);
+ dev_info(dev->mt76.dev, "Set TX queue start CR for AX management (0x%x) = 0x%x\n",
+ MT_ARB_TQSAXM0(phy->mt76->band_idx),
+ mt76_rr(dev, MT_ARB_TQSAXM0(phy->mt76->band_idx)));
@@ -1282,7 +1283,7 @@
if (!ebf && is_atenl)
return mt7915_tm_txbf_apply_tx(phy, 1, false, true, true);
-@@ -797,7 +906,7 @@ mt7915_tm_txbf_phase_cal(struct mt7915_phy *phy, u16 *val)
+@@ -797,7 +907,7 @@ mt7915_tm_txbf_phase_cal(struct mt7915_phy *phy, u16 *val)
u8 category;
u8 group_l_m_n;
u8 group;
@@ -1291,7 +1292,7 @@
u8 cal_type;
u8 lna_gain_level;
u8 _rsv[2];
-@@ -805,12 +914,12 @@ mt7915_tm_txbf_phase_cal(struct mt7915_phy *phy, u16 *val)
+@@ -805,12 +915,12 @@ mt7915_tm_txbf_phase_cal(struct mt7915_phy *phy, u16 *val)
.category = MT_BF_PHASE_CAL,
.group = val[0],
.group_l_m_n = val[1],
@@ -1307,7 +1308,7 @@
phase[req.group].status = 0;
-@@ -818,53 +927,10 @@ mt7915_tm_txbf_phase_cal(struct mt7915_phy *phy, u16 *val)
+@@ -818,53 +928,10 @@ mt7915_tm_txbf_phase_cal(struct mt7915_phy *phy, u16 *val)
sizeof(req), true);
}
@@ -1360,9 +1361,9 @@
{
+#define MT7915_TXBF_PFMU_DATA_LEN (MT7915_TXBF_SUBCAR_NUM * sizeof(struct mt7915_pfmu_data))
struct mt76_testmode_data *td = &phy->mt76->test;
+ u8 nss = hweight8(td->tx_antenna_mask);
u16 pfmu_idx = val[0];
- u16 subc_id = val[1];
-@@ -873,9 +939,9 @@ mt7915_tm_txbf_profile_update_all(struct mt7915_phy *phy, u16 *val)
+@@ -874,9 +941,9 @@ mt7915_tm_txbf_profile_update_all(struct mt7915_phy *phy, u16 *val)
u16 angle31 = val[4];
u16 angle41 = val[5];
s16 phi11 = 0, phi21 = 0, phi31 = 0;
@@ -1373,8 +1374,8 @@
+ if (subc_id > MT7915_TXBF_SUBCAR_NUM - 1)
return -EINVAL;
- if (td->tx_antenna_mask == 2) {
-@@ -889,7 +955,7 @@ mt7915_tm_txbf_profile_update_all(struct mt7915_phy *phy, u16 *val)
+ if (nss == 2) {
+@@ -890,7 +957,7 @@ mt7915_tm_txbf_profile_update_all(struct mt7915_phy *phy, u16 *val)
phi31 = (s16)(angle41 - angle31);
}
@@ -1383,7 +1384,7 @@
pfmu_data = &pfmu_data[subc_id];
if (subc_id < 32)
-@@ -899,21 +965,21 @@ mt7915_tm_txbf_profile_update_all(struct mt7915_phy *phy, u16 *val)
+@@ -900,21 +967,21 @@ mt7915_tm_txbf_profile_update_all(struct mt7915_phy *phy, u16 *val)
pfmu_data->phi11 = cpu_to_le16(phi11);
pfmu_data->phi21 = cpu_to_le16(phi21);
pfmu_data->phi31 = cpu_to_le16(phi31);
@@ -1408,7 +1409,7 @@
return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(TXBF_ACTION),
&req, sizeof(req), true);
-@@ -925,7 +991,7 @@ mt7915_tm_txbf_profile_update_all(struct mt7915_phy *phy, u16 *val)
+@@ -926,7 +993,7 @@ mt7915_tm_txbf_profile_update_all(struct mt7915_phy *phy, u16 *val)
static int
mt7915_tm_txbf_e2p_update(struct mt7915_phy *phy)
{
@@ -1417,7 +1418,7 @@
struct mt7915_dev *dev = phy->dev;
u8 *eeprom = dev->mt76.eeprom.data;
u16 offset;
-@@ -935,7 +1001,7 @@ mt7915_tm_txbf_e2p_update(struct mt7915_phy *phy)
+@@ -936,7 +1003,7 @@ mt7915_tm_txbf_e2p_update(struct mt7915_phy *phy)
is_7976 = mt7915_check_adie(dev, false) || is_mt7916(&dev->mt76);
offset = is_7976 ? 0x60a : 0x651;
@@ -1426,7 +1427,7 @@
for (i = 0; i < MAX_PHASE_GROUP_NUM; i++) {
p = &phase[i];
-@@ -950,17 +1016,75 @@ mt7915_tm_txbf_e2p_update(struct mt7915_phy *phy)
+@@ -951,17 +1018,75 @@ mt7915_tm_txbf_e2p_update(struct mt7915_phy *phy)
return 0;
}
@@ -1504,7 +1505,7 @@
return mt7915_tm_txbf_init(phy, val);
case MT76_TM_TXBF_ACT_UPDATE_CH:
mt7915_tm_update_channel(phy);
-@@ -986,6 +1110,36 @@ mt7915_tm_set_txbf(struct mt7915_phy *phy)
+@@ -987,6 +1112,36 @@ mt7915_tm_set_txbf(struct mt7915_phy *phy)
return mt7915_tm_txbf_apply_tx(phy, wlan_idx, ebf, ibf, phase_cal);
}
@@ -1541,7 +1542,7 @@
default:
break;
};
-@@ -1261,9 +1415,10 @@ mt7915_tm_set_ipi(struct mt7915_phy *phy)
+@@ -1262,9 +1417,10 @@ mt7915_tm_set_ipi(struct mt7915_phy *phy)
static int
mt7915_tm_set_wmm_qid(struct mt7915_phy *phy, u8 qid, u8 aifs, u8 cw_min,
@@ -1554,7 +1555,7 @@
struct mt7915_mcu_tx req = {
.valid = true,
.mode = tx_cmd,
-@@ -1271,6 +1426,9 @@ mt7915_tm_set_wmm_qid(struct mt7915_phy *phy, u8 qid, u8 aifs, u8 cw_min,
+@@ -1272,6 +1428,9 @@ mt7915_tm_set_wmm_qid(struct mt7915_phy *phy, u8 qid, u8 aifs, u8 cw_min,
};
struct edca *e = &req.edca[0];
@@ -1564,7 +1565,7 @@
e->queue = qid + mvif->mt76.wmm_idx * MT76_CONNAC_MAX_WMM_SETS;
e->set = WMM_PARAM_SET;
-@@ -1283,17 +1441,19 @@ mt7915_tm_set_wmm_qid(struct mt7915_phy *phy, u8 qid, u8 aifs, u8 cw_min,
+@@ -1284,17 +1443,19 @@ mt7915_tm_set_wmm_qid(struct mt7915_phy *phy, u8 qid, u8 aifs, u8 cw_min,
}
static int
@@ -1585,7 +1586,7 @@
u8 band = phy->mt76->band_idx;
u32 i2t_time, tr2t_time, txv_time;
u16 cw = 0;
-@@ -1307,6 +1467,7 @@ mt7915_tm_set_ipg_params(struct mt7915_phy *phy, u32 ipg, u8 mode)
+@@ -1308,6 +1469,7 @@ mt7915_tm_set_ipg_params(struct mt7915_phy *phy, u32 ipg, u8 mode)
ipg -= sig_ext;
if (ipg <= (TM_MAX_SIFS + slot_time)) {
@@ -1593,7 +1594,7 @@
sifs = ipg - slot_time;
} else {
u32 val = (ipg + slot_time) / slot_time;
-@@ -1342,10 +1503,12 @@ done:
+@@ -1343,10 +1505,12 @@ done:
mt7915_tm_set_slot_time(phy, slot_time, sifs);
@@ -1608,7 +1609,7 @@
}
static int
-@@ -1544,7 +1707,7 @@ mt7915_tm_init(struct mt7915_phy *phy, bool en)
+@@ -1545,7 +1709,7 @@ mt7915_tm_init(struct mt7915_phy *phy, bool en)
phy->mt76->test.aid = 0;
phy->mt76->test.tx_mpdu_len = 0;
@@ -1617,7 +1618,7 @@
mt7915_tm_set_entry(phy);
} else {
INIT_DELAYED_WORK(&phy->ipi_work, mt7915_tm_ipi_work);
-@@ -1729,7 +1892,7 @@ mt7915_tm_set_tx_frames(struct mt7915_phy *phy, bool en)
+@@ -1730,7 +1894,7 @@ mt7915_tm_set_tx_frames(struct mt7915_phy *phy, bool en)
u32 tx_time = td->tx_time, ipg = td->tx_ipg;
u8 duty_cycle = td->tx_duty_cycle;
@@ -1626,7 +1627,7 @@
mt7915_tm_update_channel(phy);
if (td->tx_spe_idx)
-@@ -1744,7 +1907,7 @@ mt7915_tm_set_tx_frames(struct mt7915_phy *phy, bool en)
+@@ -1745,7 +1909,7 @@ mt7915_tm_set_tx_frames(struct mt7915_phy *phy, bool en)
if (duty_cycle < 100)
tx_time = duty_cycle * ipg / (100 - duty_cycle);
}
@@ -1635,7 +1636,7 @@
mt7915_tm_set_tx_len(phy, tx_time);
if (ipg)
-@@ -1763,6 +1926,9 @@ mt7915_tm_set_tx_frames(struct mt7915_phy *phy, bool en)
+@@ -1764,6 +1928,9 @@ mt7915_tm_set_tx_frames(struct mt7915_phy *phy, bool en)
mt7915_tm_tx_frames_mu(phy, en);
mt7915_tm_set_trx(phy, TM_MAC_TX, en);
@@ -1645,7 +1646,7 @@
}
static int
-@@ -1854,7 +2020,7 @@ mt7915_tm_set_rx_frames(struct mt7915_phy *phy, bool en)
+@@ -1855,7 +2022,7 @@ mt7915_tm_set_rx_frames(struct mt7915_phy *phy, bool en)
mt7915_tm_set_trx(phy, TM_MAC_RX_RXV, false);
if (en) {
@@ -1654,7 +1655,7 @@
mt7915_tm_update_channel(phy);
if (td->aid)
mt7915_tm_set_rx_user_idx(phy, td->aid);
-@@ -1871,6 +2037,9 @@ mt7915_tm_set_rx_frames(struct mt7915_phy *phy, bool en)
+@@ -1872,6 +2039,9 @@ mt7915_tm_set_rx_frames(struct mt7915_phy *phy, bool en)
mt7915_tm_set_muru_aid(phy, en ? td->aid : 0xf800);
mt7915_tm_set_trx(phy, TM_MAC_RX_RXV, en);
@@ -1664,7 +1665,7 @@
}
static int
-@@ -1930,34 +2099,7 @@ mt7915_tm_set_tx_cont(struct mt7915_phy *phy, bool en)
+@@ -1931,34 +2101,7 @@ mt7915_tm_set_tx_cont(struct mt7915_phy *phy, bool en)
rate_idx = sband->bitrates[idx].hw_value & 0xff;
}
@@ -1701,7 +1702,7 @@
rateval = mode << 6 | rate_idx;
tx_cont->rateval = cpu_to_le16(rateval);
diff --git a/mt7915/testmode.h b/mt7915/testmode.h
-index 75698261..5aba13cf 100644
+index 7569826..5aba13c 100644
--- a/mt7915/testmode.h
+++ b/mt7915/testmode.h
@@ -311,137 +311,7 @@ struct mt7915_tm_muru {
@@ -1845,7 +1846,7 @@
#endif
diff --git a/testmode.c b/testmode.c
-index babae8d4..4ea58777 100644
+index babae8d..4ea5877 100644
--- a/testmode.c
+++ b/testmode.c
@@ -195,6 +195,7 @@ mt76_testmode_alloc_skb(struct mt76_phy *phy, u32 len,
@@ -1857,7 +1858,7 @@
memcpy(hdr->addr2, addr[1], ETH_ALEN);
memcpy(hdr->addr3, addr[2], ETH_ALEN);
diff --git a/testmode.h b/testmode.h
-index 97e75964..e13920ec 100644
+index 97e7596..e13920e 100644
--- a/testmode.h
+++ b/testmode.h
@@ -299,7 +299,10 @@ enum mt76_testmode_cfg {
@@ -1885,7 +1886,7 @@
/* keep last */
NUM_MT76_TM_TXBF_ACT,
diff --git a/tools/fields.c b/tools/fields.c
-index fc01043e..7caacb94 100644
+index fc01043..7caacb9 100644
--- a/tools/fields.c
+++ b/tools/fields.c
@@ -33,7 +33,10 @@ static const char * const testmode_tx_mode[] = {
@@ -1913,5 +1914,5 @@
static const char * const testmode_offchan_bw[] = {
--
-2.39.2
+2.18.0
diff --git a/recipes-wifi/linux-mt76/files/patches/1035-wifi-mt76-mt7915-Establish-BA-in-VO-queue.patch b/recipes-wifi/linux-mt76/files/patches/1035-wifi-mt76-mt7915-Establish-BA-in-VO-queue.patch
new file mode 100644
index 0000000..a6eb593
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches/1035-wifi-mt76-mt7915-Establish-BA-in-VO-queue.patch
@@ -0,0 +1,25 @@
+From faa6a52a5f0429d401b7615cc34734c6f5b8fe01 Mon Sep 17 00:00:00 2001
+From: MeiChia Chiu <meichia.chiu@mediatek.com>
+Date: Tue, 8 Aug 2023 11:20:58 +0800
+Subject: [PATCH] wifi: mt76: mt7915: Establish BA in VO queue
+
+---
+ mt76_connac_mac.c | 2 --
+ 1 file changed, 2 deletions(-)
+
+diff --git a/mt76_connac_mac.c b/mt76_connac_mac.c
+index ff3cefa..b87b733 100644
+--- a/mt76_connac_mac.c
++++ b/mt76_connac_mac.c
+@@ -1126,8 +1126,6 @@ void mt76_connac2_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi)
+ return;
+
+ tid = le32_get_bits(txwi[1], MT_TXD1_TID);
+- if (tid >= 6) /* skip VO queue */
+- return;
+
+ val = le32_to_cpu(txwi[2]);
+ fc = FIELD_GET(MT_TXD2_FRAME_TYPE, val) << 2 |
+--
+2.39.0
+
diff --git a/recipes-wifi/linux-mt76/files/patches/patches.inc b/recipes-wifi/linux-mt76/files/patches/patches.inc
index 693e0a0..a6fede3 100644
--- a/recipes-wifi/linux-mt76/files/patches/patches.inc
+++ b/recipes-wifi/linux-mt76/files/patches/patches.inc
@@ -8,6 +8,7 @@
file://0005-wifi-mt76-mt7915-add-pc-stack-dump-for-WM-s-coredump.patch \
file://0006-wifi-mt76-mt7915-update-mpdu-density-in-2-5g-capabil.patch \
file://0007-wifi-mt76-mt7915-move-temperature-margin-check-to-mt.patch \
+ file://0008-wifi-mt76-mt7915-fix-tx-emission-issue-during-bootup.patch \
file://0009-wifi-mt76-mt7915-fix-txpower-issues.patch \
file://0010-wifi-mt76-mt7915-rework-init-txpower.patch \
file://0999-wifi-mt76-mt7915-build-pass-for-Linux-Kernel-5.4-fix.patch \
@@ -46,6 +47,7 @@
file://1032-wifi-mt76-mt7915-remove-BW160-support.patch \
file://1033-wifi-mt76-mt7915-add-txpower-info-dump-support.patch \
file://1034-wifi-mt76-mt7915-report-tx-and-rx-byte-to-tpt_led-wh.patch \
+ file://1035-wifi-mt76-mt7915-Establish-BA-in-VO-queue.patch \
file://2000-wifi-mt76-mt7915-wed-add-wed-tx-support.patch \
file://2001-wifi-mt76-mt7915-wed-add-wds-support-when-wed-is-ena.patch \
file://2002-wifi-mt76-mt7915-wed-add-fill-receive-path-to-report.patch \
diff --git a/recipes-wifi/ubus/ubus_git.bb b/recipes-wifi/ubus/ubus_git.bb
index 3e99c98..3b4ce84 100644
--- a/recipes-wifi/ubus/ubus_git.bb
+++ b/recipes-wifi/ubus/ubus_git.bb
@@ -10,7 +10,7 @@
file://0001-lua5.3-support.patch \
"
-SRCREV = "9913aa61de739e3efe067a2d186021c20bcd65e2"
+SRCREV = "f787c97b34894a38b15599886cacbca01271684f"
PV = "git${SRCPV}"
diff --git a/recipes-wifi/ucode/files/0001-change-cmakelist.patch b/recipes-wifi/ucode/files/0001-change-cmakelist.patch
new file mode 100644
index 0000000..2770833
--- /dev/null
+++ b/recipes-wifi/ucode/files/0001-change-cmakelist.patch
@@ -0,0 +1,15 @@
+diff --git a/CMakeLists.txt b/CMakeLists.txt
+index d8dd34a..07e37a5 100644
+--- a/CMakeLists.txt
++++ b/CMakeLists.txt
+@@ -23,8 +23,8 @@ OPTION(FS_SUPPORT "Filesystem plugin support" ON)
+ OPTION(MATH_SUPPORT "Math plugin support" ON)
+ OPTION(UBUS_SUPPORT "Ubus plugin support" ON)
+ OPTION(UCI_SUPPORT "UCI plugin support" ON)
+-OPTION(RTNL_SUPPORT "Route Netlink plugin support" ${LINUX})
+-OPTION(NL80211_SUPPORT "Wireless Netlink plugin support" ${LINUX})
++OPTION(RTNL_SUPPORT "Route Netlink plugin support" ON)
++OPTION(NL80211_SUPPORT "Wireless Netlink plugin support" ON)
+ OPTION(RESOLV_SUPPORT "NS resolve plugin support" ON)
+ OPTION(STRUCT_SUPPORT "Struct plugin support" ON)
+ OPTION(ULOOP_SUPPORT "Uloop plugin support" ON)
diff --git a/recipes-wifi/ucode/ucode_git.bb b/recipes-wifi/ucode/ucode_git.bb
new file mode 100644
index 0000000..a2a3ce7
--- /dev/null
+++ b/recipes-wifi/ucode/ucode_git.bb
@@ -0,0 +1,40 @@
+DESCRIPTION = "Tiny scripting and templating language"
+SECTION = "lang"
+LICENSE_NAME = "ISC"
+LICENSE = "${LICENSE_NAME}"
+LIC_FILES_CHKSUM = "file://LICENSE;md5=b42eb47dc3802282b0d1be1bc8f5336c"
+
+SRC_URI = " \
+ git://git@github.com/jow-/ucode.git;protocol=https \
+ file://0001-change-cmakelist.patch \
+"
+
+SRCREV = "c7d84aae09691a99ae3db427c0b2463732ef84f4"
+PV = "git${SRCPV}"
+
+S = "${WORKDIR}/git"
+
+
+DEPENDS += "libnl-tiny libubox ubus uci"
+
+INSANE_SKIP_${PN} += "file-rdeps dev-deps dev-so"
+FILES_SOLIBSDEV = ""
+
+FILES_${PN}-dev = "${includedir}/*"
+FILES_${PN} = "${bindir}/ucode ${libdir}/libucode.so* ${libdir}/ucode/*"
+
+inherit cmake pkgconfig python3native
+
+
+EXTRA_OECMAKE = "\
+ -DFS_SUPPORT=ON \
+ -DMATH_SUPPORT=ON \
+ -DNL80211_SUPPORT=ON \
+ -DRESOLV_SUPPORT=ON \
+ -DRTNL_SUPPORT=ON \
+ -DSTRUCT_SUPPORT=ON \
+ -DUBUS_SUPPORT=OFF \
+ -DUCI_SUPPORT=ON \
+ -DULOOP_SUPPORT=ON \
+ "
+
diff --git a/recipes-wifi/wpa-supplicant/files/002-rdkb-add-ucode-support.patch b/recipes-wifi/wpa-supplicant/files/002-rdkb-add-ucode-support.patch
new file mode 100644
index 0000000..16e099a
--- /dev/null
+++ b/recipes-wifi/wpa-supplicant/files/002-rdkb-add-ucode-support.patch
@@ -0,0 +1,21 @@
+--- a/hostapd/Makefile 2023-08-14 14:07:55.808647300 +0800
++++ b/hostapd/Makefile 2023-08-14 14:09:14.222019605 +0800
+@@ -182,6 +182,7 @@
+ OBJS += ../src/utils/ucode.o
+ OBJS += ../src/ap/ucode.o
+ NEED_ULOOP:=y
++LIBS += -lblobmsg_json -lucode
+ endif
+
+ ifdef NEED_ULOOP
+
+--- a/wpa_supplicant/Makefile 2023-08-14 17:51:44.351944100 +0800
++++ b/wpa_supplicant/Makefile 2023-08-14 17:54:54.232111091 +0800
+@@ -206,6 +206,7 @@
+ OBJS += ../src/utils/ucode.o
+ OBJS += ucode.o
+ NEED_ULOOP:=y
++LIBS += -lblobmsg_json -lucode
+ endif
+
+ ifdef NEED_ULOOP
\ No newline at end of file
diff --git a/recipes-wifi/hostapd/files/patches-2.10.3/mtk-0029-hostapd-mtk-Fix-CCA-issue.patch b/recipes-wifi/wpa-supplicant/files/patches-2.10.3/180-BSS-coloring-fix-CCA-with-multiple-BSS.patch
similarity index 66%
copy from recipes-wifi/hostapd/files/patches-2.10.3/mtk-0029-hostapd-mtk-Fix-CCA-issue.patch
copy to recipes-wifi/wpa-supplicant/files/patches-2.10.3/180-BSS-coloring-fix-CCA-with-multiple-BSS.patch
index 7196118..7b0435a 100644
--- a/recipes-wifi/hostapd/files/patches-2.10.3/mtk-0029-hostapd-mtk-Fix-CCA-issue.patch
+++ b/recipes-wifi/wpa-supplicant/files/patches-2.10.3/180-BSS-coloring-fix-CCA-with-multiple-BSS.patch
@@ -1,23 +1,32 @@
-From ce585467d784d1015b5a40ec09895d0949690b04 Mon Sep 17 00:00:00 2001
-From: Michael Lee <michael-cy.lee@mediatek.com>
-Date: Wed, 3 May 2023 14:55:18 +0800
-Subject: [PATCH 29/32] hostapd: mtk: Fix CCA issue
+From: Felix Fietkau <nbd@nbd.name>
+Date: Mon, 7 Aug 2023 21:55:57 +0200
+Subject: [PATCH] BSS coloring: fix CCA with multiple BSS
-When receiving CCA-related nl80211 commands, hostapd used to work on
-struct wpa_driver_nl80211_data, whose ctx always points to
-hostpad_iface->bss[0]. However, CCA commands are sent on a per-BSS based.
-This patch makes hostapd handle CCA-related commands on a per-BSS based.
+Pass bss->ctx instead of drv->ctx in order to avoid multiple reports for
+the first bss. The first report would otherwise clear hapd->cca_color and
+subsequent reports would cause the iface bss color to be set to 0.
+In order to avoid any issues with cancellations, only overwrite the color
+based on hapd->cca_color if it was actually set.
-Signed-off-by: Michael Lee <michael-cy.lee@mediatek.com>
+Fixes: 33c4dd26cd11 ("BSS coloring: Handle the collision and CCA events coming from the kernel")
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
- src/drivers/driver_nl80211_event.c | 24 ++++++++++++------------
- 1 file changed, 12 insertions(+), 12 deletions(-)
-diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c
-index 3d0d9b7bb..ab988fad7 100644
+--- a/src/ap/drv_callbacks.c
++++ b/src/ap/drv_callbacks.c
+@@ -2260,7 +2260,8 @@ void wpa_supplicant_event(void *ctx, enu
+ case EVENT_CCA_NOTIFY:
+ wpa_printf(MSG_DEBUG, "CCA finished on on %s",
+ hapd->conf->iface);
+- hapd->iface->conf->he_op.he_bss_color = hapd->cca_color;
++ if (hapd->cca_color)
++ hapd->iface->conf->he_op.he_bss_color = hapd->cca_color;
+ hostapd_cleanup_cca_params(hapd);
+ break;
+ #endif /* CONFIG_IEEE80211AX */
--- a/src/drivers/driver_nl80211_event.c
+++ b/src/drivers/driver_nl80211_event.c
-@@ -3662,7 +3662,7 @@ static void nl80211_assoc_comeback(struct wpa_driver_nl80211_data *drv,
+@@ -3653,7 +3653,7 @@ static void nl80211_assoc_comeback(struc
#ifdef CONFIG_IEEE80211AX
@@ -26,7 +35,7 @@
struct nlattr *tb[])
{
union wpa_event_data data;
-@@ -3676,37 +3676,37 @@ static void nl80211_obss_color_collision(struct wpa_driver_nl80211_data *drv,
+@@ -3667,37 +3667,37 @@ static void nl80211_obss_color_collision
wpa_printf(MSG_DEBUG, "nl80211: BSS color collision - bitmap %08llx",
(long long unsigned int) data.bss_color_collision.bitmap);
@@ -71,7 +80,7 @@
}
#endif /* CONFIG_IEEE80211AX */
-@@ -3968,16 +3968,16 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd,
+@@ -3957,16 +3957,16 @@ static void do_process_drv_event(struct
break;
#ifdef CONFIG_IEEE80211AX
case NL80211_CMD_OBSS_COLOR_COLLISION:
@@ -92,6 +101,3 @@
break;
#endif /* CONFIG_IEEE80211AX */
default:
---
-2.39.2
-
diff --git a/recipes-wifi/wpa-supplicant/files/patches-2.10.3/200-multicall.patch b/recipes-wifi/wpa-supplicant/files/patches-2.10.3/200-multicall.patch
index f7e797a..8ebbed0 100644
--- a/recipes-wifi/wpa-supplicant/files/patches-2.10.3/200-multicall.patch
+++ b/recipes-wifi/wpa-supplicant/files/patches-2.10.3/200-multicall.patch
@@ -189,7 +189,7 @@
{
struct hostapd_data *hapd = ctx;
#ifndef CONFIG_NO_STDOUT_DEBUG
-@@ -2271,7 +2271,7 @@ void wpa_supplicant_event(void *ctx, enu
+@@ -2272,7 +2272,7 @@ void wpa_supplicant_event(void *ctx, enu
}
diff --git a/recipes-wifi/wpa-supplicant/files/patches-2.10.3/600-ubus_support.patch b/recipes-wifi/wpa-supplicant/files/patches-2.10.3/600-ubus_support.patch
index f393634..f420c18 100644
--- a/recipes-wifi/wpa-supplicant/files/patches-2.10.3/600-ubus_support.patch
+++ b/recipes-wifi/wpa-supplicant/files/patches-2.10.3/600-ubus_support.patch
@@ -1,11 +1,12 @@
--- a/hostapd/Makefile
+++ b/hostapd/Makefile
-@@ -166,6 +166,11 @@ OBJS += ../src/common/hw_features_common
+@@ -166,6 +166,12 @@ OBJS += ../src/common/hw_features_common
OBJS += ../src/eapol_auth/eapol_auth_sm.o
+ifdef CONFIG_UBUS
+CFLAGS += -DUBUS_SUPPORT
++OBJS += ../src/utils/uloop.o
+OBJS += ../src/ap/ubus.o
+LIBS += -lubox -lubus
+endif
@@ -22,15 +23,6 @@
#define OCE_STA_CFON_ENABLED(hapd) \
((hapd->conf->oce & OCE_STA_CFON) && \
-@@ -92,7 +93,7 @@ struct hapd_interfaces {
- #ifdef CONFIG_CTRL_IFACE_UDP
- unsigned char ctrl_iface_cookie[CTRL_IFACE_COOKIE_LEN];
- #endif /* CONFIG_CTRL_IFACE_UDP */
--
-+ struct ubus_object ubus;
- };
-
- enum hostapd_chan_status {
@@ -184,6 +185,7 @@ struct hostapd_data {
struct hostapd_iface *iface;
struct hostapd_config *iconf;
@@ -330,20 +322,21 @@
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
-@@ -194,6 +194,12 @@ ifdef CONFIG_EAPOL_TEST
+@@ -194,6 +194,13 @@ ifdef CONFIG_EAPOL_TEST
CFLAGS += -Werror -DEAPOL_TEST
endif
+ifdef CONFIG_UBUS
+CFLAGS += -DUBUS_SUPPORT
+OBJS += ubus.o
++OBJS += ../src/utils/uloop.o
+LIBS += -lubox -lubus
+endif
+
ifdef CONFIG_CODE_COVERAGE
CFLAGS += -O0 -fprofile-arcs -ftest-coverage
LIBS += -lgcov
-@@ -989,6 +995,9 @@ ifdef CONFIG_CTRL_IFACE_MIB
+@@ -989,6 +996,9 @@ ifdef CONFIG_CTRL_IFACE_MIB
CFLAGS += -DCONFIG_CTRL_IFACE_MIB
endif
OBJS += ../src/ap/ctrl_iface_ap.o
@@ -432,24 +425,6 @@
if (wpa_s->conf->wps_cred_processing == 1)
return 0;
---- a/hostapd/main.c
-+++ b/hostapd/main.c
-@@ -991,6 +991,7 @@ int main(int argc, char *argv[])
- }
-
- hostapd_global_ctrl_iface_init(&interfaces);
-+ hostapd_ubus_add(&interfaces);
-
- if (hostapd_global_run(&interfaces, daemonize, pid_file)) {
- wpa_printf(MSG_ERROR, "Failed to start eloop");
-@@ -1000,6 +1001,7 @@ int main(int argc, char *argv[])
- ret = 0;
-
- out:
-+ hostapd_ubus_free(&interfaces);
- hostapd_global_ctrl_iface_deinit(&interfaces);
- /* Deinitialize all interfaces */
- for (i = 0; i < interfaces.count; i++) {
--- a/wpa_supplicant/main.c
+++ b/wpa_supplicant/main.c
@@ -204,7 +204,7 @@ int main(int argc, char *argv[])
@@ -623,3 +598,151 @@
wpa_hexdump(MSG_DEBUG, "WNM: BSS Transition Candidate List Entries",
pos, end - pos);
}
+--- a/src/utils/eloop.c
++++ b/src/utils/eloop.c
+@@ -77,6 +77,9 @@ struct eloop_sock_table {
+ struct eloop_data {
+ int max_sock;
+
++ eloop_timeout_poll_handler timeout_poll_cb;
++ eloop_poll_handler poll_cb;
++
+ size_t count; /* sum of all table counts */
+ #ifdef CONFIG_ELOOP_POLL
+ size_t max_pollfd_map; /* number of pollfds_map currently allocated */
+@@ -1121,6 +1124,12 @@ void eloop_run(void)
+ os_reltime_sub(&timeout->time, &now, &tv);
+ else
+ tv.sec = tv.usec = 0;
++ }
++
++ if (eloop.timeout_poll_cb && eloop.timeout_poll_cb(&tv, !!timeout))
++ timeout = (void *)1;
++
++ if (timeout) {
+ #if defined(CONFIG_ELOOP_POLL) || defined(CONFIG_ELOOP_EPOLL)
+ timeout_ms = tv.sec * 1000 + tv.usec / 1000;
+ #endif /* defined(CONFIG_ELOOP_POLL) || defined(CONFIG_ELOOP_EPOLL) */
+@@ -1190,7 +1199,8 @@ void eloop_run(void)
+ eloop.exceptions.changed = 0;
+
+ eloop_process_pending_signals();
+-
++ if (eloop.poll_cb)
++ eloop.poll_cb();
+
+ /* check if some registered timeouts have occurred */
+ timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,
+@@ -1252,6 +1262,14 @@ out:
+ return;
+ }
+
++int eloop_register_cb(eloop_poll_handler poll_cb,
++ eloop_timeout_poll_handler timeout_cb)
++{
++ eloop.poll_cb = poll_cb;
++ eloop.timeout_poll_cb = timeout_cb;
++
++ return 0;
++}
+
+ void eloop_terminate(void)
+ {
+--- a/src/utils/eloop.h
++++ b/src/utils/eloop.h
+@@ -65,6 +65,9 @@ typedef void (*eloop_timeout_handler)(vo
+ */
+ typedef void (*eloop_signal_handler)(int sig, void *signal_ctx);
+
++typedef bool (*eloop_timeout_poll_handler)(struct os_reltime *tv, bool tv_set);
++typedef void (*eloop_poll_handler)(void);
++
+ /**
+ * eloop_init() - Initialize global event loop data
+ * Returns: 0 on success, -1 on failure
+@@ -73,6 +76,9 @@ typedef void (*eloop_signal_handler)(int
+ */
+ int eloop_init(void);
+
++int eloop_register_cb(eloop_poll_handler poll_cb,
++ eloop_timeout_poll_handler timeout_cb);
++
+ /**
+ * eloop_register_read_sock - Register handler for read events
+ * @sock: File descriptor number for the socket
+@@ -320,6 +326,8 @@ int eloop_register_signal_reconfig(eloop
+ */
+ int eloop_sock_requeue(void);
+
++void eloop_add_uloop(void);
++
+ /**
+ * eloop_run - Start the event loop
+ *
+--- /dev/null
++++ b/src/utils/uloop.c
+@@ -0,0 +1,64 @@
++#include <libubox/uloop.h>
++#include "includes.h"
++#include "common.h"
++#include "eloop.h"
++
++static void eloop_uloop_event_cb(int sock, void *eloop_ctx, void *sock_ctx)
++{
++}
++
++static void eloop_uloop_fd_cb(struct uloop_fd *fd, unsigned int events)
++{
++ unsigned int changed = events ^ fd->flags;
++
++ if (changed & ULOOP_READ) {
++ if (events & ULOOP_READ)
++ eloop_register_sock(fd->fd, EVENT_TYPE_READ, eloop_uloop_event_cb, fd, fd);
++ else
++ eloop_unregister_sock(fd->fd, EVENT_TYPE_READ);
++ }
++
++ if (changed & ULOOP_WRITE) {
++ if (events & ULOOP_WRITE)
++ eloop_register_sock(fd->fd, EVENT_TYPE_WRITE, eloop_uloop_event_cb, fd, fd);
++ else
++ eloop_unregister_sock(fd->fd, EVENT_TYPE_WRITE);
++ }
++}
++
++static bool uloop_timeout_poll_handler(struct os_reltime *tv, bool tv_set)
++{
++ struct os_reltime tv_uloop;
++ int timeout_ms = uloop_get_next_timeout();
++
++ if (timeout_ms < 0)
++ return false;
++
++ tv_uloop.sec = timeout_ms / 1000;
++ tv_uloop.usec = (timeout_ms % 1000) * 1000;
++
++ if (!tv_set || os_reltime_before(&tv_uloop, tv)) {
++ *tv = tv_uloop;
++ return true;
++ }
++
++ return false;
++}
++
++static void uloop_poll_handler(void)
++{
++ uloop_run_timeout(0);
++}
++
++void eloop_add_uloop(void)
++{
++ static bool init_done = false;
++
++ if (!init_done) {
++ uloop_init();
++ uloop_fd_set_cb = eloop_uloop_fd_cb;
++ init_done = true;
++ }
++
++ eloop_register_cb(uloop_poll_handler, uloop_timeout_poll_handler);
++}
diff --git a/recipes-wifi/wpa-supplicant/files/patches-2.10.3/601-ucode_support.patch b/recipes-wifi/wpa-supplicant/files/patches-2.10.3/601-ucode_support.patch
new file mode 100644
index 0000000..ff1a9dd
--- /dev/null
+++ b/recipes-wifi/wpa-supplicant/files/patches-2.10.3/601-ucode_support.patch
@@ -0,0 +1,234 @@
+--- a/hostapd/Makefile
++++ b/hostapd/Makefile
+@@ -168,9 +168,21 @@ OBJS += ../src/eapol_auth/eapol_auth_sm.
+
+ ifdef CONFIG_UBUS
+ CFLAGS += -DUBUS_SUPPORT
+-OBJS += ../src/utils/uloop.o
+ OBJS += ../src/ap/ubus.o
+-LIBS += -lubox -lubus
++LIBS += -lubus
++NEED_ULOOP:=y
++endif
++
++ifdef CONFIG_UCODE
++CFLAGS += -DUCODE_SUPPORT
++OBJS += ../src/utils/ucode.o
++OBJS += ../src/ap/ucode.o
++NEED_ULOOP:=y
++endif
++
++ifdef NEED_ULOOP
++OBJS += ../src/utils/uloop.o
++LIBS += -lubox
+ endif
+
+ ifdef CONFIG_CODE_COVERAGE
+--- a/hostapd/main.c
++++ b/hostapd/main.c
+@@ -991,6 +991,7 @@ int main(int argc, char *argv[])
+ }
+
+ hostapd_global_ctrl_iface_init(&interfaces);
++ hostapd_ucode_init(&interfaces);
+
+ if (hostapd_global_run(&interfaces, daemonize, pid_file)) {
+ wpa_printf(MSG_ERROR, "Failed to start eloop");
+@@ -1000,6 +1001,7 @@ int main(int argc, char *argv[])
+ ret = 0;
+
+ out:
++ hostapd_ucode_free();
+ hostapd_global_ctrl_iface_deinit(&interfaces);
+ /* Deinitialize all interfaces */
+ for (i = 0; i < interfaces.count; i++) {
+--- a/src/ap/hostapd.h
++++ b/src/ap/hostapd.h
+@@ -19,6 +19,7 @@
+ #include "ap_config.h"
+ #include "drivers/driver.h"
+ #include "ubus.h"
++#include "ucode.h"
+
+ #define OCE_STA_CFON_ENABLED(hapd) \
+ ((hapd->conf->oce & OCE_STA_CFON) && \
+@@ -51,6 +52,10 @@ struct hapd_interfaces {
+ struct hostapd_config * (*config_read_cb)(const char *config_fname);
+ int (*ctrl_iface_init)(struct hostapd_data *hapd);
+ void (*ctrl_iface_deinit)(struct hostapd_data *hapd);
++ int (*ctrl_iface_recv)(struct hostapd_data *hapd,
++ char *buf, char *reply, int reply_size,
++ struct sockaddr_storage *from,
++ socklen_t fromlen);
+ int (*for_each_interface)(struct hapd_interfaces *interfaces,
+ int (*cb)(struct hostapd_iface *iface,
+ void *ctx), void *ctx);
+@@ -186,6 +191,7 @@ struct hostapd_data {
+ struct hostapd_config *iconf;
+ struct hostapd_bss_config *conf;
+ struct hostapd_ubus_bss ubus;
++ struct hostapd_ucode_bss ucode;
+ int interface_added; /* virtual interface added for this BSS */
+ unsigned int started:1;
+ unsigned int disabled:1;
+@@ -506,6 +512,7 @@ struct hostapd_sta_info {
+ */
+ struct hostapd_iface {
+ struct hapd_interfaces *interfaces;
++ struct hostapd_ucode_iface ucode;
+ void *owner;
+ char *config_fname;
+ struct hostapd_config *conf;
+--- a/src/ap/hostapd.c
++++ b/src/ap/hostapd.c
+@@ -276,6 +276,8 @@ int hostapd_reload_config(struct hostapd
+ size_t j;
+ int i;
+
++ hostapd_ucode_reload_bss(hapd, reconf);
++
+ if (iface->config_fname == NULL) {
+ /* Only in-memory config in use - assume it has been updated */
+ hostapd_clear_old(iface);
+@@ -455,6 +457,7 @@ void hostapd_free_hapd_data(struct hosta
+ hapd->beacon_set_done = 0;
+
+ wpa_printf(MSG_DEBUG, "%s(%s)", __func__, hapd->conf->iface);
++ hostapd_ucode_free_bss(hapd);
+ hostapd_ubus_free_bss(hapd);
+ accounting_deinit(hapd);
+ hostapd_deinit_wpa(hapd);
+@@ -619,6 +622,7 @@ void hostapd_cleanup_iface_partial(struc
+ static void hostapd_cleanup_iface(struct hostapd_iface *iface)
+ {
+ wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface);
++ hostapd_ucode_free_iface(iface);
+ eloop_cancel_timeout(channel_list_update_timeout, iface, NULL);
+ eloop_cancel_timeout(hostapd_interface_setup_failure_handler, iface,
+ NULL);
+@@ -1209,6 +1213,7 @@ static int hostapd_start_beacon(struct h
+ hapd->driver->set_operstate(hapd->drv_priv, 1);
+
+ hostapd_ubus_add_bss(hapd);
++ hostapd_ucode_add_bss(hapd);
+
+ return 0;
+ }
+--- a/wpa_supplicant/Makefile
++++ b/wpa_supplicant/Makefile
+@@ -197,8 +197,20 @@ endif
+ ifdef CONFIG_UBUS
+ CFLAGS += -DUBUS_SUPPORT
+ OBJS += ubus.o
++LIBS += -lubus
++NEED_ULOOP:=y
++endif
++
++ifdef CONFIG_UCODE
++CFLAGS += -DUCODE_SUPPORT
++OBJS += ../src/utils/ucode.o
++OBJS += ucode.o
++NEED_ULOOP:=y
++endif
++
++ifdef NEED_ULOOP
+ OBJS += ../src/utils/uloop.o
+-LIBS += -lubox -lubus
++LIBS += -lubox
+ endif
+
+ ifdef CONFIG_CODE_COVERAGE
+@@ -999,6 +1011,9 @@ OBJS += ../src/ap/ctrl_iface_ap.o
+ ifdef CONFIG_UBUS
+ OBJS += ../src/ap/ubus.o
+ endif
++ifdef CONFIG_UCODE
++OBJS += ../src/ap/ucode.o
++endif
+ endif
+
+ CFLAGS += -DEAP_SERVER -DEAP_SERVER_IDENTITY
+--- a/wpa_supplicant/wpa_supplicant.c
++++ b/wpa_supplicant/wpa_supplicant.c
+@@ -7636,6 +7636,7 @@ struct wpa_supplicant * wpa_supplicant_a
+ #endif /* CONFIG_P2P */
+
+ wpas_ubus_add_bss(wpa_s);
++ wpas_ucode_add_bss(wpa_s);
+
+ return wpa_s;
+ }
+@@ -7663,6 +7664,7 @@ int wpa_supplicant_remove_iface(struct w
+ struct wpa_supplicant *parent = wpa_s->parent;
+ #endif /* CONFIG_MESH */
+
++ wpas_ucode_free_bss(wpa_s);
+ wpas_ubus_free_bss(wpa_s);
+
+ /* Remove interface from the global list of interfaces */
+@@ -7973,6 +7975,7 @@ struct wpa_global * wpa_supplicant_init(
+
+ eloop_register_timeout(WPA_SUPPLICANT_CLEANUP_INTERVAL, 0,
+ wpas_periodic, global, NULL);
++ wpas_ucode_init(global);
+
+ return global;
+ }
+@@ -8011,12 +8014,8 @@ int wpa_supplicant_run(struct wpa_global
+ eloop_register_signal_terminate(wpa_supplicant_terminate, global);
+ eloop_register_signal_reconfig(wpa_supplicant_reconfig, global);
+
+- wpas_ubus_add(global);
+-
+ eloop_run();
+
+- wpas_ubus_free(global);
+-
+ return 0;
+ }
+
+@@ -8049,6 +8048,8 @@ void wpa_supplicant_deinit(struct wpa_gl
+
+ wpas_notify_supplicant_deinitialized(global);
+
++ wpas_ucode_free();
++
+ eap_peer_unregister_methods();
+ #ifdef CONFIG_AP
+ eap_server_unregister_methods();
+--- a/wpa_supplicant/wpa_supplicant_i.h
++++ b/wpa_supplicant/wpa_supplicant_i.h
+@@ -22,6 +22,7 @@
+ #include "wmm_ac.h"
+ #include "pasn/pasn_common.h"
+ #include "ubus.h"
++#include "ucode.h"
+
+ extern const char *const wpa_supplicant_version;
+ extern const char *const wpa_supplicant_license;
+@@ -659,6 +660,7 @@ struct wpa_supplicant {
+ unsigned char perm_addr[ETH_ALEN];
+ char ifname[100];
+ struct wpas_ubus_bss ubus;
++ struct wpas_ucode_bss ucode;
+ #ifdef CONFIG_MATCH_IFACE
+ int matched;
+ #endif /* CONFIG_MATCH_IFACE */
+--- a/hostapd/ctrl_iface.c
++++ b/hostapd/ctrl_iface.c
+@@ -4921,6 +4921,7 @@ try_again:
+ return -1;
+ }
+
++ interface->ctrl_iface_recv = hostapd_ctrl_iface_receive_process;
+ wpa_msg_register_cb(hostapd_ctrl_iface_msg_cb);
+
+ return 0;
+@@ -5022,6 +5023,7 @@ fail:
+ os_free(fname);
+
+ interface->global_ctrl_sock = s;
++ interface->ctrl_iface_recv = hostapd_ctrl_iface_receive_process;
+ eloop_register_read_sock(s, hostapd_global_ctrl_iface_receive,
+ interface, NULL);
+
diff --git a/recipes-wifi/wpa-supplicant/files/patches-2.10.3/700-wifi-reload.patch b/recipes-wifi/wpa-supplicant/files/patches-2.10.3/700-wifi-reload.patch
index 0c76276..c0e7e4d 100644
--- a/recipes-wifi/wpa-supplicant/files/patches-2.10.3/700-wifi-reload.patch
+++ b/recipes-wifi/wpa-supplicant/files/patches-2.10.3/700-wifi-reload.patch
@@ -40,6 +40,15 @@
int rts_threshold;
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
+@@ -127,7 +127,7 @@ void hostapd_reconfig_encryption(struct
+ }
+
+
+-static void hostapd_reload_bss(struct hostapd_data *hapd)
++void hostapd_reload_bss(struct hostapd_data *hapd)
+ {
+ struct hostapd_ssid *ssid;
+
@@ -255,6 +255,10 @@ static int hostapd_iface_conf_changed(st
{
size_t i;
@@ -60,7 +69,7 @@
{
struct hapd_interfaces *interfaces = iface->interfaces;
struct hostapd_data *hapd = iface->bss[0];
-@@ -296,6 +300,9 @@ int hostapd_reload_config(struct hostapd
+@@ -298,6 +302,9 @@ int hostapd_reload_config(struct hostapd
char *fname;
int res;
@@ -70,7 +79,7 @@
hostapd_clear_old(iface);
wpa_printf(MSG_DEBUG,
-@@ -322,6 +329,24 @@ int hostapd_reload_config(struct hostapd
+@@ -324,6 +331,24 @@ int hostapd_reload_config(struct hostapd
wpa_printf(MSG_ERROR,
"Failed to enable interface on config reload");
return res;
@@ -95,7 +104,7 @@
}
iface->conf = newconf;
-@@ -338,6 +363,12 @@ int hostapd_reload_config(struct hostapd
+@@ -340,6 +365,12 @@ int hostapd_reload_config(struct hostapd
for (j = 0; j < iface->num_bss; j++) {
hapd = iface->bss[j];
@@ -108,7 +117,17 @@
if (!hapd->conf->config_id || !newconf->bss[j]->config_id ||
os_strcmp(hapd->conf->config_id,
newconf->bss[j]->config_id) != 0)
-@@ -2700,6 +2731,10 @@ hostapd_alloc_bss_data(struct hostapd_if
+@@ -1236,8 +1267,7 @@ static int hostapd_start_beacon(struct h
+ * initialized. Most of the modules that are initialized here will be
+ * deinitialized in hostapd_cleanup().
+ */
+-static int hostapd_setup_bss(struct hostapd_data *hapd, int first,
+- bool start_beacon)
++int hostapd_setup_bss(struct hostapd_data *hapd, int first, bool start_beacon)
+ {
+ struct hostapd_bss_config *conf = hapd->conf;
+ u8 ssid[SSID_MAX_LEN + 1];
+@@ -2705,6 +2735,10 @@ hostapd_alloc_bss_data(struct hostapd_if
hapd->iconf = conf;
hapd->conf = bss;
hapd->iface = hapd_iface;
@@ -119,9 +138,18 @@
if (conf)
hapd->driver = conf->driver;
hapd->ctrl_sock = -1;
+@@ -2723,7 +2757,7 @@ hostapd_alloc_bss_data(struct hostapd_if
+ }
+
+
+-static void hostapd_bss_deinit(struct hostapd_data *hapd)
++void hostapd_bss_deinit(struct hostapd_data *hapd)
+ {
+ if (!hapd)
+ return;
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
-@@ -47,7 +47,7 @@ struct mesh_conf;
+@@ -48,7 +48,7 @@ struct mesh_conf;
struct hostapd_iface;
struct hapd_interfaces {
@@ -130,23 +158,33 @@
struct hostapd_config * (*config_read_cb)(const char *config_fname);
int (*ctrl_iface_init)(struct hostapd_data *hapd);
void (*ctrl_iface_deinit)(struct hostapd_data *hapd);
-@@ -186,6 +186,7 @@ struct hostapd_data {
- struct hostapd_config *iconf;
+@@ -192,6 +192,7 @@ struct hostapd_data {
struct hostapd_bss_config *conf;
struct hostapd_ubus_bss ubus;
+ struct hostapd_ucode_bss ucode;
+ char *config_id;
int interface_added; /* virtual interface added for this BSS */
unsigned int started:1;
unsigned int disabled:1;
-@@ -689,7 +690,7 @@ struct hostapd_iface {
+@@ -696,7 +697,9 @@ struct hostapd_iface {
int hostapd_for_each_interface(struct hapd_interfaces *interfaces,
int (*cb)(struct hostapd_iface *iface,
void *ctx), void *ctx);
-int hostapd_reload_config(struct hostapd_iface *iface);
+int hostapd_reload_config(struct hostapd_iface *iface, int reconf);
++void hostapd_reload_bss(struct hostapd_data *hapd);
++void hostapd_bss_deinit(struct hostapd_data *hapd);
void hostapd_reconfig_encryption(struct hostapd_data *hapd);
struct hostapd_data *
hostapd_alloc_bss_data(struct hostapd_iface *hapd_iface,
+@@ -713,6 +716,7 @@ struct hostapd_iface * hostapd_init(stru
+ struct hostapd_iface *
+ hostapd_interface_init_bss(struct hapd_interfaces *interfaces, const char *phy,
+ const char *config_fname, int debug);
++int hostapd_setup_bss(struct hostapd_data *hapd, int first, bool start_beacon);
+ void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta,
+ int reassoc);
+ void hostapd_interface_deinit_free(struct hostapd_iface *iface);
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -5322,6 +5322,9 @@ static int wpa_driver_nl80211_set_ap(voi
diff --git a/recipes-wifi/wpa-supplicant/files/patches-2.10.3/701-reload_config_inline.patch b/recipes-wifi/wpa-supplicant/files/patches-2.10.3/701-reload_config_inline.patch
new file mode 100644
index 0000000..071281e
--- /dev/null
+++ b/recipes-wifi/wpa-supplicant/files/patches-2.10.3/701-reload_config_inline.patch
@@ -0,0 +1,33 @@
+--- a/hostapd/config_file.c
++++ b/hostapd/config_file.c
+@@ -4814,7 +4814,12 @@ struct hostapd_config * hostapd_config_r
+ int errors = 0;
+ size_t i;
+
+- f = fopen(fname, "r");
++ if (!strncmp(fname, "data:", 5)) {
++ f = fmemopen((void *)(fname + 5), strlen(fname + 5), "r");
++ fname = "<inline>";
++ } else {
++ f = fopen(fname, "r");
++ }
+ if (f == NULL) {
+ wpa_printf(MSG_ERROR, "Could not open configuration file '%s' "
+ "for reading.", fname);
+--- a/wpa_supplicant/config_file.c
++++ b/wpa_supplicant/config_file.c
+@@ -326,8 +326,13 @@ struct wpa_config * wpa_config_read(cons
+ while (cred_tail && cred_tail->next)
+ cred_tail = cred_tail->next;
+
++ if (!strncmp(name, "data:", 5)) {
++ f = fmemopen((void *)(name + 5), strlen(name + 5), "r");
++ name = "<inline>";
++ } else {
++ f = fopen(name, "r");
++ }
+ wpa_printf(MSG_DEBUG, "Reading configuration file '%s'", name);
+- f = fopen(name, "r");
+ if (f == NULL) {
+ wpa_printf(MSG_ERROR, "Failed to open config file '%s', "
+ "error: %s", name, strerror(errno));
diff --git a/recipes-wifi/wpa-supplicant/files/patches-2.10.3/720-iface_max_num_sta.patch b/recipes-wifi/wpa-supplicant/files/patches-2.10.3/720-iface_max_num_sta.patch
index 0bb00f9..5f40aab 100644
--- a/recipes-wifi/wpa-supplicant/files/patches-2.10.3/720-iface_max_num_sta.patch
+++ b/recipes-wifi/wpa-supplicant/files/patches-2.10.3/720-iface_max_num_sta.patch
@@ -17,7 +17,7 @@
} else if (os_strcmp(buf, "extended_key_id") == 0) {
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
-@@ -734,6 +734,7 @@ void hostapd_cleanup_cs_params(struct ho
+@@ -744,6 +744,7 @@ void hostapd_cleanup_cs_params(struct ho
void hostapd_periodic_iface(struct hostapd_iface *iface);
int hostapd_owe_trans_get_info(struct hostapd_data *hapd);
void hostapd_ocv_check_csa_sa_query(void *eloop_ctx, void *timeout_ctx);
diff --git a/recipes-wifi/wpa-supplicant/files/patches-2.10.3/750-qos_map_set_without_interworking.patch b/recipes-wifi/wpa-supplicant/files/patches-2.10.3/750-qos_map_set_without_interworking.patch
index 124f5ea..3e282b4 100644
--- a/recipes-wifi/wpa-supplicant/files/patches-2.10.3/750-qos_map_set_without_interworking.patch
+++ b/recipes-wifi/wpa-supplicant/files/patches-2.10.3/750-qos_map_set_without_interworking.patch
@@ -32,7 +32,7 @@
os_free(bss->dump_msk_file);
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
-@@ -1534,6 +1534,7 @@ static int hostapd_setup_bss(struct host
+@@ -1538,6 +1538,7 @@ int hostapd_setup_bss(struct hostapd_dat
wpa_printf(MSG_ERROR, "GAS server initialization failed");
return -1;
}
@@ -40,7 +40,7 @@
if (conf->qos_map_set_len &&
hostapd_drv_set_qos_map(hapd, conf->qos_map_set,
-@@ -1541,7 +1542,6 @@ static int hostapd_setup_bss(struct host
+@@ -1545,7 +1546,6 @@ int hostapd_setup_bss(struct hostapd_dat
wpa_printf(MSG_ERROR, "Failed to initialize QoS Map");
return -1;
}
diff --git a/recipes-wifi/wpa-supplicant/files/patches-2.10.3/761-shared_das_port.patch b/recipes-wifi/wpa-supplicant/files/patches-2.10.3/761-shared_das_port.patch
index dad7afd..d60764a 100644
--- a/recipes-wifi/wpa-supplicant/files/patches-2.10.3/761-shared_das_port.patch
+++ b/recipes-wifi/wpa-supplicant/files/patches-2.10.3/761-shared_das_port.patch
@@ -10,7 +10,7 @@
unsigned int time_window;
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
-@@ -1471,6 +1471,7 @@ static int hostapd_setup_bss(struct host
+@@ -1475,6 +1475,7 @@ int hostapd_setup_bss(struct hostapd_dat
os_memset(&das_conf, 0, sizeof(das_conf));
das_conf.port = conf->radius_das_port;
diff --git a/recipes-wifi/wpa-supplicant/files/patches-2.10.3/770-radius_server.patch b/recipes-wifi/wpa-supplicant/files/patches-2.10.3/770-radius_server.patch
new file mode 100644
index 0000000..6fca86d
--- /dev/null
+++ b/recipes-wifi/wpa-supplicant/files/patches-2.10.3/770-radius_server.patch
@@ -0,0 +1,154 @@
+--- a/hostapd/Makefile
++++ b/hostapd/Makefile
+@@ -63,6 +63,10 @@ endif
+ OBJS += main.o
+ OBJS += config_file.o
+
++ifdef CONFIG_RADIUS_SERVER
++OBJS += radius.o
++endif
++
+ OBJS += ../src/ap/hostapd.o
+ OBJS += ../src/ap/wpa_auth_glue.o
+ OBJS += ../src/ap/drv_callbacks.o
+--- a/hostapd/main.c
++++ b/hostapd/main.c
+@@ -42,6 +42,7 @@ static struct hapd_global global;
+ static int daemonize = 0;
+ static char *pid_file = NULL;
+
++extern int radius_main(int argc, char **argv);
+
+ #ifndef CONFIG_NO_HOSTAPD_LOGGER
+ static void hostapd_logger_cb(void *ctx, const u8 *addr, unsigned int module,
+@@ -755,6 +756,11 @@ int main(int argc, char *argv[])
+ if (os_program_init())
+ return -1;
+
++#ifdef RADIUS_SERVER
++ if (strstr(argv[0], "radius"))
++ return radius_main(argc, argv);
++#endif
++
+ os_memset(&interfaces, 0, sizeof(interfaces));
+ interfaces.reload_config = hostapd_reload_config;
+ interfaces.config_read_cb = hostapd_config_read;
+--- a/src/radius/radius_server.c
++++ b/src/radius/radius_server.c
+@@ -63,6 +63,12 @@ struct radius_server_counters {
+ u32 unknown_acct_types;
+ };
+
++struct radius_accept_attr {
++ u8 type;
++ u16 len;
++ void *data;
++};
++
+ /**
+ * struct radius_session - Internal RADIUS server data for a session
+ */
+@@ -90,7 +96,7 @@ struct radius_session {
+ unsigned int macacl:1;
+ unsigned int t_c_filtering:1;
+
+- struct hostapd_radius_attr *accept_attr;
++ struct radius_accept_attr *accept_attr;
+
+ u32 t_c_timestamp; /* Last read T&C timestamp from user DB */
+ };
+@@ -394,6 +400,7 @@ static void radius_server_session_free(s
+ radius_msg_free(sess->last_reply);
+ os_free(sess->username);
+ os_free(sess->nas_ip);
++ os_free(sess->accept_attr);
+ os_free(sess);
+ data->num_sess--;
+ }
+@@ -554,6 +561,36 @@ radius_server_erp_find_key(struct radius
+ }
+ #endif /* CONFIG_ERP */
+
++static struct radius_accept_attr *
++radius_server_copy_attr(const struct hostapd_radius_attr *data)
++{
++ const struct hostapd_radius_attr *attr;
++ struct radius_accept_attr *attr_new;
++ size_t data_size = 0;
++ void *data_buf;
++ int n_attr = 1;
++
++ for (attr = data; attr; attr = attr->next) {
++ n_attr++;
++ data_size += wpabuf_len(attr->val);
++ }
++
++ attr_new = os_zalloc(n_attr * sizeof(*attr) + data_size);
++ if (!attr_new)
++ return NULL;
++
++ data_buf = &attr_new[n_attr];
++ for (n_attr = 0, attr = data; attr; attr = attr->next) {
++ struct radius_accept_attr *cur = &attr_new[n_attr++];
++
++ cur->type = attr->type;
++ cur->len = wpabuf_len(attr->val);
++ cur->data = memcpy(data_buf, wpabuf_head(attr->val), cur->len);
++ data_buf += cur->len;
++ }
++
++ return attr_new;
++}
+
+ static struct radius_session *
+ radius_server_get_new_session(struct radius_server_data *data,
+@@ -607,7 +644,7 @@ radius_server_get_new_session(struct rad
+ eap_user_free(tmp);
+ return NULL;
+ }
+- sess->accept_attr = tmp->accept_attr;
++ sess->accept_attr = radius_server_copy_attr(tmp->accept_attr);
+ sess->macacl = tmp->macacl;
+ eap_user_free(tmp);
+
+@@ -1118,11 +1155,10 @@ radius_server_encapsulate_eap(struct rad
+ }
+
+ if (code == RADIUS_CODE_ACCESS_ACCEPT) {
+- struct hostapd_radius_attr *attr;
+- for (attr = sess->accept_attr; attr; attr = attr->next) {
+- if (!radius_msg_add_attr(msg, attr->type,
+- wpabuf_head(attr->val),
+- wpabuf_len(attr->val))) {
++ struct radius_accept_attr *attr;
++ for (attr = sess->accept_attr; attr->data; attr++) {
++ if (!radius_msg_add_attr(msg, attr->type, attr->data,
++ attr->len)) {
+ wpa_printf(MSG_ERROR, "Could not add RADIUS attribute");
+ radius_msg_free(msg);
+ return NULL;
+@@ -1211,11 +1247,10 @@ radius_server_macacl(struct radius_serve
+ }
+
+ if (code == RADIUS_CODE_ACCESS_ACCEPT) {
+- struct hostapd_radius_attr *attr;
+- for (attr = sess->accept_attr; attr; attr = attr->next) {
+- if (!radius_msg_add_attr(msg, attr->type,
+- wpabuf_head(attr->val),
+- wpabuf_len(attr->val))) {
++ struct radius_accept_attr *attr;
++ for (attr = sess->accept_attr; attr->data; attr++) {
++ if (!radius_msg_add_attr(msg, attr->type, attr->data,
++ attr->len)) {
+ wpa_printf(MSG_ERROR, "Could not add RADIUS attribute");
+ radius_msg_free(msg);
+ return NULL;
+@@ -2512,7 +2547,7 @@ static int radius_server_get_eap_user(vo
+ ret = data->get_eap_user(data->conf_ctx, identity, identity_len,
+ phase2, user);
+ if (ret == 0 && user) {
+- sess->accept_attr = user->accept_attr;
++ sess->accept_attr = radius_server_copy_attr(user->accept_attr);
+ sess->remediation = user->remediation;
+ sess->macacl = user->macacl;
+ sess->t_c_timestamp = user->t_c_timestamp;
diff --git a/recipes-wifi/wpa-supplicant/files/patches-2.10.3/mtk-0001-hostapd-mtk-Add-neighbor-report-and-BSS-Termination-.patch b/recipes-wifi/wpa-supplicant/files/patches-2.10.3/mtk-0001-hostapd-mtk-Add-neighbor-report-and-BSS-Termination-.patch
index 4e51a1c..4fa2dfb 100644
--- a/recipes-wifi/wpa-supplicant/files/patches-2.10.3/mtk-0001-hostapd-mtk-Add-neighbor-report-and-BSS-Termination-.patch
+++ b/recipes-wifi/wpa-supplicant/files/patches-2.10.3/mtk-0001-hostapd-mtk-Add-neighbor-report-and-BSS-Termination-.patch
@@ -1,8 +1,8 @@
-From df9a616286f2d33e5c580517238b93ee22359f95 Mon Sep 17 00:00:00 2001
+From bfca3c43597bf827e4d5faec91ac8f420d33c921 Mon Sep 17 00:00:00 2001
From: "howard.hsu" <howard-yh.hsu@mediatek.com>
Date: Wed, 19 Jan 2022 19:18:07 +0800
-Subject: [PATCH 01/32] hostapd: mtk: Add neighbor report and BSS Termination
- for MBO certification
+Subject: [PATCH] hostapd: mtk: Add neighbor report and BSS Termination for MBO
+ certification
1. Add hostapd_neighbor_count() and hostapd_neighbor_insert_buffer ()
The first function can count the number of neighbor report in neighbore report
@@ -13,12 +13,11 @@
3. Support including neignbor report elements in BTM response
4. Support configuring BSS Termination TSF by using hostapd_cli command
5. Disable interface if BSS Termination TSF is set
-6. Add set_send_disassoc_frame_timer() to send disassociate frame
-Function set_disassoc_timer() may fail if key was deleted first. This new
-function will not ask to delete key as set_disassoc_timer() did.
-7. Support including neighbor report elements in BTM request
-8. Add hostapd_neighbor_set_own_report_pref()
-9. Add hostapd_neighbor_set_pref_by_non_pref_chan()
+6. Support including neighbor report elements in BTM request
+7. Add hostapd_neighbor_set_own_report_pref()
+8. Add hostapd_neighbor_set_pref_by_non_pref_chan()
+
+Revert set_send_disassoc_frame_timer
---
hostapd/ctrl_iface.c | 5 ++
src/ap/ap_config.c | 1 +
@@ -28,11 +27,11 @@
src/ap/gas_serv.h | 2 +
src/ap/neighbor_db.c | 119 +++++++++++++++++++++++++++++++++++++++++
src/ap/neighbor_db.h | 9 ++++
- src/ap/wnm_ap.c | 72 +++++++++++++++++++++++--
- 9 files changed, 252 insertions(+), 5 deletions(-)
+ src/ap/wnm_ap.c | 42 ++++++++++++++-
+ 9 files changed, 223 insertions(+), 4 deletions(-)
diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
-index 55711ab10..fab1287cd 100644
+index 55711ab..fab1287 100644
--- a/hostapd/ctrl_iface.c
+++ b/hostapd/ctrl_iface.c
@@ -1347,6 +1347,11 @@ static int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd)
@@ -48,7 +47,7 @@
ret = hostapd_set_iface(hapd->iconf, hapd->conf, cmd, value);
if (ret)
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
-index 41c70708d..7d0de122d 100644
+index 41c7070..7d0de12 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -171,6 +171,7 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
@@ -60,7 +59,7 @@
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
-index 02fd4940c..dc6025279 100644
+index 02fd494..dc60252 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -558,6 +558,7 @@ struct hostapd_bss_config {
@@ -72,7 +71,7 @@
/* IEEE 802.11u - Interworking */
int interworking;
diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c
-index 50a4dc4d6..cf1cff447 100644
+index 50a4dc4..cf1cff4 100644
--- a/src/ap/ctrl_iface_ap.c
+++ b/src/ap/ctrl_iface_ap.c
@@ -1280,6 +1280,10 @@ int hostapd_ctrl_iface_bss_tm_req(struct hostapd_data *hapd,
@@ -115,7 +114,7 @@
if (pos) {
unsigned int mbo_reason, cell_pref, reassoc_delay;
diff --git a/src/ap/gas_serv.c b/src/ap/gas_serv.c
-index 4642e4927..cce6df41c 100644
+index 4642e49..cce6df4 100644
--- a/src/ap/gas_serv.c
+++ b/src/ap/gas_serv.c
@@ -19,6 +19,7 @@
@@ -183,7 +182,7 @@
#ifdef CONFIG_FILS
if (info_id == ANQP_FILS_REALM_INFO &&
diff --git a/src/ap/gas_serv.h b/src/ap/gas_serv.h
-index 7646a98a4..ce492b53f 100644
+index 7646a98..ce492b5 100644
--- a/src/ap/gas_serv.h
+++ b/src/ap/gas_serv.h
@@ -40,6 +40,8 @@
@@ -196,7 +195,7 @@
* First 15 Hotspot 2.0 vendor specific ANQP-elements can be included in the
* optimized bitmap.
diff --git a/src/ap/neighbor_db.c b/src/ap/neighbor_db.c
-index 5b276e8da..1c14b3201 100644
+index 5b276e8..1c14b32 100644
--- a/src/ap/neighbor_db.c
+++ b/src/ap/neighbor_db.c
@@ -89,6 +89,38 @@ int hostapd_neighbor_show(struct hostapd_data *hapd, char *buf, size_t buflen)
@@ -330,7 +329,7 @@
+}
+#endif
diff --git a/src/ap/neighbor_db.h b/src/ap/neighbor_db.h
-index 992671b62..a1ddc075b 100644
+index 992671b..a1ddc07 100644
--- a/src/ap/neighbor_db.h
+++ b/src/ap/neighbor_db.h
@@ -24,4 +24,13 @@ int hostapd_neighbor_remove(struct hostapd_data *hapd, const u8 *bssid,
@@ -348,7 +347,7 @@
+#endif
#endif /* NEIGHBOR_DB_H */
diff --git a/src/ap/wnm_ap.c b/src/ap/wnm_ap.c
-index ba1dd2ed1..32ccf14ae 100644
+index ba1dd2e..939d447 100644
--- a/src/ap/wnm_ap.c
+++ b/src/ap/wnm_ap.c
@@ -20,6 +20,7 @@
@@ -402,38 +401,10 @@
hapd->openwrt_stats.wnm.bss_transition_request_tx++;
wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Request to "
MACSTR " dialog_token=%u req_mode=0x%x disassoc_timer=%u "
-@@ -890,6 +911,50 @@ static void set_disassoc_timer(struct hostapd_data *hapd, struct sta_info *sta,
+@@ -890,6 +911,22 @@ static void set_disassoc_timer(struct hostapd_data *hapd, struct sta_info *sta,
}
-+static void set_send_disassoc_frame_timer(struct hostapd_data *hapd, struct sta_info *sta,
-+ int disassoc_timer)
-+{
-+ int timeout, beacon_int;
-+
-+ /*
-+ * Prevent STA from reconnecting using cached PMKSA to force
-+ * full authentication with the authentication server (which may
-+ * decide to reject the connection),
-+ */
-+ wpa_auth_pmksa_remove(hapd->wpa_auth, sta->addr);
-+
-+ beacon_int = hapd->iconf->beacon_int;
-+ if (beacon_int < 1)
-+ beacon_int = 100; /* best guess */
-+ /* Calculate timeout in ms based on beacon_int in TU */
-+ timeout = disassoc_timer * beacon_int * 128 / 125;
-+ wpa_printf(MSG_DEBUG, "Disassociation timer for " MACSTR
-+ " set to %d ms", MAC2STR(sta->addr), timeout);
-+
-+ u16 reason = WLAN_REASON_PREV_AUTH_NOT_VALID;
-+
-+ hostapd_drv_sta_disassoc(hapd, sta->addr, reason);
-+ if (sta)
-+ ap_sta_disassociate(hapd, sta, reason);
-+}
-+
-+
+void bss_termination_disable_iface(void *eloop_ctx, void *timeout_ctx)
+{
+ struct hostapd_data *hapd = eloop_ctx;
@@ -453,16 +424,7 @@
int wnm_send_ess_disassoc_imminent(struct hostapd_data *hapd,
struct sta_info *sta, const char *url,
int disassoc_timer)
-@@ -934,7 +999,7 @@ int wnm_send_ess_disassoc_imminent(struct hostapd_data *hapd,
- hapd->openwrt_stats.wnm.bss_transition_request_tx++;
- if (disassoc_timer) {
- /* send disassociation frame after time-out */
-- set_disassoc_timer(hapd, sta, disassoc_timer);
-+ set_send_disassoc_frame_timer(hapd, sta, disassoc_timer);
- }
-
- return 0;
-@@ -979,6 +1044,7 @@ int wnm_send_bss_tm_req(struct hostapd_data *hapd, struct sta_info *sta,
+@@ -979,6 +1016,7 @@ int wnm_send_bss_tm_req(struct hostapd_data *hapd, struct sta_info *sta,
bss_term_dur) {
os_memcpy(pos, bss_term_dur, 12);
pos += 12;
@@ -471,5 +433,5 @@
if (url) {
--
-2.39.2
+2.18.0
diff --git a/recipes-wifi/wpa-supplicant/files/patches-2.10.3/mtk-0026-hostapd-mtk-avoid-setting-beacon-after-wpa_supplican.patch b/recipes-wifi/wpa-supplicant/files/patches-2.10.3/mtk-0026-hostapd-mtk-Avoid-setting-beacon-after-wpa_supplican.patch
similarity index 89%
rename from recipes-wifi/wpa-supplicant/files/patches-2.10.3/mtk-0026-hostapd-mtk-avoid-setting-beacon-after-wpa_supplican.patch
rename to recipes-wifi/wpa-supplicant/files/patches-2.10.3/mtk-0026-hostapd-mtk-Avoid-setting-beacon-after-wpa_supplican.patch
index af79b24..dbd7163 100644
--- a/recipes-wifi/wpa-supplicant/files/patches-2.10.3/mtk-0026-hostapd-mtk-avoid-setting-beacon-after-wpa_supplican.patch
+++ b/recipes-wifi/wpa-supplicant/files/patches-2.10.3/mtk-0026-hostapd-mtk-Avoid-setting-beacon-after-wpa_supplican.patch
@@ -1,4 +1,4 @@
-From ff273381d463d82898df70cb7b43341405e3d943 Mon Sep 17 00:00:00 2001
+From 67e2363c4875dd918418dd84b43f86041db690c7 Mon Sep 17 00:00:00 2001
From: Evelyn Tsai <evelyn.tsai@mediatek.com>
Date: Fri, 12 May 2023 05:21:28 +0800
Subject: [PATCH] hostapd: mtk: Avoid setting beacon after wpa_supplicant stop
@@ -19,7 +19,7 @@
6 files changed, 22 insertions(+), 6 deletions(-)
diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
-index 9989a04..4952bef 100644
+index e575c37d1..0e352c5c7 100644
--- a/hostapd/ctrl_iface.c
+++ b/hostapd/ctrl_iface.c
@@ -194,11 +194,15 @@ static int hostapd_ctrl_iface_update(struct hostapd_data *hapd, char *txt)
@@ -39,7 +39,7 @@
iface->interfaces->config_read_cb = config_read_cb;
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
-index f26e525..1aaeaa8 100644
+index f26e5254c..1aaeaa8e4 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -2246,7 +2246,8 @@ int ieee802_11_set_beacon(struct hostapd_data *hapd)
@@ -69,7 +69,7 @@
ret = -1;
}
diff --git a/src/ap/bss_load.c b/src/ap/bss_load.c
-index 725d3cd..f2a1a10 100644
+index 725d3cd34..78fd9d8ec 100644
--- a/src/ap/bss_load.c
+++ b/src/ap/bss_load.c
@@ -49,6 +49,9 @@ static void update_channel_utilization(void *eloop_data, void *user_data)
@@ -104,7 +104,7 @@
NULL);
}
diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c
-index aab8a46..d52188b 100644
+index aab8a4665..d52188bb7 100644
--- a/src/ap/ctrl_iface_ap.c
+++ b/src/ap/ctrl_iface_ap.c
@@ -1028,8 +1028,10 @@ int hostapd_ctrl_iface_stop_ap(struct hostapd_data *hapd)
@@ -120,18 +120,18 @@
return 0;
}
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
-index abadd1a..afe0611 100644
+index 28e549b61..be75613c8 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
-@@ -508,6 +508,7 @@ void hostapd_free_hapd_data(struct hostapd_data *hapd)
+@@ -510,6 +510,7 @@ void hostapd_free_hapd_data(struct hostapd_data *hapd)
}
hapd->started = 0;
hapd->beacon_set_done = 0;
+ hapd->stopped_by_supplicant = 0;
wpa_printf(MSG_DEBUG, "%s(%s)", __func__, hapd->conf->iface);
- hostapd_ubus_free_bss(hapd);
-@@ -1316,6 +1317,7 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first,
+ hostapd_ucode_free_bss(hapd);
+@@ -1320,6 +1321,7 @@ int hostapd_setup_bss(struct hostapd_data *hapd, int first, bool start_beacon)
return -1;
}
hapd->started = 1;
@@ -139,7 +139,7 @@
if (!first || first == -1) {
u8 *addr = hapd->own_addr;
-@@ -4285,7 +4287,7 @@ void hostapd_switch_color(struct hostapd_data *hapd, u64 bitmap)
+@@ -4289,7 +4291,7 @@ void hostapd_switch_color(struct hostapd_data *hapd, u64 bitmap)
{
struct os_reltime now;
@@ -149,10 +149,10 @@
if (os_get_reltime(&now))
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
-index 072205c..4f1f988 100644
+index 5bd1537fe..435dbd027 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
-@@ -191,6 +191,7 @@ struct hostapd_data {
+@@ -197,6 +197,7 @@ struct hostapd_data {
unsigned int started:1;
unsigned int disabled:1;
unsigned int reenable_beacon:1;
@@ -161,5 +161,5 @@
u8 own_addr[ETH_ALEN];
u8 mld_addr[ETH_ALEN];
--
-2.25.1
+2.39.2
diff --git a/recipes-wifi/wpa-supplicant/files/patches-2.10.3/mtk-0029-hostapd-mtk-Fix-CCA-issue.patch b/recipes-wifi/wpa-supplicant/files/patches-2.10.3/mtk-0029-hostapd-mtk-Fix-CCA-issue.patch
deleted file mode 100644
index 7196118..0000000
--- a/recipes-wifi/wpa-supplicant/files/patches-2.10.3/mtk-0029-hostapd-mtk-Fix-CCA-issue.patch
+++ /dev/null
@@ -1,97 +0,0 @@
-From ce585467d784d1015b5a40ec09895d0949690b04 Mon Sep 17 00:00:00 2001
-From: Michael Lee <michael-cy.lee@mediatek.com>
-Date: Wed, 3 May 2023 14:55:18 +0800
-Subject: [PATCH 29/32] hostapd: mtk: Fix CCA issue
-
-When receiving CCA-related nl80211 commands, hostapd used to work on
-struct wpa_driver_nl80211_data, whose ctx always points to
-hostpad_iface->bss[0]. However, CCA commands are sent on a per-BSS based.
-This patch makes hostapd handle CCA-related commands on a per-BSS based.
-
-Signed-off-by: Michael Lee <michael-cy.lee@mediatek.com>
----
- src/drivers/driver_nl80211_event.c | 24 ++++++++++++------------
- 1 file changed, 12 insertions(+), 12 deletions(-)
-
-diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c
-index 3d0d9b7bb..ab988fad7 100644
---- a/src/drivers/driver_nl80211_event.c
-+++ b/src/drivers/driver_nl80211_event.c
-@@ -3662,7 +3662,7 @@ static void nl80211_assoc_comeback(struct wpa_driver_nl80211_data *drv,
-
- #ifdef CONFIG_IEEE80211AX
-
--static void nl80211_obss_color_collision(struct wpa_driver_nl80211_data *drv,
-+static void nl80211_obss_color_collision(struct i802_bss *bss,
- struct nlattr *tb[])
- {
- union wpa_event_data data;
-@@ -3676,37 +3676,37 @@ static void nl80211_obss_color_collision(struct wpa_driver_nl80211_data *drv,
-
- wpa_printf(MSG_DEBUG, "nl80211: BSS color collision - bitmap %08llx",
- (long long unsigned int) data.bss_color_collision.bitmap);
-- wpa_supplicant_event(drv->ctx, EVENT_BSS_COLOR_COLLISION, &data);
-+ wpa_supplicant_event(bss->ctx, EVENT_BSS_COLOR_COLLISION, &data);
- }
-
-
- static void
--nl80211_color_change_announcement_started(struct wpa_driver_nl80211_data *drv)
-+nl80211_color_change_announcement_started(struct i802_bss *bss)
- {
- union wpa_event_data data = {};
-
- wpa_printf(MSG_DEBUG, "nl80211: CCA started");
-- wpa_supplicant_event(drv->ctx, EVENT_CCA_STARTED_NOTIFY, &data);
-+ wpa_supplicant_event(bss->ctx, EVENT_CCA_STARTED_NOTIFY, &data);
- }
-
-
- static void
--nl80211_color_change_announcement_aborted(struct wpa_driver_nl80211_data *drv)
-+nl80211_color_change_announcement_aborted(struct i802_bss *bss)
- {
- union wpa_event_data data = {};
-
- wpa_printf(MSG_DEBUG, "nl80211: CCA aborted");
-- wpa_supplicant_event(drv->ctx, EVENT_CCA_ABORTED_NOTIFY, &data);
-+ wpa_supplicant_event(bss->ctx, EVENT_CCA_ABORTED_NOTIFY, &data);
- }
-
-
- static void
--nl80211_color_change_announcement_completed(struct wpa_driver_nl80211_data *drv)
-+nl80211_color_change_announcement_completed(struct i802_bss *bss)
- {
- union wpa_event_data data = {};
-
- wpa_printf(MSG_DEBUG, "nl80211: CCA completed");
-- wpa_supplicant_event(drv->ctx, EVENT_CCA_NOTIFY, &data);
-+ wpa_supplicant_event(bss->ctx, EVENT_CCA_NOTIFY, &data);
- }
-
- #endif /* CONFIG_IEEE80211AX */
-@@ -3968,16 +3968,16 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd,
- break;
- #ifdef CONFIG_IEEE80211AX
- case NL80211_CMD_OBSS_COLOR_COLLISION:
-- nl80211_obss_color_collision(drv, tb);
-+ nl80211_obss_color_collision(bss, tb);
- break;
- case NL80211_CMD_COLOR_CHANGE_STARTED:
-- nl80211_color_change_announcement_started(drv);
-+ nl80211_color_change_announcement_started(bss);
- break;
- case NL80211_CMD_COLOR_CHANGE_ABORTED:
-- nl80211_color_change_announcement_aborted(drv);
-+ nl80211_color_change_announcement_aborted(bss);
- break;
- case NL80211_CMD_COLOR_CHANGE_COMPLETED:
-- nl80211_color_change_announcement_completed(drv);
-+ nl80211_color_change_announcement_completed(bss);
- break;
- #endif /* CONFIG_IEEE80211AX */
- default:
---
-2.39.2
-
diff --git a/recipes-wifi/wpa-supplicant/files/patches-2.10.3/mtk-0033-hostapd-mtk-Fix-background-channel-overlapping-opera.patch b/recipes-wifi/wpa-supplicant/files/patches-2.10.3/mtk-0033-hostapd-mtk-Fix-background-channel-overlapping-opera.patch
new file mode 100644
index 0000000..dd121ca
--- /dev/null
+++ b/recipes-wifi/wpa-supplicant/files/patches-2.10.3/mtk-0033-hostapd-mtk-Fix-background-channel-overlapping-opera.patch
@@ -0,0 +1,64 @@
+From 76e54b095fdd8ab65a562c28fba330afcfb519ec Mon Sep 17 00:00:00 2001
+From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
+Date: Wed, 5 Jul 2023 10:44:15 +0800
+Subject: [PATCH] hostapd: mtk: Fix background channel overlapping operating
+ channel issue
+
+Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
+---
+ src/ap/dfs.c | 18 ++++++++++++++++++
+ 1 file changed, 18 insertions(+)
+
+diff --git a/src/ap/dfs.c b/src/ap/dfs.c
+index 2f5c86e..c9a9c6c 100644
+--- a/src/ap/dfs.c
++++ b/src/ap/dfs.c
+@@ -807,6 +807,20 @@ static int dfs_are_channels_overlapped(struct hostapd_iface *iface, int freq,
+ }
+
+
++static void dfs_check_background_overlapped(struct hostapd_iface *iface)
++{
++ int width = hostapd_get_oper_chwidth(iface->conf);
++
++ if (!dfs_use_radar_background(iface))
++ return;
++
++ if (dfs_are_channels_overlapped(iface, iface->radar_background.freq,
++ width, iface->radar_background.centr_freq_seg0_idx,
++ iface->radar_background.centr_freq_seg1_idx))
++ iface->radar_background.channel = -1;
++}
++
++
+ static unsigned int dfs_get_cac_time(struct hostapd_iface *iface,
+ int start_chan_idx, int n_chans)
+ {
+@@ -1127,6 +1141,8 @@ static void hostpad_dfs_update_background_chain(struct hostapd_iface *iface)
+ &oper_centr_freq_seg1_idx,
+ &channel_type);
+ if (!channel ||
++ channel->chan == iface->conf->channel ||
++ channel->chan == iface->radar_background.channel ||
+ hostapd_start_dfs_cac(iface, iface->conf->hw_mode,
+ channel->freq, channel->chan,
+ iface->conf->ieee80211n,
+@@ -1361,6 +1377,7 @@ static int hostapd_dfs_start_channel_switch_cac(struct hostapd_iface *iface)
+ hostapd_set_oper_centr_freq_seg1_idx(iface->conf,
+ oper_centr_freq_seg1_idx);
+ err = 0;
++ dfs_check_background_overlapped(iface);
+
+ hostapd_setup_interface_complete(iface, err);
+ return err;
+@@ -1488,6 +1505,7 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
+ hostapd_set_oper_centr_freq_seg1_idx(
+ iface->conf, oper_centr_freq_seg1_idx);
+
++ dfs_check_background_overlapped(iface);
+ hostapd_disable_iface(iface);
+ hostapd_enable_iface(iface);
+ return 0;
+--
+2.18.0
+
diff --git a/recipes-wifi/wpa-supplicant/files/patches-2.10.3/mtk-0038-hostapd-mtk-Fix-11vmbss-aid-using-wrong-pool.patch b/recipes-wifi/wpa-supplicant/files/patches-2.10.3/mtk-0038-hostapd-mtk-Fix-11vmbss-aid-using-wrong-pool.patch
new file mode 100644
index 0000000..7cd34cd
--- /dev/null
+++ b/recipes-wifi/wpa-supplicant/files/patches-2.10.3/mtk-0038-hostapd-mtk-Fix-11vmbss-aid-using-wrong-pool.patch
@@ -0,0 +1,30 @@
+From 1671a37b5990929bd11823158d496e7877d83d92 Mon Sep 17 00:00:00 2001
+From: "Allen.Ye" <allen.ye@mediatek.com>
+Date: Wed, 2 Aug 2023 18:33:31 +0800
+Subject: [PATCH 38/38] hostapd: mtk: Fix 11vmbss aid using wrong pool
+
+Fix 11vmbss aid using wrong pool.
+All STAs use the aid pool in transmitted bss.
+
+Signed-off-by: Allen.Ye <allen.ye@mediatek.com>
+---
+ src/ap/ieee802_11.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
+index d36798e..f20073c 100755
+--- a/src/ap/ieee802_11.c
++++ b/src/ap/ieee802_11.c
+@@ -3307,6 +3307,9 @@ int hostapd_get_aid(struct hostapd_data *hapd, struct sta_info *sta)
+ {
+ int i, j = 32, aid;
+
++ if (hapd->iconf->mbssid)
++ hapd = hostapd_mbssid_get_tx_bss(hapd);
++
+ /* get a unique AID */
+ if (sta->aid > 0) {
+ wpa_printf(MSG_DEBUG, " old AID %d", sta->aid);
+--
+2.18.0
+
diff --git a/recipes-wifi/wpa-supplicant/files/patches-2.10.3/mtk-0039-hostapd-mtk-Fix-rnr-ie-length-when-no-need-to-report.patch b/recipes-wifi/wpa-supplicant/files/patches-2.10.3/mtk-0039-hostapd-mtk-Fix-rnr-ie-length-when-no-need-to-report.patch
new file mode 100644
index 0000000..9218f9b
--- /dev/null
+++ b/recipes-wifi/wpa-supplicant/files/patches-2.10.3/mtk-0039-hostapd-mtk-Fix-rnr-ie-length-when-no-need-to-report.patch
@@ -0,0 +1,34 @@
+From ea3e20d6cc8d11750e509a701131297da81ef35d Mon Sep 17 00:00:00 2001
+From: "Allen.Ye" <allen.ye@mediatek.com>
+Date: Mon, 7 Aug 2023 15:27:27 +0800
+Subject: [PATCH 39/39] hostapd: mtk: Fix rnr ie length when no need to report
+ bss
+
+Fix rnr ie length when no need to report bss. If we don't have content in
+TBTT then don't change the length of the ie (*size_offset).
+
+Signed-off-by: Allen.Ye <allen.ye@mediatek.com>
+---
+ src/ap/ieee802_11.c | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
+index f20073c..ef520c8 100755
+--- a/src/ap/ieee802_11.c
++++ b/src/ap/ieee802_11.c
+@@ -7494,8 +7494,10 @@ static u8 * hostapd_eid_rnr_iface(struct hostapd_data *hapd,
+ }
+
+ start = i;
+- *tbtt_count_pos = RNR_TBTT_INFO_COUNT(tbtt_count - 1);
+- *size_offset = (eid - size_offset) - 1;
++ if (tbtt_count != 0) {
++ *tbtt_count_pos = RNR_TBTT_INFO_COUNT(tbtt_count - 1);
++ *size_offset = (eid - size_offset) - 1;
++ }
+ }
+
+ if (tbtt_count == 0)
+--
+2.18.0
+
diff --git a/recipes-wifi/wpa-supplicant/files/patches-2.10.3/mtk-0040-hostapd-mtk-add-back-ht-vht-cap-missing-field-before.patch b/recipes-wifi/wpa-supplicant/files/patches-2.10.3/mtk-0040-hostapd-mtk-add-back-ht-vht-cap-missing-field-before.patch
new file mode 100644
index 0000000..0a27496
--- /dev/null
+++ b/recipes-wifi/wpa-supplicant/files/patches-2.10.3/mtk-0040-hostapd-mtk-add-back-ht-vht-cap-missing-field-before.patch
@@ -0,0 +1,44 @@
+From 2ea36366ea036e3063ff553a2939c9cac17c6ac8 Mon Sep 17 00:00:00 2001
+From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
+Date: Tue, 8 Aug 2023 19:21:41 +0800
+Subject: [PATCH] hostapd: mtk: add back ht vht cap missing field before dfs
+ channel fallback
+
+hostapd_event_ch_switch would set / clear ht_capab and vht_capab, based
+on the bandwidth of switched channel.
+For example, vht bw 160 support field would be cleared if we switch to
+non bw 160 channel.
+This design works fine with NON-DFS channel switch.
+However, for those DFS channels who require CAC, channel switch command
+calls hostapd_switch_channel_fallback instead of hostapd_switch_channel.
+This is simply restarting the interface not CHANNEL SWITCHING, so
+hostapd will not receive any ch_switch event from kernel.
+Therefore, the cleared field in vht_capab will not be set back to 1,
+even if we channel switch to dfs channel bw 160.
+
+Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
+---
+ src/ap/hostapd.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
+index c2e0b13..4b7ebc5 100644
+--- a/src/ap/hostapd.c
++++ b/src/ap/hostapd.c
+@@ -4161,6 +4161,13 @@ hostapd_switch_channel_fallback(struct hostapd_iface *iface,
+ break;
+ }
+
++ if ((iface->current_mode->ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET) &&
++ freq_params->bandwidth > 20)
++ iface->conf->ht_capab |= HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET;
++ if ((iface->current_mode->vht_capab & VHT_CAP_SUPP_CHAN_WIDTH_160MHZ) &&
++ freq_params->bandwidth == 160)
++ iface->conf->vht_capab |= VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
++
+ iface->freq = freq_params->freq;
+ iface->conf->channel = freq_params->channel;
+ iface->conf->secondary_channel = freq_params->sec_channel_offset;
+--
+2.18.0
+
diff --git a/recipes-wifi/wpa-supplicant/files/patches-2.10.3/patches.inc b/recipes-wifi/wpa-supplicant/files/patches-2.10.3/patches.inc
index 78dae59..89585bc 100644
--- a/recipes-wifi/wpa-supplicant/files/patches-2.10.3/patches.inc
+++ b/recipes-wifi/wpa-supplicant/files/patches-2.10.3/patches.inc
@@ -17,6 +17,7 @@
file://150-add-NULL-checks-encountered-during-tests-hwsim.patch \
file://160-dpp_pkex-EC-point-mul-w-value-prime.patch \
file://170-hostapd-update-cfs0-and-cfs1-for-160MHz.patch \
+ file://180-BSS-coloring-fix-CCA-with-multiple-BSS.patch \
file://200-multicall.patch \
file://300-noscan.patch \
file://301-mesh-noscan.patch \
@@ -46,8 +47,10 @@
file://590-rrm-wnm-statistics.patch \
file://599-wpa_supplicant-fix-warnings.patch \
file://600-ubus_support.patch \
+ file://601-ucode_support.patch \
file://610-hostapd_cli_ujail_permission.patch \
file://700-wifi-reload.patch \
+ file://701-reload_config_inline.patch \
file://710-vlan_no_bridge.patch \
file://711-wds_bridge_force.patch \
file://720-iface_max_num_sta.patch \
@@ -57,6 +60,7 @@
file://751-qos_map_ignore_when_unsupported.patch \
file://760-dynamic_own_ip.patch \
file://761-shared_das_port.patch \
+ file://770-radius_server.patch \
file://990-ctrl-make-WNM_AP-functions-dependant-on-CONFIG_AP.patch \
file://mtk-0001-hostapd-mtk-Add-neighbor-report-and-BSS-Termination-.patch \
file://mtk-0002-hostapd-mtk-print-sae-groups-by-hostapd-ctrl.patch \
@@ -83,17 +87,20 @@
file://mtk-0023-hostapd-mtk-Add-vendor-for-CAPI-certification-comman.patch \
file://mtk-0024-hostapd-mtk-Air-Monitor-support-in-hostapd-by-vendor.patch \
file://mtk-0025-hostapd-mtk-Fix-scan-result-updating-issue.patch \
- file://mtk-0026-hostapd-mtk-avoid-setting-beacon-after-wpa_supplican.patch \
+ file://mtk-0026-hostapd-mtk-Avoid-setting-beacon-after-wpa_supplican.patch \
file://mtk-0027-hostapd-mtk-Fix-setting-wrong-seg0-index-for-5G-cent.patch \
file://mtk-0028-hostapd-mtk-Add-muru-user-number-debug-command.patch \
- file://mtk-0029-hostapd-mtk-Fix-CCA-issue.patch \
file://mtk-0030-hostapd-mtk-Fix-unexpected-AP-beacon-state-transitio.patch \
file://mtk-0031-hostapd-mtk-add-connac3-PHY-MURU-manual-mode-config-.patch \
file://mtk-0032-hostapd-mtk-Add-HE-capabilities-check.patch \
+ file://mtk-0033-hostapd-mtk-Fix-background-channel-overlapping-opera.patch \
file://mtk-0034-hostapd-mtk-Fix-hostapd_dfs_start_cac-log.patch \
file://mtk-0035-hostapd-mtk-Check-the-bridge-after-ioctl-SIOCBRADDIF.patch \
file://mtk-0036-hostapd-mtk-Update-parameter_set_count-in-MU-EDCA-IE.patch \
file://mtk-0037-hostapd-mtk-Add-extension-IE-list-for-non-inherit-IE.patch \
+ file://mtk-0038-hostapd-mtk-Fix-11vmbss-aid-using-wrong-pool.patch \
+ file://mtk-0039-hostapd-mtk-Fix-rnr-ie-length-when-no-need-to-report.patch \
+ file://mtk-0040-hostapd-mtk-add-back-ht-vht-cap-missing-field-before.patch \
file://mtk-1000-hostapd-mtk-update-eht-operation-element.patch \
file://mtk-1001-hostapd-mtk-Add-support-for-gtk-rekeying-in-hostapd-.patch \
"
diff --git a/recipes-wifi/wpa-supplicant/files/patches/mtk-0006-hostapd-mtk-Add-hostapd-MU-SET-GET-control.patch b/recipes-wifi/wpa-supplicant/files/patches/mtk-0006-hostapd-mtk-Add-hostapd-MU-SET-GET-control.patch
index f51b42f..b3f4138 100644
--- a/recipes-wifi/wpa-supplicant/files/patches/mtk-0006-hostapd-mtk-Add-hostapd-MU-SET-GET-control.patch
+++ b/recipes-wifi/wpa-supplicant/files/patches/mtk-0006-hostapd-mtk-Add-hostapd-MU-SET-GET-control.patch
@@ -1,7 +1,7 @@
-From e063e89785d74506976e34a0a3cbb14836d6b8e3 Mon Sep 17 00:00:00 2001
+From 53a7b7af61b75ea0e3f9d12d3d6302cf40941a8a Mon Sep 17 00:00:00 2001
From: TomLiu <tomml.liu@mediatek.com>
Date: Tue, 9 Aug 2022 10:23:44 -0700
-Subject: [PATCH 06/35] hostapd: mtk: Add hostapd MU SET/GET control
+Subject: [PATCH 06/37] hostapd: mtk: Add hostapd MU SET/GET control
---
hostapd/config_file.c | 9 +++
@@ -156,14 +156,14 @@
{ "dpp_qr_code", hostapd_cli_cmd_dpp_qr_code, NULL,
"report a scanned DPP URI from a QR Code" },
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
-index 344585a..d4fc191 100644
+index 344585a..1b0e990 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -280,6 +280,7 @@ struct hostapd_config * hostapd_config_defaults(void)
conf->he_6ghz_max_ampdu_len_exp = 7;
conf->he_6ghz_rx_ant_pat = 1;
conf->he_6ghz_tx_ant_pat = 1;
-+ conf->mu_onoff = 13;
++ conf->mu_onoff = 0xf;
#endif /* CONFIG_IEEE80211AX */
/* The third octet of the country string uses an ASCII space character
@@ -446,5 +446,5 @@
}
--
-2.18.0
+2.39.0
diff --git a/recipes-wifi/wpa-supplicant/files/patches/mtk-0037-hostapd-mtk-Fix-11vmbss-aid-using-wrong-pool.patch b/recipes-wifi/wpa-supplicant/files/patches/mtk-0037-hostapd-mtk-Fix-11vmbss-aid-using-wrong-pool.patch
new file mode 100644
index 0000000..aff2234
--- /dev/null
+++ b/recipes-wifi/wpa-supplicant/files/patches/mtk-0037-hostapd-mtk-Fix-11vmbss-aid-using-wrong-pool.patch
@@ -0,0 +1,30 @@
+From 845f192fe55b4774425752ecba8cb8f5c4e24c69 Mon Sep 17 00:00:00 2001
+From: "Allen.Ye" <allen.ye@mediatek.com>
+Date: Wed, 2 Aug 2023 18:33:31 +0800
+Subject: [PATCH 37/38] hostapd: mtk: Fix 11vmbss aid using wrong pool
+
+Fix 11vmbss aid using wrong pool.
+All STAs use the aid pool in transmitted bss.
+
+Signed-off-by: Allen.Ye <allen.ye@mediatek.com>
+---
+ src/ap/ieee802_11.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
+index f866b8a..b73b821 100644
+--- a/src/ap/ieee802_11.c
++++ b/src/ap/ieee802_11.c
+@@ -4002,6 +4002,9 @@ int hostapd_get_aid(struct hostapd_data *hapd, struct sta_info *sta)
+ {
+ int i, j = 32, aid;
+
++ if (hapd->iconf->mbssid)
++ hapd = hostapd_mbssid_get_tx_bss(hapd);
++
+ /* get a unique AID */
+ if (sta->aid > 0) {
+ wpa_printf(MSG_DEBUG, " old AID %d", sta->aid);
+--
+2.18.0
+
diff --git a/recipes-wifi/wpa-supplicant/files/patches/mtk-0037-hostapd-mtk-add-back-ht-vht-cap-missing-field-before.patch b/recipes-wifi/wpa-supplicant/files/patches/mtk-0037-hostapd-mtk-add-back-ht-vht-cap-missing-field-before.patch
new file mode 100644
index 0000000..ec82302
--- /dev/null
+++ b/recipes-wifi/wpa-supplicant/files/patches/mtk-0037-hostapd-mtk-add-back-ht-vht-cap-missing-field-before.patch
@@ -0,0 +1,44 @@
+From 87ed81b81030cb5567c04227d0fe65c6a15148f3 Mon Sep 17 00:00:00 2001
+From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
+Date: Tue, 8 Aug 2023 19:21:41 +0800
+Subject: [PATCH] hostapd: mtk: add back ht vht cap missing field before dfs
+ channel fallback
+
+hostapd_event_ch_switch would set / clear ht_capab and vht_capab, based
+on the bandwidth of switched channel.
+For example, vht bw 160 support field would be cleared if we switch to
+non bw 160 channel.
+This design works fine with NON-DFS channel switch.
+However, for those DFS channels who require CAC, channel switch command
+calls hostapd_switch_channel_fallback instead of hostapd_switch_channel.
+This is simply restarting the interface not CHANNEL SWITCHING, so
+hostapd will not receive any ch_switch event from kernel.
+Therefore, the cleared field in vht_capab will not be set back to 1,
+even if we channel switch to dfs channel bw 160.
+
+Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
+---
+ src/ap/hostapd.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
+index 707e7d5..5d17cf8 100644
+--- a/src/ap/hostapd.c
++++ b/src/ap/hostapd.c
+@@ -3888,6 +3888,13 @@ hostapd_switch_channel_fallback(struct hostapd_iface *iface,
+ break;
+ }
+
++ if ((iface->current_mode->ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET) &&
++ freq_params->bandwidth > 20)
++ iface->conf->ht_capab |= HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET;
++ if ((iface->current_mode->vht_capab & VHT_CAP_SUPP_CHAN_WIDTH_160MHZ) &&
++ freq_params->bandwidth == 160)
++ iface->conf->vht_capab |= VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
++
+ iface->freq = freq_params->freq;
+ iface->conf->channel = freq_params->channel;
+ iface->conf->secondary_channel = freq_params->sec_channel_offset;
+--
+2.18.0
+
diff --git a/recipes-wifi/wpa-supplicant/files/patches/mtk-0038-hostapd-mtk-Fix-rnr-ie-length-when-no-need-to-report.patch b/recipes-wifi/wpa-supplicant/files/patches/mtk-0038-hostapd-mtk-Fix-rnr-ie-length-when-no-need-to-report.patch
new file mode 100644
index 0000000..d6fa8b6
--- /dev/null
+++ b/recipes-wifi/wpa-supplicant/files/patches/mtk-0038-hostapd-mtk-Fix-rnr-ie-length-when-no-need-to-report.patch
@@ -0,0 +1,34 @@
+From 70c8f9355c4df3c083965ce652d33e01f8fe7e7c Mon Sep 17 00:00:00 2001
+From: "Allen.Ye" <allen.ye@mediatek.com>
+Date: Mon, 7 Aug 2023 15:27:27 +0800
+Subject: [PATCH 38/38] hostapd: mtk: Fix rnr ie length when no need to report
+ bss
+
+Fix rnr ie length when no need to report bss. If we don't have content in
+TBTT then don't change the length of the ie (*size_offset).
+
+Signed-off-by: Allen.Ye <allen.ye@mediatek.com>
+---
+ src/ap/ieee802_11.c | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
+index b73b821..ff39fad 100644
+--- a/src/ap/ieee802_11.c
++++ b/src/ap/ieee802_11.c
+@@ -7530,8 +7530,10 @@ static u8 * hostapd_eid_rnr_iface(struct hostapd_data *hapd,
+ }
+
+ start = i;
+- *tbtt_count_pos = RNR_TBTT_INFO_COUNT(tbtt_count - 1);
+- *size_offset = (eid - size_offset) - 1;
++ if (tbtt_count != 0) {
++ *tbtt_count_pos = RNR_TBTT_INFO_COUNT(tbtt_count - 1);
++ *size_offset = (eid - size_offset) - 1;
++ }
+ }
+
+ if (tbtt_count == 0)
+--
+2.18.0
+
diff --git a/recipes-wifi/wpa-supplicant/files/patches/patches.inc b/recipes-wifi/wpa-supplicant/files/patches/patches.inc
index 3e8cc14..f783c48 100644
--- a/recipes-wifi/wpa-supplicant/files/patches/patches.inc
+++ b/recipes-wifi/wpa-supplicant/files/patches/patches.inc
@@ -99,4 +99,7 @@
file://mtk-0035-hostapd-mtk-add-extension-IE-list-for-non-inherit-IE.patch \
file://mtk-0036-hostapd-mtk-Fix-background-channel-overlapping-opera.patch \
file://mtk-0036-hostapd-mtk-Fix-wpa_supplicant-configuration-parsing.patch \
+ file://mtk-0037-hostapd-mtk-Fix-11vmbss-aid-using-wrong-pool.patch \
+ file://mtk-0037-hostapd-mtk-add-back-ht-vht-cap-missing-field-before.patch \
+ file://mtk-0038-hostapd-mtk-Fix-rnr-ie-length-when-no-need-to-report.patch \
"
diff --git a/recipes-wifi/wpa-supplicant/files/src-2.10.3/hostapd/radius.c b/recipes-wifi/wpa-supplicant/files/src-2.10.3/hostapd/radius.c
new file mode 100644
index 0000000..362a22c
--- /dev/null
+++ b/recipes-wifi/wpa-supplicant/files/src-2.10.3/hostapd/radius.c
@@ -0,0 +1,715 @@
+#include "utils/includes.h"
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "crypto/crypto.h"
+#include "crypto/tls.h"
+
+#include "ap/ap_config.h"
+#include "eap_server/eap.h"
+#include "radius/radius.h"
+#include "radius/radius_server.h"
+#include "eap_register.h"
+
+#include <libubox/blobmsg_json.h>
+#include <libubox/blobmsg.h>
+#include <libubox/avl.h>
+#include <libubox/avl-cmp.h>
+#include <libubox/kvlist.h>
+
+#include <sys/stat.h>
+#include <fnmatch.h>
+
+#define VENDOR_ID_WISPR 14122
+#define VENDOR_ATTR_SIZE 6
+
+struct radius_parse_attr_data {
+ unsigned int vendor;
+ u8 type;
+ int size;
+ char format;
+ const char *data;
+};
+
+struct radius_parse_attr_state {
+ struct hostapd_radius_attr *prev;
+ struct hostapd_radius_attr *attr;
+ struct wpabuf *buf;
+ void *attrdata;
+};
+
+struct radius_user_state {
+ struct avl_node node;
+ struct eap_user data;
+};
+
+struct radius_user_data {
+ struct kvlist users;
+ struct avl_tree user_state;
+ struct blob_attr *wildcard;
+};
+
+struct radius_state {
+ struct radius_server_data *radius;
+ struct eap_config eap;
+
+ struct radius_user_data phase1, phase2;
+ const char *user_file;
+ time_t user_file_ts;
+
+ int n_attrs;
+ struct hostapd_radius_attr *attrs;
+};
+
+struct radius_config {
+ struct tls_connection_params tls;
+ struct radius_server_conf radius;
+};
+
+enum {
+ USER_ATTR_PASSWORD,
+ USER_ATTR_HASH,
+ USER_ATTR_SALT,
+ USER_ATTR_METHODS,
+ USER_ATTR_RADIUS,
+ USER_ATTR_VLAN,
+ USER_ATTR_MAX_RATE_UP,
+ USER_ATTR_MAX_RATE_DOWN,
+ __USER_ATTR_MAX
+};
+
+static void radius_tls_event(void *ctx, enum tls_event ev,
+ union tls_event_data *data)
+{
+ switch (ev) {
+ case TLS_CERT_CHAIN_SUCCESS:
+ wpa_printf(MSG_DEBUG, "radius: remote certificate verification success");
+ break;
+ case TLS_CERT_CHAIN_FAILURE:
+ wpa_printf(MSG_INFO, "radius: certificate chain failure: reason=%d depth=%d subject='%s' err='%s'",
+ data->cert_fail.reason,
+ data->cert_fail.depth,
+ data->cert_fail.subject,
+ data->cert_fail.reason_txt);
+ break;
+ case TLS_PEER_CERTIFICATE:
+ wpa_printf(MSG_DEBUG, "radius: peer certificate: depth=%d serial_num=%s subject=%s",
+ data->peer_cert.depth,
+ data->peer_cert.serial_num ? data->peer_cert.serial_num : "N/A",
+ data->peer_cert.subject);
+ break;
+ case TLS_ALERT:
+ if (data->alert.is_local)
+ wpa_printf(MSG_DEBUG, "radius: local TLS alert: %s",
+ data->alert.description);
+ else
+ wpa_printf(MSG_DEBUG, "radius: remote TLS alert: %s",
+ data->alert.description);
+ break;
+ case TLS_UNSAFE_RENEGOTIATION_DISABLED:
+ /* Not applicable to TLS server */
+ break;
+ }
+}
+
+static void radius_userdata_init(struct radius_user_data *u)
+{
+ kvlist_init(&u->users, kvlist_blob_len);
+ avl_init(&u->user_state, avl_strcmp, false, NULL);
+}
+
+static void radius_userdata_free(struct radius_user_data *u)
+{
+ struct radius_user_state *s, *tmp;
+
+ kvlist_free(&u->users);
+ free(u->wildcard);
+ u->wildcard = NULL;
+ avl_remove_all_elements(&u->user_state, s, node, tmp)
+ free(s);
+}
+
+static void
+radius_userdata_load(struct radius_user_data *u, struct blob_attr *data)
+{
+ enum {
+ USERSTATE_USERS,
+ USERSTATE_WILDCARD,
+ __USERSTATE_MAX,
+ };
+ static const struct blobmsg_policy policy[__USERSTATE_MAX] = {
+ [USERSTATE_USERS] = { "users", BLOBMSG_TYPE_TABLE },
+ [USERSTATE_WILDCARD] = { "wildcard", BLOBMSG_TYPE_ARRAY },
+ };
+ struct blob_attr *tb[__USERSTATE_MAX], *cur;
+ int rem;
+
+ if (!data)
+ return;
+
+ blobmsg_parse(policy, __USERSTATE_MAX, tb, blobmsg_data(data), blobmsg_len(data));
+
+ blobmsg_for_each_attr(cur, tb[USERSTATE_USERS], rem)
+ kvlist_set(&u->users, blobmsg_name(cur), cur);
+
+ if (tb[USERSTATE_WILDCARD])
+ u->wildcard = blob_memdup(tb[USERSTATE_WILDCARD]);
+}
+
+static void
+load_userfile(struct radius_state *s)
+{
+ enum {
+ USERDATA_PHASE1,
+ USERDATA_PHASE2,
+ __USERDATA_MAX
+ };
+ static const struct blobmsg_policy policy[__USERDATA_MAX] = {
+ [USERDATA_PHASE1] = { "phase1", BLOBMSG_TYPE_TABLE },
+ [USERDATA_PHASE2] = { "phase2", BLOBMSG_TYPE_TABLE },
+ };
+ struct blob_attr *tb[__USERDATA_MAX], *cur;
+ static struct blob_buf b;
+ struct stat st;
+ int rem;
+
+ if (stat(s->user_file, &st))
+ return;
+
+ if (s->user_file_ts == st.st_mtime)
+ return;
+
+ s->user_file_ts = st.st_mtime;
+ radius_userdata_free(&s->phase1);
+ radius_userdata_free(&s->phase2);
+
+ blob_buf_init(&b, 0);
+ blobmsg_add_json_from_file(&b, s->user_file);
+ blobmsg_parse(policy, __USERDATA_MAX, tb, blob_data(b.head), blob_len(b.head));
+ radius_userdata_load(&s->phase1, tb[USERDATA_PHASE1]);
+ radius_userdata_load(&s->phase2, tb[USERDATA_PHASE2]);
+
+ blob_buf_free(&b);
+}
+
+static struct blob_attr *
+radius_user_get(struct radius_user_data *s, const char *name)
+{
+ struct blob_attr *cur;
+ int rem;
+
+ cur = kvlist_get(&s->users, name);
+ if (cur)
+ return cur;
+
+ blobmsg_for_each_attr(cur, s->wildcard, rem) {
+ static const struct blobmsg_policy policy = {
+ "name", BLOBMSG_TYPE_STRING
+ };
+ struct blob_attr *pattern;
+
+ if (blobmsg_type(cur) != BLOBMSG_TYPE_TABLE)
+ continue;
+
+ blobmsg_parse(&policy, 1, &pattern, blobmsg_data(cur), blobmsg_len(cur));
+ if (!name)
+ continue;
+
+ if (!fnmatch(blobmsg_get_string(pattern), name, 0))
+ return cur;
+ }
+
+ return NULL;
+}
+
+static struct radius_parse_attr_data *
+radius_parse_attr(struct blob_attr *attr)
+{
+ static const struct blobmsg_policy policy[4] = {
+ { .type = BLOBMSG_TYPE_INT32 },
+ { .type = BLOBMSG_TYPE_INT32 },
+ { .type = BLOBMSG_TYPE_STRING },
+ { .type = BLOBMSG_TYPE_STRING },
+ };
+ static struct radius_parse_attr_data data;
+ struct blob_attr *tb[4];
+ const char *format;
+
+ blobmsg_parse_array(policy, ARRAY_SIZE(policy), tb, blobmsg_data(attr), blobmsg_len(attr));
+
+ if (!tb[0] || !tb[1] || !tb[2] || !tb[3])
+ return NULL;
+
+ format = blobmsg_get_string(tb[2]);
+ if (strlen(format) != 1)
+ return NULL;
+
+ data.vendor = blobmsg_get_u32(tb[0]);
+ data.type = blobmsg_get_u32(tb[1]);
+ data.format = format[0];
+ data.data = blobmsg_get_string(tb[3]);
+ data.size = strlen(data.data);
+
+ switch (data.format) {
+ case 's':
+ break;
+ case 'x':
+ if (data.size & 1)
+ return NULL;
+ data.size /= 2;
+ break;
+ case 'd':
+ data.size = 4;
+ break;
+ default:
+ return NULL;
+ }
+
+ return &data;
+}
+
+static void
+radius_count_attrs(struct blob_attr **tb, int *n_attr, size_t *attr_size)
+{
+ struct blob_attr *data = tb[USER_ATTR_RADIUS];
+ struct blob_attr *cur;
+ int rem;
+
+ blobmsg_for_each_attr(cur, data, rem) {
+ struct radius_parse_attr_data *data;
+ size_t prev = *attr_size;
+
+ data = radius_parse_attr(cur);
+ if (!data)
+ continue;
+
+ *attr_size += data->size;
+ if (data->vendor)
+ *attr_size += VENDOR_ATTR_SIZE;
+
+ (*n_attr)++;
+ }
+
+ *n_attr += !!tb[USER_ATTR_VLAN] * 3 +
+ !!tb[USER_ATTR_MAX_RATE_UP] +
+ !!tb[USER_ATTR_MAX_RATE_DOWN];
+ *attr_size += !!tb[USER_ATTR_VLAN] * (4 + 4 + 5) +
+ !!tb[USER_ATTR_MAX_RATE_UP] * (4 + VENDOR_ATTR_SIZE) +
+ !!tb[USER_ATTR_MAX_RATE_DOWN] * (4 + VENDOR_ATTR_SIZE);
+}
+
+static void *
+radius_add_attr(struct radius_parse_attr_state *state,
+ u32 vendor, u8 type, u8 len)
+{
+ struct hostapd_radius_attr *attr;
+ struct wpabuf *buf;
+ void *val;
+
+ val = state->attrdata;
+
+ buf = state->buf++;
+ buf->buf = val;
+
+ attr = state->attr++;
+ attr->val = buf;
+ attr->type = type;
+
+ if (state->prev)
+ state->prev->next = attr;
+ state->prev = attr;
+
+ if (vendor) {
+ u8 *vendor_hdr = val + 4;
+
+ WPA_PUT_BE32(val, vendor);
+ vendor_hdr[0] = type;
+ vendor_hdr[1] = len + 2;
+
+ len += VENDOR_ATTR_SIZE;
+ val += VENDOR_ATTR_SIZE;
+ attr->type = RADIUS_ATTR_VENDOR_SPECIFIC;
+ }
+
+ buf->size = buf->used = len;
+ state->attrdata += len;
+
+ return val;
+}
+
+static void
+radius_parse_attrs(struct blob_attr **tb, struct radius_parse_attr_state *state)
+{
+ struct blob_attr *data = tb[USER_ATTR_RADIUS];
+ struct hostapd_radius_attr *prev = NULL;
+ struct blob_attr *cur;
+ int len, rem;
+ void *val;
+
+ if ((cur = tb[USER_ATTR_VLAN]) != NULL && blobmsg_get_u32(cur) < 4096) {
+ char buf[5];
+
+ val = radius_add_attr(state, 0, RADIUS_ATTR_TUNNEL_TYPE, 4);
+ WPA_PUT_BE32(val, RADIUS_TUNNEL_TYPE_VLAN);
+
+ val = radius_add_attr(state, 0, RADIUS_ATTR_TUNNEL_MEDIUM_TYPE, 4);
+ WPA_PUT_BE32(val, RADIUS_TUNNEL_MEDIUM_TYPE_802);
+
+ len = snprintf(buf, sizeof(buf), "%d", blobmsg_get_u32(cur));
+ val = radius_add_attr(state, 0, RADIUS_ATTR_TUNNEL_PRIVATE_GROUP_ID, len);
+ memcpy(val, buf, len);
+ }
+
+ if ((cur = tb[USER_ATTR_MAX_RATE_UP]) != NULL) {
+ val = radius_add_attr(state, VENDOR_ID_WISPR, 7, 4);
+ WPA_PUT_BE32(val, blobmsg_get_u32(cur));
+ }
+
+ if ((cur = tb[USER_ATTR_MAX_RATE_DOWN]) != NULL) {
+ val = radius_add_attr(state, VENDOR_ID_WISPR, 8, 4);
+ WPA_PUT_BE32(val, blobmsg_get_u32(cur));
+ }
+
+ blobmsg_for_each_attr(cur, data, rem) {
+ struct radius_parse_attr_data *data;
+ void *val;
+ int size;
+
+ data = radius_parse_attr(cur);
+ if (!data)
+ continue;
+
+ val = radius_add_attr(state, data->vendor, data->type, data->size);
+ switch (data->format) {
+ case 's':
+ memcpy(val, data->data, data->size);
+ break;
+ case 'x':
+ hexstr2bin(data->data, val, data->size);
+ break;
+ case 'd':
+ WPA_PUT_BE32(val, atoi(data->data));
+ break;
+ }
+ }
+}
+
+static void
+radius_user_parse_methods(struct eap_user *eap, struct blob_attr *data)
+{
+ struct blob_attr *cur;
+ int rem, n = 0;
+
+ if (!data)
+ return;
+
+ blobmsg_for_each_attr(cur, data, rem) {
+ const char *method;
+
+ if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING)
+ continue;
+
+ if (n == EAP_MAX_METHODS)
+ break;
+
+ method = blobmsg_get_string(cur);
+ eap->methods[n].method = eap_server_get_type(method, &eap->methods[n].vendor);
+ if (eap->methods[n].vendor == EAP_VENDOR_IETF &&
+ eap->methods[n].method == EAP_TYPE_NONE) {
+ if (!strcmp(method, "TTLS-PAP")) {
+ eap->ttls_auth |= EAP_TTLS_AUTH_PAP;
+ continue;
+ }
+ if (!strcmp(method, "TTLS-CHAP")) {
+ eap->ttls_auth |= EAP_TTLS_AUTH_CHAP;
+ continue;
+ }
+ if (!strcmp(method, "TTLS-MSCHAP")) {
+ eap->ttls_auth |= EAP_TTLS_AUTH_MSCHAP;
+ continue;
+ }
+ if (!strcmp(method, "TTLS-MSCHAPV2")) {
+ eap->ttls_auth |= EAP_TTLS_AUTH_MSCHAPV2;
+ continue;
+ }
+ }
+ n++;
+ }
+}
+
+static struct eap_user *
+radius_user_get_state(struct radius_user_data *u, struct blob_attr *data,
+ const char *id)
+{
+ static const struct blobmsg_policy policy[__USER_ATTR_MAX] = {
+ [USER_ATTR_PASSWORD] = { "password", BLOBMSG_TYPE_STRING },
+ [USER_ATTR_HASH] = { "hash", BLOBMSG_TYPE_STRING },
+ [USER_ATTR_SALT] = { "salt", BLOBMSG_TYPE_STRING },
+ [USER_ATTR_METHODS] = { "methods", BLOBMSG_TYPE_ARRAY },
+ [USER_ATTR_RADIUS] = { "radius", BLOBMSG_TYPE_ARRAY },
+ [USER_ATTR_VLAN] = { "vlan-id", BLOBMSG_TYPE_INT32 },
+ [USER_ATTR_MAX_RATE_UP] = { "max-rate-up", BLOBMSG_TYPE_INT32 },
+ [USER_ATTR_MAX_RATE_DOWN] = { "max-rate-down", BLOBMSG_TYPE_INT32 },
+ };
+ struct blob_attr *tb[__USER_ATTR_MAX], *cur;
+ char *password_buf, *salt_buf, *name_buf;
+ struct radius_parse_attr_state astate = {};
+ struct hostapd_radius_attr *attr;
+ struct radius_user_state *state;
+ int pw_len = 0, salt_len = 0;
+ struct eap_user *eap;
+ struct wpabuf *val;
+ size_t attrsize = 0;
+ void *attrdata;
+ int n_attr = 0;
+
+ state = avl_find_element(&u->user_state, id, state, node);
+ if (state)
+ return &state->data;
+
+ blobmsg_parse(policy, __USER_ATTR_MAX, tb, blobmsg_data(data), blobmsg_len(data));
+
+ if ((cur = tb[USER_ATTR_SALT]) != NULL)
+ salt_len = strlen(blobmsg_get_string(cur)) / 2;
+ if ((cur = tb[USER_ATTR_HASH]) != NULL)
+ pw_len = strlen(blobmsg_get_string(cur)) / 2;
+ else if ((cur = tb[USER_ATTR_PASSWORD]) != NULL)
+ pw_len = blobmsg_len(cur) - 1;
+ radius_count_attrs(tb, &n_attr, &attrsize);
+
+ state = calloc_a(sizeof(*state), &name_buf, strlen(id) + 1,
+ &password_buf, pw_len,
+ &salt_buf, salt_len,
+ &astate.attr, n_attr * sizeof(*astate.attr),
+ &astate.buf, n_attr * sizeof(*astate.buf),
+ &astate.attrdata, attrsize);
+ eap = &state->data;
+ eap->salt = salt_len ? salt_buf : NULL;
+ eap->salt_len = salt_len;
+ eap->password = pw_len ? password_buf : NULL;
+ eap->password_len = pw_len;
+ eap->force_version = -1;
+
+ if ((cur = tb[USER_ATTR_SALT]) != NULL)
+ hexstr2bin(blobmsg_get_string(cur), salt_buf, salt_len);
+ if ((cur = tb[USER_ATTR_PASSWORD]) != NULL)
+ memcpy(password_buf, blobmsg_get_string(cur), pw_len);
+ else if ((cur = tb[USER_ATTR_HASH]) != NULL) {
+ hexstr2bin(blobmsg_get_string(cur), password_buf, pw_len);
+ eap->password_hash = 1;
+ }
+ radius_user_parse_methods(eap, tb[USER_ATTR_METHODS]);
+
+ if (n_attr > 0) {
+ cur = tb[USER_ATTR_RADIUS];
+ eap->accept_attr = astate.attr;
+ radius_parse_attrs(tb, &astate);
+ }
+
+ state->node.key = strcpy(name_buf, id);
+ avl_insert(&u->user_state, &state->node);
+
+ return &state->data;
+
+free:
+ free(state);
+ return NULL;
+}
+
+static int radius_get_eap_user(void *ctx, const u8 *identity,
+ size_t identity_len, int phase2,
+ struct eap_user *user)
+{
+ struct radius_state *s = ctx;
+ struct radius_user_data *u = phase2 ? &s->phase2 : &s->phase1;
+ struct blob_attr *entry;
+ struct eap_user *data;
+ char *id;
+
+ if (identity_len > 512)
+ return -1;
+
+ load_userfile(s);
+
+ id = alloca(identity_len + 1);
+ memcpy(id, identity, identity_len);
+ id[identity_len] = 0;
+
+ entry = radius_user_get(u, id);
+ if (!entry)
+ return -1;
+
+ if (!user)
+ return 0;
+
+ data = radius_user_get_state(u, entry, id);
+ if (!data)
+ return -1;
+
+ *user = *data;
+ if (user->password_len > 0)
+ user->password = os_memdup(user->password, user->password_len);
+ if (user->salt_len > 0)
+ user->salt = os_memdup(user->salt, user->salt_len);
+ user->phase2 = phase2;
+
+ return 0;
+}
+
+static int radius_setup(struct radius_state *s, struct radius_config *c)
+{
+ struct eap_config *eap = &s->eap;
+ struct tls_config conf = {
+ .event_cb = radius_tls_event,
+ .tls_flags = TLS_CONN_DISABLE_TLSv1_3,
+ .cb_ctx = s,
+ };
+
+ eap->eap_server = 1;
+ eap->max_auth_rounds = 100;
+ eap->max_auth_rounds_short = 50;
+ eap->ssl_ctx = tls_init(&conf);
+ if (!eap->ssl_ctx) {
+ wpa_printf(MSG_INFO, "TLS init failed\n");
+ return 1;
+ }
+
+ if (tls_global_set_params(eap->ssl_ctx, &c->tls)) {
+ wpa_printf(MSG_INFO, "failed to set TLS parameters\n");
+ return 1;
+ }
+
+ c->radius.eap_cfg = eap;
+ c->radius.conf_ctx = s;
+ c->radius.get_eap_user = radius_get_eap_user;
+ s->radius = radius_server_init(&c->radius);
+ if (!s->radius) {
+ wpa_printf(MSG_INFO, "failed to initialize radius server\n");
+ return 1;
+ }
+
+ return 0;
+}
+
+static int radius_init(struct radius_state *s)
+{
+ memset(s, 0, sizeof(*s));
+ radius_userdata_init(&s->phase1);
+ radius_userdata_init(&s->phase2);
+}
+
+static void radius_deinit(struct radius_state *s)
+{
+ if (s->radius)
+ radius_server_deinit(s->radius);
+
+ if (s->eap.ssl_ctx)
+ tls_deinit(s->eap.ssl_ctx);
+
+ radius_userdata_free(&s->phase1);
+ radius_userdata_free(&s->phase2);
+}
+
+static int usage(const char *progname)
+{
+ fprintf(stderr, "Usage: %s <options>\n",
+ progname);
+}
+
+int radius_main(int argc, char **argv)
+{
+ static struct radius_state state = {};
+ static struct radius_config config = {};
+ const char *progname = argv[0];
+ int ret = 0;
+ int ch;
+
+ wpa_debug_setup_stdout();
+ wpa_debug_level = 0;
+
+ if (eloop_init()) {
+ wpa_printf(MSG_ERROR, "Failed to initialize event loop");
+ return 1;
+ }
+
+ eap_server_register_methods();
+ radius_init(&state);
+
+ while ((ch = getopt(argc, argv, "6C:c:d:i:k:K:p:P:s:u:")) != -1) {
+ switch (ch) {
+ case '6':
+ config.radius.ipv6 = 1;
+ break;
+ case 'C':
+ config.tls.ca_cert = optarg;
+ break;
+ case 'c':
+ if (config.tls.client_cert2)
+ return usage(progname);
+
+ if (config.tls.client_cert)
+ config.tls.client_cert2 = optarg;
+ else
+ config.tls.client_cert = optarg;
+ break;
+ case 'd':
+ config.tls.dh_file = optarg;
+ break;
+ case 'i':
+ state.eap.server_id = optarg;
+ state.eap.server_id_len = strlen(optarg);
+ break;
+ case 'k':
+ if (config.tls.private_key2)
+ return usage(progname);
+
+ if (config.tls.private_key)
+ config.tls.private_key2 = optarg;
+ else
+ config.tls.private_key = optarg;
+ break;
+ case 'K':
+ if (config.tls.private_key_passwd2)
+ return usage(progname);
+
+ if (config.tls.private_key_passwd)
+ config.tls.private_key_passwd2 = optarg;
+ else
+ config.tls.private_key_passwd = optarg;
+ break;
+ case 'p':
+ config.radius.auth_port = atoi(optarg);
+ break;
+ case 'P':
+ config.radius.acct_port = atoi(optarg);
+ break;
+ case 's':
+ config.radius.client_file = optarg;
+ break;
+ case 'u':
+ state.user_file = optarg;
+ break;
+ default:
+ return usage(progname);
+ }
+ }
+
+ if (!config.tls.client_cert || !config.tls.private_key ||
+ !config.radius.client_file || !state.eap.server_id ||
+ !state.user_file) {
+ wpa_printf(MSG_INFO, "missing options\n");
+ goto out;
+ }
+
+ ret = radius_setup(&state, &config);
+ if (ret)
+ goto out;
+
+ load_userfile(&state);
+ eloop_run();
+
+out:
+ radius_deinit(&state);
+ os_program_deinit();
+
+ return ret;
+}
diff --git a/recipes-wifi/wpa-supplicant/files/src-2.10.3/src/ap/ubus.c b/recipes-wifi/wpa-supplicant/files/src-2.10.3/src/ap/ubus.c
new file mode 100644
index 0000000..a609eb1
--- /dev/null
+++ b/recipes-wifi/wpa-supplicant/files/src-2.10.3/src/ap/ubus.c
@@ -0,0 +1,2002 @@
+/*
+ * hostapd / ubus support
+ * Copyright (c) 2013, Felix Fietkau <nbd@nbd.name>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "utils/wpabuf.h"
+#include "common/ieee802_11_defs.h"
+#include "common/hw_features_common.h"
+#include "hostapd.h"
+#include "neighbor_db.h"
+#include "wps_hostapd.h"
+#include "sta_info.h"
+#include "ubus.h"
+#include "ap_drv_ops.h"
+#include "beacon.h"
+#include "rrm.h"
+#include "wnm_ap.h"
+#include "taxonomy.h"
+#include "airtime_policy.h"
+#include "hw_features.h"
+
+static struct ubus_context *ctx;
+static struct blob_buf b;
+static int ctx_ref;
+
+static inline struct hostapd_data *get_hapd_from_object(struct ubus_object *obj)
+{
+ return container_of(obj, struct hostapd_data, ubus.obj);
+}
+
+struct ubus_banned_client {
+ struct avl_node avl;
+ u8 addr[ETH_ALEN];
+};
+
+static void ubus_reconnect_timeout(void *eloop_data, void *user_ctx)
+{
+ if (ubus_reconnect(ctx, NULL)) {
+ eloop_register_timeout(1, 0, ubus_reconnect_timeout, ctx, NULL);
+ return;
+ }
+
+ ubus_add_uloop(ctx);
+}
+
+static void hostapd_ubus_connection_lost(struct ubus_context *ctx)
+{
+ uloop_fd_delete(&ctx->sock);
+ eloop_register_timeout(1, 0, ubus_reconnect_timeout, ctx, NULL);
+}
+
+static bool hostapd_ubus_init(void)
+{
+ if (ctx)
+ return true;
+
+ eloop_add_uloop();
+ ctx = ubus_connect(NULL);
+ if (!ctx)
+ return false;
+
+ ctx->connection_lost = hostapd_ubus_connection_lost;
+ ubus_add_uloop(ctx);
+
+ return true;
+}
+
+static void hostapd_ubus_ref_inc(void)
+{
+ ctx_ref++;
+}
+
+static void hostapd_ubus_ref_dec(void)
+{
+ ctx_ref--;
+ if (!ctx)
+ return;
+
+ if (ctx_ref)
+ return;
+
+ uloop_fd_delete(&ctx->sock);
+ ubus_free(ctx);
+ ctx = NULL;
+}
+
+void hostapd_ubus_add_iface(struct hostapd_iface *iface)
+{
+ if (!hostapd_ubus_init())
+ return;
+}
+
+void hostapd_ubus_free_iface(struct hostapd_iface *iface)
+{
+ if (!ctx)
+ return;
+}
+
+static void hostapd_notify_ubus(struct ubus_object *obj, char *bssname, char *event)
+{
+ char *event_type;
+
+ if (!ctx || !obj)
+ return;
+
+ if (asprintf(&event_type, "bss.%s", event) < 0)
+ return;
+
+ blob_buf_init(&b, 0);
+ blobmsg_add_string(&b, "name", bssname);
+ ubus_notify(ctx, obj, event_type, b.head, -1);
+ free(event_type);
+}
+
+static void
+hostapd_bss_del_ban(void *eloop_data, void *user_ctx)
+{
+ struct ubus_banned_client *ban = eloop_data;
+ struct hostapd_data *hapd = user_ctx;
+
+ avl_delete(&hapd->ubus.banned, &ban->avl);
+ free(ban);
+}
+
+static void
+hostapd_bss_ban_client(struct hostapd_data *hapd, u8 *addr, int time)
+{
+ struct ubus_banned_client *ban;
+
+ if (time < 0)
+ time = 0;
+
+ ban = avl_find_element(&hapd->ubus.banned, addr, ban, avl);
+ if (!ban) {
+ if (!time)
+ return;
+
+ ban = os_zalloc(sizeof(*ban));
+ memcpy(ban->addr, addr, sizeof(ban->addr));
+ ban->avl.key = ban->addr;
+ avl_insert(&hapd->ubus.banned, &ban->avl);
+ } else {
+ eloop_cancel_timeout(hostapd_bss_del_ban, ban, hapd);
+ if (!time) {
+ hostapd_bss_del_ban(ban, hapd);
+ return;
+ }
+ }
+
+ eloop_register_timeout(0, time * 1000, hostapd_bss_del_ban, ban, hapd);
+}
+
+static int
+hostapd_bss_reload(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *req, const char *method,
+ struct blob_attr *msg)
+{
+ struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
+
+ return hostapd_reload_config(hapd->iface, 1);
+}
+
+
+static void
+hostapd_parse_vht_map_blobmsg(uint16_t map)
+{
+ char label[4];
+ int16_t val;
+ int i;
+
+ for (i = 0; i < 8; i++) {
+ snprintf(label, 4, "%dss", i + 1);
+
+ val = (map & (BIT(1) | BIT(0))) + 7;
+ blobmsg_add_u16(&b, label, val == 10 ? -1 : val);
+ map = map >> 2;
+ }
+}
+
+static void
+hostapd_parse_vht_capab_blobmsg(struct ieee80211_vht_capabilities *vhtc)
+{
+ void *supported_mcs;
+ void *map;
+ int i;
+
+ static const struct {
+ const char *name;
+ uint32_t flag;
+ } vht_capas[] = {
+ { "su_beamformee", VHT_CAP_SU_BEAMFORMEE_CAPABLE },
+ { "mu_beamformee", VHT_CAP_MU_BEAMFORMEE_CAPABLE },
+ };
+
+ for (i = 0; i < ARRAY_SIZE(vht_capas); i++)
+ blobmsg_add_u8(&b, vht_capas[i].name,
+ !!(vhtc->vht_capabilities_info & vht_capas[i].flag));
+
+ supported_mcs = blobmsg_open_table(&b, "mcs_map");
+
+ /* RX map */
+ map = blobmsg_open_table(&b, "rx");
+ hostapd_parse_vht_map_blobmsg(le_to_host16(vhtc->vht_supported_mcs_set.rx_map));
+ blobmsg_close_table(&b, map);
+
+ /* TX map */
+ map = blobmsg_open_table(&b, "tx");
+ hostapd_parse_vht_map_blobmsg(le_to_host16(vhtc->vht_supported_mcs_set.tx_map));
+ blobmsg_close_table(&b, map);
+
+ blobmsg_close_table(&b, supported_mcs);
+}
+
+static void
+hostapd_parse_capab_blobmsg(struct sta_info *sta)
+{
+ void *r, *v;
+
+ v = blobmsg_open_table(&b, "capabilities");
+
+ if (sta->vht_capabilities) {
+ r = blobmsg_open_table(&b, "vht");
+ hostapd_parse_vht_capab_blobmsg(sta->vht_capabilities);
+ blobmsg_close_table(&b, r);
+ }
+
+ /* ToDo: Add HT / HE capability parsing */
+
+ blobmsg_close_table(&b, v);
+}
+
+static int
+hostapd_bss_get_clients(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *req, const char *method,
+ struct blob_attr *msg)
+{
+ struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
+ struct hostap_sta_driver_data sta_driver_data;
+ struct sta_info *sta;
+ void *list, *c;
+ char mac_buf[20];
+ static const struct {
+ const char *name;
+ uint32_t flag;
+ } sta_flags[] = {
+ { "auth", WLAN_STA_AUTH },
+ { "assoc", WLAN_STA_ASSOC },
+ { "authorized", WLAN_STA_AUTHORIZED },
+ { "preauth", WLAN_STA_PREAUTH },
+ { "wds", WLAN_STA_WDS },
+ { "wmm", WLAN_STA_WMM },
+ { "ht", WLAN_STA_HT },
+ { "vht", WLAN_STA_VHT },
+ { "he", WLAN_STA_HE },
+ { "wps", WLAN_STA_WPS },
+ { "mfp", WLAN_STA_MFP },
+ };
+
+ blob_buf_init(&b, 0);
+ blobmsg_add_u32(&b, "freq", hapd->iface->freq);
+ list = blobmsg_open_table(&b, "clients");
+ for (sta = hapd->sta_list; sta; sta = sta->next) {
+ void *r;
+ int i;
+
+ sprintf(mac_buf, MACSTR, MAC2STR(sta->addr));
+ c = blobmsg_open_table(&b, mac_buf);
+ for (i = 0; i < ARRAY_SIZE(sta_flags); i++)
+ blobmsg_add_u8(&b, sta_flags[i].name,
+ !!(sta->flags & sta_flags[i].flag));
+
+#ifdef CONFIG_MBO
+ blobmsg_add_u8(&b, "mbo", !!(sta->cell_capa));
+#endif
+
+ r = blobmsg_open_array(&b, "rrm");
+ for (i = 0; i < ARRAY_SIZE(sta->rrm_enabled_capa); i++)
+ blobmsg_add_u32(&b, "", sta->rrm_enabled_capa[i]);
+ blobmsg_close_array(&b, r);
+
+ r = blobmsg_open_array(&b, "extended_capabilities");
+ /* Check if client advertises extended capabilities */
+ if (sta->ext_capability && sta->ext_capability[0] > 0) {
+ for (i = 0; i < sta->ext_capability[0]; i++) {
+ blobmsg_add_u32(&b, "", sta->ext_capability[1 + i]);
+ }
+ }
+ blobmsg_close_array(&b, r);
+
+ blobmsg_add_u32(&b, "aid", sta->aid);
+#ifdef CONFIG_TAXONOMY
+ r = blobmsg_alloc_string_buffer(&b, "signature", 1024);
+ if (retrieve_sta_taxonomy(hapd, sta, r, 1024) > 0)
+ blobmsg_add_string_buffer(&b);
+#endif
+
+ /* Driver information */
+ if (hostapd_drv_read_sta_data(hapd, &sta_driver_data, sta->addr) >= 0) {
+ r = blobmsg_open_table(&b, "bytes");
+ blobmsg_add_u64(&b, "rx", sta_driver_data.rx_bytes);
+ blobmsg_add_u64(&b, "tx", sta_driver_data.tx_bytes);
+ blobmsg_close_table(&b, r);
+ r = blobmsg_open_table(&b, "airtime");
+ blobmsg_add_u64(&b, "rx", sta_driver_data.rx_airtime);
+ blobmsg_add_u64(&b, "tx", sta_driver_data.tx_airtime);
+ blobmsg_close_table(&b, r);
+ r = blobmsg_open_table(&b, "packets");
+ blobmsg_add_u32(&b, "rx", sta_driver_data.rx_packets);
+ blobmsg_add_u32(&b, "tx", sta_driver_data.tx_packets);
+ blobmsg_close_table(&b, r);
+ r = blobmsg_open_table(&b, "rate");
+ /* Rate in kbits */
+ blobmsg_add_u32(&b, "rx", sta_driver_data.current_rx_rate * 100);
+ blobmsg_add_u32(&b, "tx", sta_driver_data.current_tx_rate * 100);
+ blobmsg_close_table(&b, r);
+ blobmsg_add_u32(&b, "signal", sta_driver_data.signal);
+ }
+
+ hostapd_parse_capab_blobmsg(sta);
+
+ blobmsg_close_table(&b, c);
+ }
+ blobmsg_close_array(&b, list);
+ ubus_send_reply(ctx, req, b.head);
+
+ return 0;
+}
+
+static int
+hostapd_bss_get_features(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *req, const char *method,
+ struct blob_attr *msg)
+{
+ struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
+
+ blob_buf_init(&b, 0);
+ blobmsg_add_u8(&b, "ht_supported", ht_supported(hapd->iface->hw_features));
+ blobmsg_add_u8(&b, "vht_supported", vht_supported(hapd->iface->hw_features));
+ ubus_send_reply(ctx, req, b.head);
+
+ return 0;
+}
+
+static int
+hostapd_bss_get_status(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *req, const char *method,
+ struct blob_attr *msg)
+{
+ struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
+ void *airtime_table, *dfs_table, *rrm_table, *wnm_table;
+ struct os_reltime now;
+ char ssid[SSID_MAX_LEN + 1];
+ char phy_name[17];
+ size_t ssid_len = SSID_MAX_LEN;
+ u8 channel = 0, op_class = 0;
+
+ if (hapd->conf->ssid.ssid_len < SSID_MAX_LEN)
+ ssid_len = hapd->conf->ssid.ssid_len;
+
+ ieee80211_freq_to_channel_ext(hapd->iface->freq,
+ hapd->iconf->secondary_channel,
+ hostapd_get_oper_chwidth(hapd->iconf),
+ &op_class, &channel);
+
+ blob_buf_init(&b, 0);
+ blobmsg_add_string(&b, "status", hostapd_state_text(hapd->iface->state));
+ blobmsg_printf(&b, "bssid", MACSTR, MAC2STR(hapd->conf->bssid));
+
+ memset(ssid, 0, SSID_MAX_LEN + 1);
+ memcpy(ssid, hapd->conf->ssid.ssid, ssid_len);
+ blobmsg_add_string(&b, "ssid", ssid);
+
+ blobmsg_add_u32(&b, "freq", hapd->iface->freq);
+ blobmsg_add_u32(&b, "channel", channel);
+ blobmsg_add_u32(&b, "op_class", op_class);
+ blobmsg_add_u32(&b, "beacon_interval", hapd->iconf->beacon_int);
+#ifdef CONFIG_IEEE80211AX
+ blobmsg_add_u32(&b, "bss_color", hapd->iface->conf->he_op.he_bss_color_disabled ? -1 :
+ hapd->iface->conf->he_op.he_bss_color);
+#else
+ blobmsg_add_u32(&b, "bss_color", -1);
+#endif
+
+ snprintf(phy_name, 17, "%s", hapd->iface->phy);
+ blobmsg_add_string(&b, "phy", phy_name);
+
+ /* RRM */
+ rrm_table = blobmsg_open_table(&b, "rrm");
+ blobmsg_add_u64(&b, "neighbor_report_tx", hapd->openwrt_stats.rrm.neighbor_report_tx);
+ blobmsg_close_table(&b, rrm_table);
+
+ /* WNM */
+ wnm_table = blobmsg_open_table(&b, "wnm");
+ blobmsg_add_u64(&b, "bss_transition_query_rx", hapd->openwrt_stats.wnm.bss_transition_query_rx);
+ blobmsg_add_u64(&b, "bss_transition_request_tx", hapd->openwrt_stats.wnm.bss_transition_request_tx);
+ blobmsg_add_u64(&b, "bss_transition_response_rx", hapd->openwrt_stats.wnm.bss_transition_response_rx);
+ blobmsg_close_table(&b, wnm_table);
+
+ /* Airtime */
+ airtime_table = blobmsg_open_table(&b, "airtime");
+ blobmsg_add_u64(&b, "time", hapd->iface->last_channel_time);
+ blobmsg_add_u64(&b, "time_busy", hapd->iface->last_channel_time_busy);
+ blobmsg_add_u16(&b, "utilization", hapd->iface->channel_utilization);
+ blobmsg_close_table(&b, airtime_table);
+
+ /* DFS */
+ dfs_table = blobmsg_open_table(&b, "dfs");
+ blobmsg_add_u32(&b, "cac_seconds", hapd->iface->dfs_cac_ms / 1000);
+ blobmsg_add_u8(&b, "cac_active", !!(hapd->iface->cac_started));
+ os_reltime_age(&hapd->iface->dfs_cac_start, &now);
+ blobmsg_add_u32(&b, "cac_seconds_left",
+ hapd->iface->cac_started ? hapd->iface->dfs_cac_ms / 1000 - now.sec : 0);
+ blobmsg_close_table(&b, dfs_table);
+
+ ubus_send_reply(ctx, req, b.head);
+
+ return 0;
+}
+
+enum {
+ NOTIFY_RESPONSE,
+ __NOTIFY_MAX
+};
+
+static const struct blobmsg_policy notify_policy[__NOTIFY_MAX] = {
+ [NOTIFY_RESPONSE] = { "notify_response", BLOBMSG_TYPE_INT32 },
+};
+
+static int
+hostapd_notify_response(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *req, const char *method,
+ struct blob_attr *msg)
+{
+ struct blob_attr *tb[__NOTIFY_MAX];
+ struct hostapd_data *hapd = get_hapd_from_object(obj);
+ struct wpabuf *elems;
+ const char *pos;
+ size_t len;
+
+ blobmsg_parse(notify_policy, __NOTIFY_MAX, tb,
+ blob_data(msg), blob_len(msg));
+
+ if (!tb[NOTIFY_RESPONSE])
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
+ hapd->ubus.notify_response = blobmsg_get_u32(tb[NOTIFY_RESPONSE]);
+
+ return UBUS_STATUS_OK;
+}
+
+enum {
+ DEL_CLIENT_ADDR,
+ DEL_CLIENT_REASON,
+ DEL_CLIENT_DEAUTH,
+ DEL_CLIENT_BAN_TIME,
+ __DEL_CLIENT_MAX
+};
+
+static const struct blobmsg_policy del_policy[__DEL_CLIENT_MAX] = {
+ [DEL_CLIENT_ADDR] = { "addr", BLOBMSG_TYPE_STRING },
+ [DEL_CLIENT_REASON] = { "reason", BLOBMSG_TYPE_INT32 },
+ [DEL_CLIENT_DEAUTH] = { "deauth", BLOBMSG_TYPE_INT8 },
+ [DEL_CLIENT_BAN_TIME] = { "ban_time", BLOBMSG_TYPE_INT32 },
+};
+
+static int
+hostapd_bss_del_client(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *req, const char *method,
+ struct blob_attr *msg)
+{
+ struct blob_attr *tb[__DEL_CLIENT_MAX];
+ struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
+ struct sta_info *sta;
+ bool deauth = false;
+ int reason;
+ u8 addr[ETH_ALEN];
+
+ blobmsg_parse(del_policy, __DEL_CLIENT_MAX, tb, blob_data(msg), blob_len(msg));
+
+ if (!tb[DEL_CLIENT_ADDR])
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
+ if (hwaddr_aton(blobmsg_data(tb[DEL_CLIENT_ADDR]), addr))
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
+ if (tb[DEL_CLIENT_REASON])
+ reason = blobmsg_get_u32(tb[DEL_CLIENT_REASON]);
+
+ if (tb[DEL_CLIENT_DEAUTH])
+ deauth = blobmsg_get_bool(tb[DEL_CLIENT_DEAUTH]);
+
+ sta = ap_get_sta(hapd, addr);
+ if (sta) {
+ if (deauth) {
+ hostapd_drv_sta_deauth(hapd, addr, reason);
+ ap_sta_deauthenticate(hapd, sta, reason);
+ } else {
+ hostapd_drv_sta_disassoc(hapd, addr, reason);
+ ap_sta_disassociate(hapd, sta, reason);
+ }
+ }
+
+ if (tb[DEL_CLIENT_BAN_TIME])
+ hostapd_bss_ban_client(hapd, addr, blobmsg_get_u32(tb[DEL_CLIENT_BAN_TIME]));
+
+ return 0;
+}
+
+static void
+blobmsg_add_macaddr(struct blob_buf *buf, const char *name, const u8 *addr)
+{
+ char *s;
+
+ s = blobmsg_alloc_string_buffer(buf, name, 20);
+ sprintf(s, MACSTR, MAC2STR(addr));
+ blobmsg_add_string_buffer(buf);
+}
+
+static int
+hostapd_bss_list_bans(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *req, const char *method,
+ struct blob_attr *msg)
+{
+ struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
+ struct ubus_banned_client *ban;
+ void *c;
+
+ blob_buf_init(&b, 0);
+ c = blobmsg_open_array(&b, "clients");
+ avl_for_each_element(&hapd->ubus.banned, ban, avl)
+ blobmsg_add_macaddr(&b, NULL, ban->addr);
+ blobmsg_close_array(&b, c);
+ ubus_send_reply(ctx, req, b.head);
+
+ return 0;
+}
+
+#ifdef CONFIG_WPS
+static int
+hostapd_bss_wps_start(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *req, const char *method,
+ struct blob_attr *msg)
+{
+ int rc;
+ struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
+
+ rc = hostapd_wps_button_pushed(hapd, NULL);
+
+ if (rc != 0)
+ return UBUS_STATUS_NOT_SUPPORTED;
+
+ return 0;
+}
+
+
+static const char * pbc_status_enum_str(enum pbc_status status)
+{
+ switch (status) {
+ case WPS_PBC_STATUS_DISABLE:
+ return "Disabled";
+ case WPS_PBC_STATUS_ACTIVE:
+ return "Active";
+ case WPS_PBC_STATUS_TIMEOUT:
+ return "Timed-out";
+ case WPS_PBC_STATUS_OVERLAP:
+ return "Overlap";
+ default:
+ return "Unknown";
+ }
+}
+
+static int
+hostapd_bss_wps_status(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *req, const char *method,
+ struct blob_attr *msg)
+{
+ int rc;
+ struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
+
+ blob_buf_init(&b, 0);
+
+ blobmsg_add_string(&b, "pbc_status", pbc_status_enum_str(hapd->wps_stats.pbc_status));
+ blobmsg_add_string(&b, "last_wps_result",
+ (hapd->wps_stats.status == WPS_STATUS_SUCCESS ?
+ "Success":
+ (hapd->wps_stats.status == WPS_STATUS_FAILURE ?
+ "Failed" : "None")));
+
+ /* If status == Failure - Add possible Reasons */
+ if(hapd->wps_stats.status == WPS_STATUS_FAILURE &&
+ hapd->wps_stats.failure_reason > 0)
+ blobmsg_add_string(&b, "reason", wps_ei_str(hapd->wps_stats.failure_reason));
+
+ if (hapd->wps_stats.status)
+ blobmsg_printf(&b, "peer_address", MACSTR, MAC2STR(hapd->wps_stats.peer_addr));
+
+ ubus_send_reply(ctx, req, b.head);
+
+ return 0;
+}
+
+static int
+hostapd_bss_wps_cancel(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *req, const char *method,
+ struct blob_attr *msg)
+{
+ int rc;
+ struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
+
+ rc = hostapd_wps_cancel(hapd);
+
+ if (rc != 0)
+ return UBUS_STATUS_NOT_SUPPORTED;
+
+ return 0;
+}
+#endif /* CONFIG_WPS */
+
+static int
+hostapd_bss_update_beacon(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *req, const char *method,
+ struct blob_attr *msg)
+{
+ int rc;
+ struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
+
+ rc = ieee802_11_set_beacon(hapd);
+
+ if (rc != 0)
+ return UBUS_STATUS_NOT_SUPPORTED;
+
+ return 0;
+}
+
+enum {
+ CONFIG_IFACE,
+ CONFIG_FILE,
+ __CONFIG_MAX
+};
+
+enum {
+ CSA_FREQ,
+ CSA_BCN_COUNT,
+ CSA_CENTER_FREQ1,
+ CSA_CENTER_FREQ2,
+ CSA_BANDWIDTH,
+ CSA_SEC_CHANNEL_OFFSET,
+ CSA_HT,
+ CSA_VHT,
+ CSA_HE,
+ CSA_BLOCK_TX,
+ CSA_FORCE,
+ __CSA_MAX
+};
+
+static const struct blobmsg_policy csa_policy[__CSA_MAX] = {
+ [CSA_FREQ] = { "freq", BLOBMSG_TYPE_INT32 },
+ [CSA_BCN_COUNT] = { "bcn_count", BLOBMSG_TYPE_INT32 },
+ [CSA_CENTER_FREQ1] = { "center_freq1", BLOBMSG_TYPE_INT32 },
+ [CSA_CENTER_FREQ2] = { "center_freq2", BLOBMSG_TYPE_INT32 },
+ [CSA_BANDWIDTH] = { "bandwidth", BLOBMSG_TYPE_INT32 },
+ [CSA_SEC_CHANNEL_OFFSET] = { "sec_channel_offset", BLOBMSG_TYPE_INT32 },
+ [CSA_HT] = { "ht", BLOBMSG_TYPE_BOOL },
+ [CSA_VHT] = { "vht", BLOBMSG_TYPE_BOOL },
+ [CSA_HE] = { "he", BLOBMSG_TYPE_BOOL },
+ [CSA_BLOCK_TX] = { "block_tx", BLOBMSG_TYPE_BOOL },
+ [CSA_FORCE] = { "force", BLOBMSG_TYPE_BOOL },
+};
+
+
+static void switch_chan_fallback_cb(void *eloop_data, void *user_ctx)
+{
+ struct hostapd_iface *iface = eloop_data;
+ struct hostapd_freq_params *freq_params = user_ctx;
+
+ hostapd_switch_channel_fallback(iface, freq_params);
+}
+
+#ifdef NEED_AP_MLME
+static int
+hostapd_switch_chan(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *req, const char *method,
+ struct blob_attr *msg)
+{
+ struct blob_attr *tb[__CSA_MAX];
+ struct hostapd_data *hapd = get_hapd_from_object(obj);
+ struct hostapd_config *iconf = hapd->iface->conf;
+ struct hostapd_freq_params *freq_params;
+ struct hostapd_hw_modes *mode = hapd->iface->current_mode;
+ struct csa_settings css = {
+ .freq_params = {
+ .ht_enabled = iconf->ieee80211n,
+ .vht_enabled = iconf->ieee80211ac,
+ .he_enabled = iconf->ieee80211ax,
+ .sec_channel_offset = iconf->secondary_channel,
+ }
+ };
+ u8 chwidth = hostapd_get_oper_chwidth(iconf);
+ u8 seg0 = 0, seg1 = 0;
+ int ret = UBUS_STATUS_OK;
+ int i;
+
+ blobmsg_parse(csa_policy, __CSA_MAX, tb, blob_data(msg), blob_len(msg));
+
+ if (!tb[CSA_FREQ])
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
+ switch (iconf->vht_oper_chwidth) {
+ case CHANWIDTH_USE_HT:
+ if (iconf->secondary_channel)
+ css.freq_params.bandwidth = 40;
+ else
+ css.freq_params.bandwidth = 20;
+ break;
+ case CHANWIDTH_160MHZ:
+ css.freq_params.bandwidth = 160;
+ break;
+ default:
+ css.freq_params.bandwidth = 80;
+ break;
+ }
+
+ css.freq_params.freq = blobmsg_get_u32(tb[CSA_FREQ]);
+
+#define SET_CSA_SETTING(name, field, type) \
+ do { \
+ if (tb[name]) \
+ css.field = blobmsg_get_ ## type(tb[name]); \
+ } while(0)
+
+ SET_CSA_SETTING(CSA_BCN_COUNT, cs_count, u32);
+ SET_CSA_SETTING(CSA_CENTER_FREQ1, freq_params.center_freq1, u32);
+ SET_CSA_SETTING(CSA_CENTER_FREQ2, freq_params.center_freq2, u32);
+ SET_CSA_SETTING(CSA_BANDWIDTH, freq_params.bandwidth, u32);
+ SET_CSA_SETTING(CSA_SEC_CHANNEL_OFFSET, freq_params.sec_channel_offset, u32);
+ SET_CSA_SETTING(CSA_HT, freq_params.ht_enabled, bool);
+ SET_CSA_SETTING(CSA_VHT, freq_params.vht_enabled, bool);
+ SET_CSA_SETTING(CSA_HE, freq_params.he_enabled, bool);
+ SET_CSA_SETTING(CSA_BLOCK_TX, block_tx, bool);
+
+ css.freq_params.channel = hostapd_hw_get_channel(hapd, css.freq_params.freq);
+ if (!css.freq_params.channel)
+ return UBUS_STATUS_NOT_SUPPORTED;
+
+ switch (css.freq_params.bandwidth) {
+ case 160:
+ chwidth = CHANWIDTH_160MHZ;
+ break;
+ case 80:
+ chwidth = css.freq_params.center_freq2 ? CHANWIDTH_80P80MHZ : CHANWIDTH_80MHZ;
+ break;
+ default:
+ chwidth = CHANWIDTH_USE_HT;
+ break;
+ }
+
+ hostapd_set_freq_params(&css.freq_params, iconf->hw_mode,
+ css.freq_params.freq,
+ css.freq_params.channel, iconf->enable_edmg,
+ iconf->edmg_channel,
+ css.freq_params.ht_enabled,
+ css.freq_params.vht_enabled,
+ css.freq_params.he_enabled,
+ css.freq_params.eht_enabled,
+ css.freq_params.sec_channel_offset,
+ chwidth, seg0, seg1,
+ iconf->vht_capab,
+ mode ? &mode->he_capab[IEEE80211_MODE_AP] :
+ NULL,
+ mode ? &mode->eht_capab[IEEE80211_MODE_AP] :
+ NULL);
+
+ for (i = 0; i < hapd->iface->num_bss; i++) {
+ struct hostapd_data *bss = hapd->iface->bss[i];
+
+ if (hostapd_switch_channel(bss, &css) != 0)
+ ret = UBUS_STATUS_NOT_SUPPORTED;
+ }
+
+ if (!ret || !tb[CSA_FORCE] || !blobmsg_get_bool(tb[CSA_FORCE]))
+ return ret;
+
+ freq_params = malloc(sizeof(*freq_params));
+ memcpy(freq_params, &css.freq_params, sizeof(*freq_params));
+ eloop_register_timeout(0, 1, switch_chan_fallback_cb,
+ hapd->iface, freq_params);
+
+ return 0;
+#undef SET_CSA_SETTING
+}
+#endif
+
+enum {
+ VENDOR_ELEMENTS,
+ __VENDOR_ELEMENTS_MAX
+};
+
+static const struct blobmsg_policy ve_policy[__VENDOR_ELEMENTS_MAX] = {
+ /* vendor elements are provided as hex-string */
+ [VENDOR_ELEMENTS] = { "vendor_elements", BLOBMSG_TYPE_STRING },
+};
+
+static int
+hostapd_vendor_elements(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *req, const char *method,
+ struct blob_attr *msg)
+{
+ struct blob_attr *tb[__VENDOR_ELEMENTS_MAX];
+ struct hostapd_data *hapd = get_hapd_from_object(obj);
+ struct hostapd_bss_config *bss = hapd->conf;
+ struct wpabuf *elems;
+ const char *pos;
+ size_t len;
+
+ blobmsg_parse(ve_policy, __VENDOR_ELEMENTS_MAX, tb,
+ blob_data(msg), blob_len(msg));
+
+ if (!tb[VENDOR_ELEMENTS])
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
+ pos = blobmsg_data(tb[VENDOR_ELEMENTS]);
+ len = os_strlen(pos);
+ if (len & 0x01)
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
+ len /= 2;
+ if (len == 0) {
+ wpabuf_free(bss->vendor_elements);
+ bss->vendor_elements = NULL;
+ return 0;
+ }
+
+ elems = wpabuf_alloc(len);
+ if (elems == NULL)
+ return 1;
+
+ if (hexstr2bin(pos, wpabuf_put(elems, len), len)) {
+ wpabuf_free(elems);
+ return UBUS_STATUS_INVALID_ARGUMENT;
+ }
+
+ wpabuf_free(bss->vendor_elements);
+ bss->vendor_elements = elems;
+
+ /* update beacons if vendor elements were set successfully */
+ if (ieee802_11_update_beacons(hapd->iface) != 0)
+ return UBUS_STATUS_NOT_SUPPORTED;
+ return UBUS_STATUS_OK;
+}
+
+static void
+hostapd_rrm_print_nr(struct hostapd_neighbor_entry *nr)
+{
+ const u8 *data;
+ char *str;
+ int len;
+
+ blobmsg_printf(&b, "", MACSTR, MAC2STR(nr->bssid));
+
+ str = blobmsg_alloc_string_buffer(&b, "", nr->ssid.ssid_len + 1);
+ memcpy(str, nr->ssid.ssid, nr->ssid.ssid_len);
+ str[nr->ssid.ssid_len] = 0;
+ blobmsg_add_string_buffer(&b);
+
+ len = wpabuf_len(nr->nr);
+ str = blobmsg_alloc_string_buffer(&b, "", 2 * len + 1);
+ wpa_snprintf_hex(str, 2 * len + 1, wpabuf_head_u8(nr->nr), len);
+ blobmsg_add_string_buffer(&b);
+}
+
+enum {
+ BSS_MGMT_EN_NEIGHBOR,
+ BSS_MGMT_EN_BEACON,
+ BSS_MGMT_EN_LINK_MEASUREMENT,
+#ifdef CONFIG_WNM_AP
+ BSS_MGMT_EN_BSS_TRANSITION,
+#endif
+ __BSS_MGMT_EN_MAX
+};
+
+static bool
+__hostapd_bss_mgmt_enable_f(struct hostapd_data *hapd, int flag)
+{
+ struct hostapd_bss_config *bss = hapd->conf;
+ uint32_t flags;
+
+ switch (flag) {
+ case BSS_MGMT_EN_NEIGHBOR:
+ if (bss->radio_measurements[0] &
+ WLAN_RRM_CAPS_NEIGHBOR_REPORT)
+ return false;
+
+ bss->radio_measurements[0] |=
+ WLAN_RRM_CAPS_NEIGHBOR_REPORT;
+ hostapd_neighbor_set_own_report(hapd);
+ return true;
+ case BSS_MGMT_EN_BEACON:
+ flags = WLAN_RRM_CAPS_BEACON_REPORT_PASSIVE |
+ WLAN_RRM_CAPS_BEACON_REPORT_ACTIVE |
+ WLAN_RRM_CAPS_BEACON_REPORT_TABLE;
+
+ if (bss->radio_measurements[0] & flags == flags)
+ return false;
+
+ bss->radio_measurements[0] |= (u8) flags;
+ return true;
+ case BSS_MGMT_EN_LINK_MEASUREMENT:
+ flags = WLAN_RRM_CAPS_LINK_MEASUREMENT;
+
+ if (bss->radio_measurements[0] & flags == flags)
+ return false;
+
+ bss->radio_measurements[0] |= (u8) flags;
+ return true;
+#ifdef CONFIG_WNM_AP
+ case BSS_MGMT_EN_BSS_TRANSITION:
+ if (bss->bss_transition)
+ return false;
+
+ bss->bss_transition = 1;
+ return true;
+#endif
+ }
+}
+
+static void
+__hostapd_bss_mgmt_enable(struct hostapd_data *hapd, uint32_t flags)
+{
+ bool update = false;
+ int i;
+
+ for (i = 0; i < __BSS_MGMT_EN_MAX; i++) {
+ if (!(flags & (1 << i)))
+ continue;
+
+ update |= __hostapd_bss_mgmt_enable_f(hapd, i);
+ }
+
+ if (update)
+ ieee802_11_update_beacons(hapd->iface);
+}
+
+
+static const struct blobmsg_policy bss_mgmt_enable_policy[__BSS_MGMT_EN_MAX] = {
+ [BSS_MGMT_EN_NEIGHBOR] = { "neighbor_report", BLOBMSG_TYPE_BOOL },
+ [BSS_MGMT_EN_BEACON] = { "beacon_report", BLOBMSG_TYPE_BOOL },
+ [BSS_MGMT_EN_LINK_MEASUREMENT] = { "link_measurement", BLOBMSG_TYPE_BOOL },
+#ifdef CONFIG_WNM_AP
+ [BSS_MGMT_EN_BSS_TRANSITION] = { "bss_transition", BLOBMSG_TYPE_BOOL },
+#endif
+};
+
+static int
+hostapd_bss_mgmt_enable(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *req, const char *method,
+ struct blob_attr *msg)
+
+{
+ struct hostapd_data *hapd = get_hapd_from_object(obj);
+ struct blob_attr *tb[__BSS_MGMT_EN_MAX];
+ struct blob_attr *cur;
+ uint32_t flags = 0;
+ int i;
+ bool neigh = false, beacon = false;
+
+ blobmsg_parse(bss_mgmt_enable_policy, __BSS_MGMT_EN_MAX, tb, blob_data(msg), blob_len(msg));
+
+ for (i = 0; i < ARRAY_SIZE(tb); i++) {
+ if (!tb[i] || !blobmsg_get_bool(tb[i]))
+ continue;
+
+ flags |= (1 << i);
+ }
+
+ __hostapd_bss_mgmt_enable(hapd, flags);
+
+ return 0;
+}
+
+
+static void
+hostapd_rrm_nr_enable(struct hostapd_data *hapd)
+{
+ __hostapd_bss_mgmt_enable(hapd, 1 << BSS_MGMT_EN_NEIGHBOR);
+}
+
+static int
+hostapd_rrm_nr_get_own(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *req, const char *method,
+ struct blob_attr *msg)
+{
+ struct hostapd_data *hapd = get_hapd_from_object(obj);
+ struct hostapd_neighbor_entry *nr;
+ void *c;
+
+ hostapd_rrm_nr_enable(hapd);
+
+ nr = hostapd_neighbor_get(hapd, hapd->own_addr, NULL);
+ if (!nr)
+ return UBUS_STATUS_NOT_FOUND;
+
+ blob_buf_init(&b, 0);
+
+ c = blobmsg_open_array(&b, "value");
+ hostapd_rrm_print_nr(nr);
+ blobmsg_close_array(&b, c);
+
+ ubus_send_reply(ctx, req, b.head);
+
+ return 0;
+}
+
+static int
+hostapd_rrm_nr_list(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *req, const char *method,
+ struct blob_attr *msg)
+{
+ struct hostapd_data *hapd = get_hapd_from_object(obj);
+ struct hostapd_neighbor_entry *nr;
+ void *c;
+
+ hostapd_rrm_nr_enable(hapd);
+ blob_buf_init(&b, 0);
+
+ c = blobmsg_open_array(&b, "list");
+ dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry, list) {
+ void *cur;
+
+ if (!memcmp(nr->bssid, hapd->own_addr, ETH_ALEN))
+ continue;
+
+ cur = blobmsg_open_array(&b, NULL);
+ hostapd_rrm_print_nr(nr);
+ blobmsg_close_array(&b, cur);
+ }
+ blobmsg_close_array(&b, c);
+
+ ubus_send_reply(ctx, req, b.head);
+
+ return 0;
+}
+
+enum {
+ NR_SET_LIST,
+ __NR_SET_LIST_MAX
+};
+
+static const struct blobmsg_policy nr_set_policy[__NR_SET_LIST_MAX] = {
+ [NR_SET_LIST] = { "list", BLOBMSG_TYPE_ARRAY },
+};
+
+
+static void
+hostapd_rrm_nr_clear(struct hostapd_data *hapd)
+{
+ struct hostapd_neighbor_entry *nr;
+
+restart:
+ dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry, list) {
+ if (!memcmp(nr->bssid, hapd->own_addr, ETH_ALEN))
+ continue;
+
+ hostapd_neighbor_remove(hapd, nr->bssid, &nr->ssid);
+ goto restart;
+ }
+}
+
+static int
+hostapd_rrm_nr_set(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *req, const char *method,
+ struct blob_attr *msg)
+{
+ static const struct blobmsg_policy nr_e_policy[] = {
+ { .type = BLOBMSG_TYPE_STRING },
+ { .type = BLOBMSG_TYPE_STRING },
+ { .type = BLOBMSG_TYPE_STRING },
+ };
+ struct hostapd_data *hapd = get_hapd_from_object(obj);
+ struct blob_attr *tb_l[__NR_SET_LIST_MAX];
+ struct blob_attr *tb[ARRAY_SIZE(nr_e_policy)];
+ struct blob_attr *cur;
+ int rem;
+
+ hostapd_rrm_nr_enable(hapd);
+
+ blobmsg_parse(nr_set_policy, __NR_SET_LIST_MAX, tb_l, blob_data(msg), blob_len(msg));
+ if (!tb_l[NR_SET_LIST])
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
+ hostapd_rrm_nr_clear(hapd);
+ blobmsg_for_each_attr(cur, tb_l[NR_SET_LIST], rem) {
+ struct wpa_ssid_value ssid;
+ struct wpabuf *data;
+ u8 bssid[ETH_ALEN];
+ char *s, *nr_s;
+
+ blobmsg_parse_array(nr_e_policy, ARRAY_SIZE(nr_e_policy), tb, blobmsg_data(cur), blobmsg_data_len(cur));
+ if (!tb[0] || !tb[1] || !tb[2])
+ goto invalid;
+
+ /* Neighbor Report binary */
+ nr_s = blobmsg_get_string(tb[2]);
+ data = wpabuf_parse_bin(nr_s);
+ if (!data)
+ goto invalid;
+
+ /* BSSID */
+ s = blobmsg_get_string(tb[0]);
+ if (strlen(s) == 0) {
+ /* Copy BSSID from neighbor report */
+ if (hwaddr_compact_aton(nr_s, bssid))
+ goto invalid;
+ } else if (hwaddr_aton(s, bssid)) {
+ goto invalid;
+ }
+
+ /* SSID */
+ s = blobmsg_get_string(tb[1]);
+ if (strlen(s) == 0) {
+ /* Copy SSID from hostapd BSS conf */
+ memcpy(&ssid, &hapd->conf->ssid, sizeof(ssid));
+ } else {
+ ssid.ssid_len = strlen(s);
+ if (ssid.ssid_len > sizeof(ssid.ssid))
+ goto invalid;
+
+ memcpy(&ssid, s, ssid.ssid_len);
+ }
+
+ hostapd_neighbor_set(hapd, bssid, &ssid, data, NULL, NULL, 0, 0);
+ wpabuf_free(data);
+ continue;
+
+invalid:
+ return UBUS_STATUS_INVALID_ARGUMENT;
+ }
+
+ return 0;
+}
+
+enum {
+ BEACON_REQ_ADDR,
+ BEACON_REQ_MODE,
+ BEACON_REQ_OP_CLASS,
+ BEACON_REQ_CHANNEL,
+ BEACON_REQ_DURATION,
+ BEACON_REQ_BSSID,
+ BEACON_REQ_SSID,
+ __BEACON_REQ_MAX,
+};
+
+static const struct blobmsg_policy beacon_req_policy[__BEACON_REQ_MAX] = {
+ [BEACON_REQ_ADDR] = { "addr", BLOBMSG_TYPE_STRING },
+ [BEACON_REQ_OP_CLASS] { "op_class", BLOBMSG_TYPE_INT32 },
+ [BEACON_REQ_CHANNEL] { "channel", BLOBMSG_TYPE_INT32 },
+ [BEACON_REQ_DURATION] { "duration", BLOBMSG_TYPE_INT32 },
+ [BEACON_REQ_MODE] { "mode", BLOBMSG_TYPE_INT32 },
+ [BEACON_REQ_BSSID] { "bssid", BLOBMSG_TYPE_STRING },
+ [BEACON_REQ_SSID] { "ssid", BLOBMSG_TYPE_STRING },
+};
+
+static int
+hostapd_rrm_beacon_req(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *ureq, const char *method,
+ struct blob_attr *msg)
+{
+ struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
+ struct blob_attr *tb[__BEACON_REQ_MAX];
+ struct blob_attr *cur;
+ struct wpabuf *req;
+ u8 bssid[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+ u8 addr[ETH_ALEN];
+ int mode, rem, ret;
+ int buf_len = 13;
+
+ blobmsg_parse(beacon_req_policy, __BEACON_REQ_MAX, tb, blob_data(msg), blob_len(msg));
+
+ if (!tb[BEACON_REQ_ADDR] || !tb[BEACON_REQ_MODE] || !tb[BEACON_REQ_DURATION] ||
+ !tb[BEACON_REQ_OP_CLASS] || !tb[BEACON_REQ_CHANNEL])
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
+ if (tb[BEACON_REQ_SSID])
+ buf_len += blobmsg_data_len(tb[BEACON_REQ_SSID]) + 2 - 1;
+
+ mode = blobmsg_get_u32(tb[BEACON_REQ_MODE]);
+ if (hwaddr_aton(blobmsg_data(tb[BEACON_REQ_ADDR]), addr))
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
+ if (tb[BEACON_REQ_BSSID] &&
+ hwaddr_aton(blobmsg_data(tb[BEACON_REQ_BSSID]), bssid))
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
+ req = wpabuf_alloc(buf_len);
+ if (!req)
+ return UBUS_STATUS_UNKNOWN_ERROR;
+
+ /* 1: regulatory class */
+ wpabuf_put_u8(req, blobmsg_get_u32(tb[BEACON_REQ_OP_CLASS]));
+
+ /* 2: channel number */
+ wpabuf_put_u8(req, blobmsg_get_u32(tb[BEACON_REQ_CHANNEL]));
+
+ /* 3-4: randomization interval */
+ wpabuf_put_le16(req, 0);
+
+ /* 5-6: duration */
+ wpabuf_put_le16(req, blobmsg_get_u32(tb[BEACON_REQ_DURATION]));
+
+ /* 7: mode */
+ wpabuf_put_u8(req, blobmsg_get_u32(tb[BEACON_REQ_MODE]));
+
+ /* 8-13: BSSID */
+ wpabuf_put_data(req, bssid, ETH_ALEN);
+
+ if ((cur = tb[BEACON_REQ_SSID]) != NULL) {
+ wpabuf_put_u8(req, WLAN_EID_SSID);
+ wpabuf_put_u8(req, blobmsg_data_len(cur) - 1);
+ wpabuf_put_data(req, blobmsg_data(cur), blobmsg_data_len(cur) - 1);
+ }
+
+ ret = hostapd_send_beacon_req(hapd, addr, 0, req);
+ if (ret < 0)
+ return -ret;
+
+ return 0;
+}
+
+enum {
+ LM_REQ_ADDR,
+ LM_REQ_TX_POWER_USED,
+ LM_REQ_TX_POWER_MAX,
+ __LM_REQ_MAX,
+};
+
+static const struct blobmsg_policy lm_req_policy[__LM_REQ_MAX] = {
+ [LM_REQ_ADDR] = { "addr", BLOBMSG_TYPE_STRING },
+ [LM_REQ_TX_POWER_USED] = { "tx-power-used", BLOBMSG_TYPE_INT32 },
+ [LM_REQ_TX_POWER_MAX] = { "tx-power-max", BLOBMSG_TYPE_INT32 },
+};
+
+static int
+hostapd_rrm_lm_req(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *ureq, const char *method,
+ struct blob_attr *msg)
+{
+ struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
+ struct blob_attr *tb[__LM_REQ_MAX];
+ struct wpabuf *buf;
+ u8 addr[ETH_ALEN];
+ int ret;
+ int8_t txp_used, txp_max;
+
+ txp_used = 0;
+ txp_max = 0;
+
+ blobmsg_parse(lm_req_policy, __LM_REQ_MAX, tb, blob_data(msg), blob_len(msg));
+
+ if (!tb[LM_REQ_ADDR])
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
+ if (tb[LM_REQ_TX_POWER_USED])
+ txp_used = (int8_t) blobmsg_get_u32(tb[LM_REQ_TX_POWER_USED]);
+
+ if (tb[LM_REQ_TX_POWER_MAX])
+ txp_max = (int8_t) blobmsg_get_u32(tb[LM_REQ_TX_POWER_MAX]);
+
+ if (hwaddr_aton(blobmsg_data(tb[LM_REQ_ADDR]), addr))
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
+ buf = wpabuf_alloc(5);
+ if (!buf)
+ return UBUS_STATUS_UNKNOWN_ERROR;
+
+ wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT);
+ wpabuf_put_u8(buf, WLAN_RRM_LINK_MEASUREMENT_REQUEST);
+ wpabuf_put_u8(buf, 1);
+ /* TX-Power used */
+ wpabuf_put_u8(buf, txp_used);
+ /* Max TX Power */
+ wpabuf_put_u8(buf, txp_max);
+
+ ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr,
+ wpabuf_head(buf), wpabuf_len(buf));
+
+ wpabuf_free(buf);
+ if (ret < 0)
+ return -ret;
+
+ return 0;
+}
+
+
+void hostapd_ubus_handle_link_measurement(struct hostapd_data *hapd, const u8 *data, size_t len)
+{
+ const struct ieee80211_mgmt *mgmt = (const struct ieee80211_mgmt *) data;
+ const u8 *pos, *end;
+ u8 token;
+
+ end = data + len;
+ token = mgmt->u.action.u.rrm.dialog_token;
+ pos = mgmt->u.action.u.rrm.variable;
+
+ if (end - pos < 8)
+ return;
+
+ if (!hapd->ubus.obj.has_subscribers)
+ return;
+
+ blob_buf_init(&b, 0);
+ blobmsg_add_macaddr(&b, "address", mgmt->sa);
+ blobmsg_add_u16(&b, "dialog-token", token);
+ blobmsg_add_u16(&b, "rx-antenna-id", pos[4]);
+ blobmsg_add_u16(&b, "tx-antenna-id", pos[5]);
+ blobmsg_add_u16(&b, "rcpi", pos[6]);
+ blobmsg_add_u16(&b, "rsni", pos[7]);
+
+ ubus_notify(ctx, &hapd->ubus.obj, "link-measurement-report", b.head, -1);
+}
+
+
+#ifdef CONFIG_WNM_AP
+
+static int
+hostapd_bss_tr_send(struct hostapd_data *hapd, u8 *addr, bool disassoc_imminent, bool abridged,
+ u16 disassoc_timer, u8 validity_period, u8 dialog_token,
+ struct blob_attr *neighbors, u8 mbo_reason, u8 cell_pref, u8 reassoc_delay)
+{
+ struct blob_attr *cur;
+ struct sta_info *sta;
+ int nr_len = 0;
+ int rem;
+ u8 *nr = NULL;
+ u8 req_mode = 0;
+ u8 mbo[10];
+ size_t mbo_len = 0;
+
+ sta = ap_get_sta(hapd, addr);
+ if (!sta)
+ return UBUS_STATUS_NOT_FOUND;
+
+ if (neighbors) {
+ u8 *nr_cur;
+
+ if (blobmsg_check_array(neighbors,
+ BLOBMSG_TYPE_STRING) < 0)
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
+ blobmsg_for_each_attr(cur, neighbors, rem) {
+ int len = strlen(blobmsg_get_string(cur));
+
+ if (len % 2)
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
+ nr_len += (len / 2) + 2;
+ }
+
+ if (nr_len) {
+ nr = os_zalloc(nr_len);
+ if (!nr)
+ return UBUS_STATUS_UNKNOWN_ERROR;
+ }
+
+ nr_cur = nr;
+ blobmsg_for_each_attr(cur, neighbors, rem) {
+ int len = strlen(blobmsg_get_string(cur)) / 2;
+
+ *nr_cur++ = WLAN_EID_NEIGHBOR_REPORT;
+ *nr_cur++ = (u8) len;
+ if (hexstr2bin(blobmsg_data(cur), nr_cur, len)) {
+ free(nr);
+ return UBUS_STATUS_INVALID_ARGUMENT;
+ }
+
+ nr_cur += len;
+ }
+ }
+
+ if (nr)
+ req_mode |= WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED;
+
+ if (abridged)
+ req_mode |= WNM_BSS_TM_REQ_ABRIDGED;
+
+ if (disassoc_imminent)
+ req_mode |= WNM_BSS_TM_REQ_DISASSOC_IMMINENT;
+
+#ifdef CONFIG_MBO
+ u8 *mbo_pos = mbo;
+
+ if (mbo_reason > MBO_TRANSITION_REASON_PREMIUM_AP)
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
+ if (cell_pref != 0 && cell_pref != 1 && cell_pref != 255)
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
+ if (reassoc_delay > 65535 || (reassoc_delay && !disassoc_imminent))
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
+ *mbo_pos++ = MBO_ATTR_ID_TRANSITION_REASON;
+ *mbo_pos++ = 1;
+ *mbo_pos++ = mbo_reason;
+ *mbo_pos++ = MBO_ATTR_ID_CELL_DATA_PREF;
+ *mbo_pos++ = 1;
+ *mbo_pos++ = cell_pref;
+
+ if (reassoc_delay) {
+ *mbo_pos++ = MBO_ATTR_ID_ASSOC_RETRY_DELAY;
+ *mbo_pos++ = 2;
+ WPA_PUT_LE16(mbo_pos, reassoc_delay);
+ mbo_pos += 2;
+ }
+
+ mbo_len = mbo_pos - mbo;
+#endif
+
+ if (wnm_send_bss_tm_req(hapd, sta, req_mode, disassoc_timer, validity_period, NULL,
+ dialog_token, NULL, nr, nr_len, mbo_len ? mbo : NULL, mbo_len))
+ return UBUS_STATUS_UNKNOWN_ERROR;
+
+ return 0;
+}
+
+enum {
+ BSS_TR_ADDR,
+ BSS_TR_DA_IMMINENT,
+ BSS_TR_DA_TIMER,
+ BSS_TR_VALID_PERIOD,
+ BSS_TR_NEIGHBORS,
+ BSS_TR_ABRIDGED,
+ BSS_TR_DIALOG_TOKEN,
+#ifdef CONFIG_MBO
+ BSS_TR_MBO_REASON,
+ BSS_TR_CELL_PREF,
+ BSS_TR_REASSOC_DELAY,
+#endif
+ __BSS_TR_DISASSOC_MAX
+};
+
+static const struct blobmsg_policy bss_tr_policy[__BSS_TR_DISASSOC_MAX] = {
+ [BSS_TR_ADDR] = { "addr", BLOBMSG_TYPE_STRING },
+ [BSS_TR_DA_IMMINENT] = { "disassociation_imminent", BLOBMSG_TYPE_BOOL },
+ [BSS_TR_DA_TIMER] = { "disassociation_timer", BLOBMSG_TYPE_INT32 },
+ [BSS_TR_VALID_PERIOD] = { "validity_period", BLOBMSG_TYPE_INT32 },
+ [BSS_TR_NEIGHBORS] = { "neighbors", BLOBMSG_TYPE_ARRAY },
+ [BSS_TR_ABRIDGED] = { "abridged", BLOBMSG_TYPE_BOOL },
+ [BSS_TR_DIALOG_TOKEN] = { "dialog_token", BLOBMSG_TYPE_INT32 },
+#ifdef CONFIG_MBO
+ [BSS_TR_MBO_REASON] = { "mbo_reason", BLOBMSG_TYPE_INT32 },
+ [BSS_TR_CELL_PREF] = { "cell_pref", BLOBMSG_TYPE_INT32 },
+ [BSS_TR_REASSOC_DELAY] = { "reassoc_delay", BLOBMSG_TYPE_INT32 },
+#endif
+};
+
+static int
+hostapd_bss_transition_request(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *ureq, const char *method,
+ struct blob_attr *msg)
+{
+ struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
+ struct blob_attr *tb[__BSS_TR_DISASSOC_MAX];
+ struct sta_info *sta;
+ u32 da_timer = 0;
+ u32 valid_period = 0;
+ u8 addr[ETH_ALEN];
+ u32 dialog_token = 1;
+ bool abridged;
+ bool da_imminent;
+ u8 mbo_reason;
+ u8 cell_pref;
+ u8 reassoc_delay;
+
+ blobmsg_parse(bss_tr_policy, __BSS_TR_DISASSOC_MAX, tb, blob_data(msg), blob_len(msg));
+
+ if (!tb[BSS_TR_ADDR])
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
+ if (hwaddr_aton(blobmsg_data(tb[BSS_TR_ADDR]), addr))
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
+ if (tb[BSS_TR_DA_TIMER])
+ da_timer = blobmsg_get_u32(tb[BSS_TR_DA_TIMER]);
+
+ if (tb[BSS_TR_VALID_PERIOD])
+ valid_period = blobmsg_get_u32(tb[BSS_TR_VALID_PERIOD]);
+
+ if (tb[BSS_TR_DIALOG_TOKEN])
+ dialog_token = blobmsg_get_u32(tb[BSS_TR_DIALOG_TOKEN]);
+
+ da_imminent = !!(tb[BSS_TR_DA_IMMINENT] && blobmsg_get_bool(tb[BSS_TR_DA_IMMINENT]));
+ abridged = !!(tb[BSS_TR_ABRIDGED] && blobmsg_get_bool(tb[BSS_TR_ABRIDGED]));
+
+#ifdef CONFIG_MBO
+ if (tb[BSS_TR_MBO_REASON])
+ mbo_reason = blobmsg_get_u32(tb[BSS_TR_MBO_REASON]);
+
+ if (tb[BSS_TR_CELL_PREF])
+ cell_pref = blobmsg_get_u32(tb[BSS_TR_CELL_PREF]);
+
+ if (tb[BSS_TR_REASSOC_DELAY])
+ reassoc_delay = blobmsg_get_u32(tb[BSS_TR_REASSOC_DELAY]);
+#endif
+
+ return hostapd_bss_tr_send(hapd, addr, da_imminent, abridged, da_timer, valid_period,
+ dialog_token, tb[BSS_TR_NEIGHBORS], mbo_reason, cell_pref, reassoc_delay);
+}
+#endif
+
+#ifdef CONFIG_AIRTIME_POLICY
+enum {
+ UPDATE_AIRTIME_STA,
+ UPDATE_AIRTIME_WEIGHT,
+ __UPDATE_AIRTIME_MAX,
+};
+
+
+static const struct blobmsg_policy airtime_policy[__UPDATE_AIRTIME_MAX] = {
+ [UPDATE_AIRTIME_STA] = { "sta", BLOBMSG_TYPE_STRING },
+ [UPDATE_AIRTIME_WEIGHT] = { "weight", BLOBMSG_TYPE_INT32 },
+};
+
+static int
+hostapd_bss_update_airtime(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *ureq, const char *method,
+ struct blob_attr *msg)
+{
+ struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
+ struct blob_attr *tb[__UPDATE_AIRTIME_MAX];
+ struct sta_info *sta = NULL;
+ u8 addr[ETH_ALEN];
+ int weight;
+
+ blobmsg_parse(airtime_policy, __UPDATE_AIRTIME_MAX, tb, blob_data(msg), blob_len(msg));
+
+ if (!tb[UPDATE_AIRTIME_WEIGHT])
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
+ weight = blobmsg_get_u32(tb[UPDATE_AIRTIME_WEIGHT]);
+
+ if (!tb[UPDATE_AIRTIME_STA]) {
+ if (!weight)
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
+ hapd->conf->airtime_weight = weight;
+ return 0;
+ }
+
+ if (hwaddr_aton(blobmsg_data(tb[UPDATE_AIRTIME_STA]), addr))
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
+ sta = ap_get_sta(hapd, addr);
+ if (!sta)
+ return UBUS_STATUS_NOT_FOUND;
+
+ sta->dyn_airtime_weight = weight;
+ airtime_policy_new_sta(hapd, sta);
+
+ return 0;
+}
+#endif
+
+#ifdef CONFIG_TAXONOMY
+static const struct blobmsg_policy addr_policy[] = {
+ { "address", BLOBMSG_TYPE_STRING }
+};
+
+static bool
+hostapd_add_b64_data(const char *name, const struct wpabuf *buf)
+{
+ char *str;
+
+ if (!buf)
+ return false;
+
+ str = blobmsg_alloc_string_buffer(&b, name, B64_ENCODE_LEN(wpabuf_len(buf)));
+ b64_encode(wpabuf_head(buf), wpabuf_len(buf), str, B64_ENCODE_LEN(wpabuf_len(buf)));
+ blobmsg_add_string_buffer(&b);
+
+ return true;
+}
+
+static int
+hostapd_bss_get_sta_ies(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *req, const char *method,
+ struct blob_attr *msg)
+{
+ struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj);
+ struct blob_attr *tb;
+ struct sta_info *sta;
+ u8 addr[ETH_ALEN];
+
+ blobmsg_parse(addr_policy, 1, &tb, blobmsg_data(msg), blobmsg_len(msg));
+
+ if (!tb || hwaddr_aton(blobmsg_data(tb), addr))
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
+ sta = ap_get_sta(hapd, addr);
+ if (!sta || (!sta->probe_ie_taxonomy && !sta->assoc_ie_taxonomy))
+ return UBUS_STATUS_NOT_FOUND;
+
+ blob_buf_init(&b, 0);
+ hostapd_add_b64_data("probe_ie", sta->probe_ie_taxonomy);
+ hostapd_add_b64_data("assoc_ie", sta->assoc_ie_taxonomy);
+ ubus_send_reply(ctx, req, b.head);
+
+ return 0;
+}
+#endif
+
+
+static const struct ubus_method bss_methods[] = {
+ UBUS_METHOD_NOARG("reload", hostapd_bss_reload),
+ UBUS_METHOD_NOARG("get_clients", hostapd_bss_get_clients),
+#ifdef CONFIG_TAXONOMY
+ UBUS_METHOD("get_sta_ies", hostapd_bss_get_sta_ies, addr_policy),
+#endif
+ UBUS_METHOD_NOARG("get_status", hostapd_bss_get_status),
+ UBUS_METHOD("del_client", hostapd_bss_del_client, del_policy),
+#ifdef CONFIG_AIRTIME_POLICY
+ UBUS_METHOD("update_airtime", hostapd_bss_update_airtime, airtime_policy),
+#endif
+ UBUS_METHOD_NOARG("list_bans", hostapd_bss_list_bans),
+#ifdef CONFIG_WPS
+ UBUS_METHOD_NOARG("wps_start", hostapd_bss_wps_start),
+ UBUS_METHOD_NOARG("wps_status", hostapd_bss_wps_status),
+ UBUS_METHOD_NOARG("wps_cancel", hostapd_bss_wps_cancel),
+#endif
+ UBUS_METHOD_NOARG("update_beacon", hostapd_bss_update_beacon),
+ UBUS_METHOD_NOARG("get_features", hostapd_bss_get_features),
+#ifdef NEED_AP_MLME
+ UBUS_METHOD("switch_chan", hostapd_switch_chan, csa_policy),
+#endif
+ UBUS_METHOD("set_vendor_elements", hostapd_vendor_elements, ve_policy),
+ UBUS_METHOD("notify_response", hostapd_notify_response, notify_policy),
+ UBUS_METHOD("bss_mgmt_enable", hostapd_bss_mgmt_enable, bss_mgmt_enable_policy),
+ UBUS_METHOD_NOARG("rrm_nr_get_own", hostapd_rrm_nr_get_own),
+ UBUS_METHOD_NOARG("rrm_nr_list", hostapd_rrm_nr_list),
+ UBUS_METHOD("rrm_nr_set", hostapd_rrm_nr_set, nr_set_policy),
+ UBUS_METHOD("rrm_beacon_req", hostapd_rrm_beacon_req, beacon_req_policy),
+ UBUS_METHOD("link_measurement_req", hostapd_rrm_lm_req, lm_req_policy),
+#ifdef CONFIG_WNM_AP
+ UBUS_METHOD("bss_transition_request", hostapd_bss_transition_request, bss_tr_policy),
+#endif
+};
+
+static struct ubus_object_type bss_object_type =
+ UBUS_OBJECT_TYPE("hostapd_bss", bss_methods);
+
+static int avl_compare_macaddr(const void *k1, const void *k2, void *ptr)
+{
+ return memcmp(k1, k2, ETH_ALEN);
+}
+
+void hostapd_ubus_add_bss(struct hostapd_data *hapd)
+{
+ struct ubus_object *obj = &hapd->ubus.obj;
+ char *name;
+ int ret;
+
+#ifdef CONFIG_MESH
+ if (hapd->conf->mesh & MESH_ENABLED)
+ return;
+#endif
+
+ if (!hostapd_ubus_init())
+ return;
+
+ if (asprintf(&name, "hostapd.%s", hapd->conf->iface) < 0)
+ return;
+
+ avl_init(&hapd->ubus.banned, avl_compare_macaddr, false, NULL);
+ obj->name = name;
+ obj->type = &bss_object_type;
+ obj->methods = bss_object_type.methods;
+ obj->n_methods = bss_object_type.n_methods;
+ ret = ubus_add_object(ctx, obj);
+ hostapd_ubus_ref_inc();
+}
+
+void hostapd_ubus_free_bss(struct hostapd_data *hapd)
+{
+ struct ubus_object *obj = &hapd->ubus.obj;
+ char *name = (char *) obj->name;
+
+#ifdef CONFIG_MESH
+ if (hapd->conf->mesh & MESH_ENABLED)
+ return;
+#endif
+
+ if (!ctx)
+ return;
+
+ if (obj->id) {
+ ubus_remove_object(ctx, obj);
+ hostapd_ubus_ref_dec();
+ }
+
+ free(name);
+}
+
+static void
+hostapd_ubus_vlan_action(struct hostapd_data *hapd, struct hostapd_vlan *vlan,
+ const char *action)
+{
+ struct vlan_description *desc = &vlan->vlan_desc;
+ void *c;
+ int i;
+
+ if (!hapd->ubus.obj.has_subscribers)
+ return;
+
+ blob_buf_init(&b, 0);
+ blobmsg_add_string(&b, "ifname", vlan->ifname);
+ blobmsg_add_string(&b, "bridge", vlan->bridge);
+ blobmsg_add_u32(&b, "vlan_id", vlan->vlan_id);
+
+ if (desc->notempty) {
+ blobmsg_add_u32(&b, "untagged", desc->untagged);
+ c = blobmsg_open_array(&b, "tagged");
+ for (i = 0; i < ARRAY_SIZE(desc->tagged) && desc->tagged[i]; i++)
+ blobmsg_add_u32(&b, "", desc->tagged[i]);
+ blobmsg_close_array(&b, c);
+ }
+
+ ubus_notify(ctx, &hapd->ubus.obj, action, b.head, -1);
+}
+
+void hostapd_ubus_add_vlan(struct hostapd_data *hapd, struct hostapd_vlan *vlan)
+{
+ hostapd_ubus_vlan_action(hapd, vlan, "vlan_add");
+}
+
+void hostapd_ubus_remove_vlan(struct hostapd_data *hapd, struct hostapd_vlan *vlan)
+{
+ hostapd_ubus_vlan_action(hapd, vlan, "vlan_remove");
+}
+
+struct ubus_event_req {
+ struct ubus_notify_request nreq;
+ int resp;
+};
+
+static void
+ubus_event_cb(struct ubus_notify_request *req, int idx, int ret)
+{
+ struct ubus_event_req *ureq = container_of(req, struct ubus_event_req, nreq);
+
+ ureq->resp = ret;
+}
+
+int hostapd_ubus_handle_event(struct hostapd_data *hapd, struct hostapd_ubus_request *req)
+{
+ struct ubus_banned_client *ban;
+ const char *types[HOSTAPD_UBUS_TYPE_MAX] = {
+ [HOSTAPD_UBUS_PROBE_REQ] = "probe",
+ [HOSTAPD_UBUS_AUTH_REQ] = "auth",
+ [HOSTAPD_UBUS_ASSOC_REQ] = "assoc",
+ };
+ const char *type = "mgmt";
+ struct ubus_event_req ureq = {};
+ const u8 *addr;
+
+ if (req->mgmt_frame)
+ addr = req->mgmt_frame->sa;
+ else
+ addr = req->addr;
+
+ ban = avl_find_element(&hapd->ubus.banned, addr, ban, avl);
+ if (ban)
+ return WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
+
+ if (!hapd->ubus.obj.has_subscribers)
+ return WLAN_STATUS_SUCCESS;
+
+ if (req->type < ARRAY_SIZE(types))
+ type = types[req->type];
+
+ blob_buf_init(&b, 0);
+ blobmsg_add_macaddr(&b, "address", addr);
+ if (req->mgmt_frame)
+ blobmsg_add_macaddr(&b, "target", req->mgmt_frame->da);
+ if (req->ssi_signal)
+ blobmsg_add_u32(&b, "signal", req->ssi_signal);
+ blobmsg_add_u32(&b, "freq", hapd->iface->freq);
+
+ if (req->elems) {
+ if(req->elems->ht_capabilities)
+ {
+ struct ieee80211_ht_capabilities *ht_capabilities;
+ void *ht_cap, *ht_cap_mcs_set, *mcs_set;
+
+
+ ht_capabilities = (struct ieee80211_ht_capabilities*) req->elems->ht_capabilities;
+ ht_cap = blobmsg_open_table(&b, "ht_capabilities");
+ blobmsg_add_u16(&b, "ht_capabilities_info", ht_capabilities->ht_capabilities_info);
+ ht_cap_mcs_set = blobmsg_open_table(&b, "supported_mcs_set");
+ blobmsg_add_u16(&b, "a_mpdu_params", ht_capabilities->a_mpdu_params);
+ blobmsg_add_u16(&b, "ht_extended_capabilities", ht_capabilities->ht_extended_capabilities);
+ blobmsg_add_u32(&b, "tx_bf_capability_info", ht_capabilities->tx_bf_capability_info);
+ blobmsg_add_u16(&b, "asel_capabilities", ht_capabilities->asel_capabilities);
+ mcs_set = blobmsg_open_array(&b, "supported_mcs_set");
+ for (int i = 0; i < 16; i++) {
+ blobmsg_add_u16(&b, NULL, (u16) ht_capabilities->supported_mcs_set[i]);
+ }
+ blobmsg_close_array(&b, mcs_set);
+ blobmsg_close_table(&b, ht_cap_mcs_set);
+ blobmsg_close_table(&b, ht_cap);
+ }
+ if(req->elems->vht_capabilities)
+ {
+ struct ieee80211_vht_capabilities *vht_capabilities;
+ void *vht_cap, *vht_cap_mcs_set;
+
+ vht_capabilities = (struct ieee80211_vht_capabilities*) req->elems->vht_capabilities;
+ vht_cap = blobmsg_open_table(&b, "vht_capabilities");
+ blobmsg_add_u32(&b, "vht_capabilities_info", vht_capabilities->vht_capabilities_info);
+ vht_cap_mcs_set = blobmsg_open_table(&b, "vht_supported_mcs_set");
+ blobmsg_add_u16(&b, "rx_map", vht_capabilities->vht_supported_mcs_set.rx_map);
+ blobmsg_add_u16(&b, "rx_highest", vht_capabilities->vht_supported_mcs_set.rx_highest);
+ blobmsg_add_u16(&b, "tx_map", vht_capabilities->vht_supported_mcs_set.tx_map);
+ blobmsg_add_u16(&b, "tx_highest", vht_capabilities->vht_supported_mcs_set.tx_highest);
+ blobmsg_close_table(&b, vht_cap_mcs_set);
+ blobmsg_close_table(&b, vht_cap);
+ }
+ }
+
+ if (!hapd->ubus.notify_response) {
+ ubus_notify(ctx, &hapd->ubus.obj, type, b.head, -1);
+ return WLAN_STATUS_SUCCESS;
+ }
+
+ if (ubus_notify_async(ctx, &hapd->ubus.obj, type, b.head, &ureq.nreq))
+ return WLAN_STATUS_SUCCESS;
+
+ ureq.nreq.status_cb = ubus_event_cb;
+ ubus_complete_request(ctx, &ureq.nreq.req, 100);
+
+ if (ureq.resp)
+ return ureq.resp;
+
+ return WLAN_STATUS_SUCCESS;
+}
+
+void hostapd_ubus_notify(struct hostapd_data *hapd, const char *type, const u8 *addr)
+{
+ if (!hapd->ubus.obj.has_subscribers)
+ return;
+
+ if (!addr)
+ return;
+
+ blob_buf_init(&b, 0);
+ blobmsg_add_macaddr(&b, "address", addr);
+
+ ubus_notify(ctx, &hapd->ubus.obj, type, b.head, -1);
+}
+
+void hostapd_ubus_notify_authorized(struct hostapd_data *hapd, struct sta_info *sta,
+ const char *auth_alg)
+{
+ if (!hapd->ubus.obj.has_subscribers)
+ return;
+
+ blob_buf_init(&b, 0);
+ blobmsg_add_macaddr(&b, "address", sta->addr);
+ if (auth_alg)
+ blobmsg_add_string(&b, "auth-alg", auth_alg);
+
+ ubus_notify(ctx, &hapd->ubus.obj, "sta-authorized", b.head, -1);
+}
+
+void hostapd_ubus_notify_beacon_report(
+ struct hostapd_data *hapd, const u8 *addr, u8 token, u8 rep_mode,
+ struct rrm_measurement_beacon_report *rep, size_t len)
+{
+ if (!hapd->ubus.obj.has_subscribers)
+ return;
+
+ if (!addr || !rep)
+ return;
+
+ blob_buf_init(&b, 0);
+ blobmsg_add_macaddr(&b, "address", addr);
+ blobmsg_add_u16(&b, "op-class", rep->op_class);
+ blobmsg_add_u16(&b, "channel", rep->channel);
+ blobmsg_add_u64(&b, "start-time", rep->start_time);
+ blobmsg_add_u16(&b, "duration", rep->duration);
+ blobmsg_add_u16(&b, "report-info", rep->report_info);
+ blobmsg_add_u16(&b, "rcpi", rep->rcpi);
+ blobmsg_add_u16(&b, "rsni", rep->rsni);
+ blobmsg_add_macaddr(&b, "bssid", rep->bssid);
+ blobmsg_add_u16(&b, "antenna-id", rep->antenna_id);
+ blobmsg_add_u16(&b, "parent-tsf", rep->parent_tsf);
+ blobmsg_add_u16(&b, "rep-mode", rep_mode);
+
+ ubus_notify(ctx, &hapd->ubus.obj, "beacon-report", b.head, -1);
+}
+
+void hostapd_ubus_notify_radar_detected(struct hostapd_iface *iface, int frequency,
+ int chan_width, int cf1, int cf2)
+{
+ struct hostapd_data *hapd;
+ int i;
+
+ blob_buf_init(&b, 0);
+ blobmsg_add_u16(&b, "frequency", frequency);
+ blobmsg_add_u16(&b, "width", chan_width);
+ blobmsg_add_u16(&b, "center1", cf1);
+ blobmsg_add_u16(&b, "center2", cf2);
+
+ for (i = 0; i < iface->num_bss; i++) {
+ hapd = iface->bss[i];
+ ubus_notify(ctx, &hapd->ubus.obj, "radar-detected", b.head, -1);
+ }
+}
+
+#ifdef CONFIG_WNM_AP
+static void hostapd_ubus_notify_bss_transition_add_candidate_list(
+ const u8 *candidate_list, u16 candidate_list_len)
+{
+ char *cl_str;
+ int i;
+
+ if (candidate_list_len == 0)
+ return;
+
+ cl_str = blobmsg_alloc_string_buffer(&b, "candidate-list", candidate_list_len * 2 + 1);
+ for (i = 0; i < candidate_list_len; i++)
+ snprintf(&cl_str[i*2], 3, "%02X", candidate_list[i]);
+ blobmsg_add_string_buffer(&b);
+
+}
+#endif
+
+void hostapd_ubus_notify_bss_transition_response(
+ struct hostapd_data *hapd, const u8 *addr, u8 dialog_token, u8 status_code,
+ u8 bss_termination_delay, const u8 *target_bssid,
+ const u8 *candidate_list, u16 candidate_list_len)
+{
+#ifdef CONFIG_WNM_AP
+ u16 i;
+
+ if (!hapd->ubus.obj.has_subscribers)
+ return;
+
+ if (!addr)
+ return;
+
+ blob_buf_init(&b, 0);
+ blobmsg_add_macaddr(&b, "address", addr);
+ blobmsg_add_u8(&b, "dialog-token", dialog_token);
+ blobmsg_add_u8(&b, "status-code", status_code);
+ blobmsg_add_u8(&b, "bss-termination-delay", bss_termination_delay);
+ if (target_bssid)
+ blobmsg_add_macaddr(&b, "target-bssid", target_bssid);
+
+ hostapd_ubus_notify_bss_transition_add_candidate_list(candidate_list, candidate_list_len);
+
+ ubus_notify(ctx, &hapd->ubus.obj, "bss-transition-response", b.head, -1);
+#endif
+}
+
+int hostapd_ubus_notify_bss_transition_query(
+ struct hostapd_data *hapd, const u8 *addr, u8 dialog_token, u8 reason,
+ const u8 *candidate_list, u16 candidate_list_len)
+{
+#ifdef CONFIG_WNM_AP
+ struct ubus_event_req ureq = {};
+ char *cl_str;
+ u16 i;
+
+ if (!hapd->ubus.obj.has_subscribers)
+ return 0;
+
+ if (!addr)
+ return 0;
+
+ blob_buf_init(&b, 0);
+ blobmsg_add_macaddr(&b, "address", addr);
+ blobmsg_add_u8(&b, "dialog-token", dialog_token);
+ blobmsg_add_u8(&b, "reason", reason);
+ hostapd_ubus_notify_bss_transition_add_candidate_list(candidate_list, candidate_list_len);
+
+ if (!hapd->ubus.notify_response) {
+ ubus_notify(ctx, &hapd->ubus.obj, "bss-transition-query", b.head, -1);
+ return 0;
+ }
+
+ if (ubus_notify_async(ctx, &hapd->ubus.obj, "bss-transition-query", b.head, &ureq.nreq))
+ return 0;
+
+ ureq.nreq.status_cb = ubus_event_cb;
+ ubus_complete_request(ctx, &ureq.nreq.req, 100);
+
+ return ureq.resp;
+#endif
+}
diff --git a/recipes-wifi/wpa-supplicant/files/src-2.10.3/src/ap/ubus.h b/recipes-wifi/wpa-supplicant/files/src-2.10.3/src/ap/ubus.h
new file mode 100644
index 0000000..b0f7c44
--- /dev/null
+++ b/recipes-wifi/wpa-supplicant/files/src-2.10.3/src/ap/ubus.h
@@ -0,0 +1,154 @@
+/*
+ * hostapd / ubus support
+ * Copyright (c) 2013, Felix Fietkau <nbd@nbd.name>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+#ifndef __HOSTAPD_UBUS_H
+#define __HOSTAPD_UBUS_H
+
+enum hostapd_ubus_event_type {
+ HOSTAPD_UBUS_PROBE_REQ,
+ HOSTAPD_UBUS_AUTH_REQ,
+ HOSTAPD_UBUS_ASSOC_REQ,
+ HOSTAPD_UBUS_TYPE_MAX
+};
+
+struct hostapd_ubus_request {
+ enum hostapd_ubus_event_type type;
+ const struct ieee80211_mgmt *mgmt_frame;
+ const struct ieee802_11_elems *elems;
+ int ssi_signal; /* dBm */
+ const u8 *addr;
+};
+
+struct hostapd_iface;
+struct hostapd_data;
+struct hapd_interfaces;
+struct rrm_measurement_beacon_report;
+
+#ifdef UBUS_SUPPORT
+
+#include <libubox/avl.h>
+#include <libubus.h>
+
+struct hostapd_ubus_bss {
+ struct ubus_object obj;
+ struct avl_tree banned;
+ int notify_response;
+};
+
+void hostapd_ubus_add_iface(struct hostapd_iface *iface);
+void hostapd_ubus_free_iface(struct hostapd_iface *iface);
+void hostapd_ubus_add_bss(struct hostapd_data *hapd);
+void hostapd_ubus_free_bss(struct hostapd_data *hapd);
+void hostapd_ubus_add_vlan(struct hostapd_data *hapd, struct hostapd_vlan *vlan);
+void hostapd_ubus_remove_vlan(struct hostapd_data *hapd, struct hostapd_vlan *vlan);
+
+int hostapd_ubus_handle_event(struct hostapd_data *hapd, struct hostapd_ubus_request *req);
+void hostapd_ubus_handle_link_measurement(struct hostapd_data *hapd, const u8 *data, size_t len);
+void hostapd_ubus_notify(struct hostapd_data *hapd, const char *type, const u8 *mac);
+void hostapd_ubus_notify_beacon_report(struct hostapd_data *hapd,
+ const u8 *addr, u8 token, u8 rep_mode,
+ struct rrm_measurement_beacon_report *rep,
+ size_t len);
+void hostapd_ubus_notify_radar_detected(struct hostapd_iface *iface, int frequency,
+ int chan_width, int cf1, int cf2);
+
+void hostapd_ubus_notify_bss_transition_response(
+ struct hostapd_data *hapd, const u8 *addr, u8 dialog_token, u8 status_code,
+ u8 bss_termination_delay, const u8 *target_bssid,
+ const u8 *candidate_list, u16 candidate_list_len);
+void hostapd_ubus_add(struct hapd_interfaces *interfaces);
+void hostapd_ubus_free(struct hapd_interfaces *interfaces);
+int hostapd_ubus_notify_bss_transition_query(
+ struct hostapd_data *hapd, const u8 *addr, u8 dialog_token, u8 reason,
+ const u8 *candidate_list, u16 candidate_list_len);
+void hostapd_ubus_notify_authorized(struct hostapd_data *hapd, struct sta_info *sta,
+ const char *auth_alg);
+
+#else
+
+struct hostapd_ubus_bss {};
+
+static inline void hostapd_ubus_add_iface(struct hostapd_iface *iface)
+{
+}
+
+static inline void hostapd_ubus_free_iface(struct hostapd_iface *iface)
+{
+}
+
+static inline void hostapd_ubus_add_bss(struct hostapd_data *hapd)
+{
+}
+
+static inline void hostapd_ubus_free_bss(struct hostapd_data *hapd)
+{
+}
+
+static inline void hostapd_ubus_add_vlan(struct hostapd_data *hapd, struct hostapd_vlan *vlan)
+{
+}
+
+static inline void hostapd_ubus_remove_vlan(struct hostapd_data *hapd, struct hostapd_vlan *vlan)
+{
+}
+
+static inline int hostapd_ubus_handle_event(struct hostapd_data *hapd, struct hostapd_ubus_request *req)
+{
+ return 0;
+}
+
+static inline void hostapd_ubus_handle_link_measurement(struct hostapd_data *hapd, const u8 *data, size_t len)
+{
+}
+
+static inline void hostapd_ubus_notify(struct hostapd_data *hapd, const char *type, const u8 *mac)
+{
+}
+
+static inline void hostapd_ubus_notify_beacon_report(struct hostapd_data *hapd,
+ const u8 *addr, u8 token,
+ u8 rep_mode,
+ struct rrm_measurement_beacon_report *rep,
+ size_t len)
+{
+}
+static inline void hostapd_ubus_notify_radar_detected(struct hostapd_iface *iface, int frequency,
+ int chan_width, int cf1, int cf2)
+{
+}
+
+static inline void hostapd_ubus_notify_bss_transition_response(
+ struct hostapd_data *hapd, const u8 *addr, u8 dialog_token, u8 status_code,
+ u8 bss_termination_delay, const u8 *target_bssid,
+ const u8 *candidate_list, u16 candidate_list_len)
+{
+}
+
+static inline void hostapd_ubus_add(struct hapd_interfaces *interfaces)
+{
+}
+
+static inline void hostapd_ubus_free(struct hapd_interfaces *interfaces)
+{
+}
+
+static inline int hostapd_ubus_notify_bss_transition_query(
+ struct hostapd_data *hapd, const u8 *addr, u8 dialog_token, u8 reason,
+ const u8 *candidate_list, u16 candidate_list_len)
+{
+ return 0;
+}
+
+static inline void
+hostapd_ubus_notify_authorized(struct hostapd_data *hapd, struct sta_info *sta,
+ const char *auth_alg)
+{
+}
+
+#endif
+
+#endif
diff --git a/recipes-wifi/wpa-supplicant/files/src-2.10.3/src/ap/ucode.c b/recipes-wifi/wpa-supplicant/files/src-2.10.3/src/ap/ucode.c
new file mode 100644
index 0000000..137cb81
--- /dev/null
+++ b/recipes-wifi/wpa-supplicant/files/src-2.10.3/src/ap/ucode.c
@@ -0,0 +1,394 @@
+#include <sys/un.h>
+
+#include "utils/includes.h"
+#include "utils/common.h"
+#include "utils/ucode.h"
+#include "hostapd.h"
+#include "ap_drv_ops.h"
+#include <libubox/uloop.h>
+
+static uc_resource_type_t *global_type, *bss_type, *iface_type;
+static struct hapd_interfaces *interfaces;
+static uc_value_t *global, *bss_registry, *iface_registry;
+static uc_vm_t *vm;
+
+static uc_value_t *
+hostapd_ucode_bss_get_uval(struct hostapd_data *hapd)
+{
+ uc_value_t *val;
+
+ if (hapd->ucode.idx)
+ return wpa_ucode_registry_get(bss_registry, hapd->ucode.idx);
+
+ val = uc_resource_new(bss_type, hapd);
+ wpa_ucode_registry_add(bss_registry, val, &hapd->ucode.idx);
+
+ return val;
+}
+
+static uc_value_t *
+hostapd_ucode_iface_get_uval(struct hostapd_iface *hapd)
+{
+ uc_value_t *val;
+
+ if (hapd->ucode.idx)
+ return wpa_ucode_registry_get(iface_registry, hapd->ucode.idx);
+
+ val = uc_resource_new(iface_type, hapd);
+ wpa_ucode_registry_add(iface_registry, val, &hapd->ucode.idx);
+
+ return val;
+}
+
+static void
+hostapd_ucode_update_bss_list(struct hostapd_iface *iface)
+{
+ uc_value_t *ifval, *list;
+ int i;
+
+ list = ucv_array_new(vm);
+ for (i = 0; i < iface->num_bss; i++) {
+ struct hostapd_data *hapd = iface->bss[i];
+ uc_value_t *val = hostapd_ucode_bss_get_uval(hapd);
+ uc_value_t *proto = ucv_prototype_get(val);
+
+ ucv_object_add(proto, "name", ucv_get(ucv_string_new(hapd->conf->iface)));
+ ucv_object_add(proto, "index", ucv_int64_new(i));
+ ucv_array_set(list, i, ucv_get(val));
+ }
+
+ ifval = hostapd_ucode_iface_get_uval(iface);
+ ucv_object_add(ucv_prototype_get(ifval), "bss", ucv_get(list));
+}
+
+static void
+hostapd_ucode_update_interfaces(void)
+{
+ uc_value_t *ifs = ucv_object_new(vm);
+ int i;
+
+ for (i = 0; i < interfaces->count; i++) {
+ struct hostapd_iface *iface = interfaces->iface[i];
+
+ ucv_object_add(ifs, iface->phy, ucv_get(hostapd_ucode_iface_get_uval(iface)));
+ hostapd_ucode_update_bss_list(iface);
+ }
+
+ ucv_object_add(ucv_prototype_get(global), "interfaces", ucv_get(ifs));
+ ucv_gc(vm);
+}
+
+static uc_value_t *
+uc_hostapd_add_iface(uc_vm_t *vm, size_t nargs)
+{
+ uc_value_t *iface = uc_fn_arg(0);
+ int ret;
+
+ if (ucv_type(iface) != UC_STRING)
+ return ucv_int64_new(-1);
+
+ ret = hostapd_add_iface(interfaces, ucv_string_get(iface));
+ hostapd_ucode_update_interfaces();
+
+ return ucv_int64_new(ret);
+}
+
+static uc_value_t *
+uc_hostapd_remove_iface(uc_vm_t *vm, size_t nargs)
+{
+ uc_value_t *iface = uc_fn_arg(0);
+
+ if (ucv_type(iface) != UC_STRING)
+ return NULL;
+
+ hostapd_remove_iface(interfaces, ucv_string_get(iface));
+ hostapd_ucode_update_interfaces();
+
+ return NULL;
+}
+
+static uc_value_t *
+uc_hostapd_bss_set_config(uc_vm_t *vm, size_t nargs)
+{
+ struct hostapd_data *hapd = uc_fn_thisval("hostapd.bss");
+ struct hostapd_bss_config *old_bss;
+ struct hostapd_iface *iface;
+ struct hostapd_config *conf;
+ uc_value_t *file = uc_fn_arg(0);
+ uc_value_t *index = uc_fn_arg(1);
+ unsigned int i, idx = 0;
+ int ret = -1;
+
+ if (!hapd || ucv_type(file) != UC_STRING)
+ goto out;
+
+ if (ucv_type(index) == UC_INTEGER)
+ idx = ucv_int64_get(index);
+
+ iface = hapd->iface;
+ conf = interfaces->config_read_cb(ucv_string_get(file));
+ if (!conf || idx > conf->num_bss || !conf->bss[idx])
+ goto out;
+
+ hostapd_bss_deinit_no_free(hapd);
+ hostapd_drv_stop_ap(hapd);
+ hostapd_free_hapd_data(hapd);
+
+ old_bss = hapd->conf;
+ for (i = 0; i < iface->conf->num_bss; i++)
+ if (iface->conf->bss[i] == hapd->conf)
+ iface->conf->bss[i] = conf->bss[idx];
+ hapd->conf = conf->bss[idx];
+ conf->bss[idx] = old_bss;
+ hostapd_config_free(conf);
+
+ hostapd_setup_bss(hapd, hapd == iface->bss[0], !iface->conf->mbssid);
+
+ ret = 0;
+
+out:
+ return ucv_int64_new(ret);
+}
+
+static void
+hostapd_remove_iface_bss_conf(struct hostapd_config *iconf,
+ struct hostapd_bss_config *conf)
+{
+ int i;
+
+ for (i = 0; i < iconf->num_bss; i++)
+ if (iconf->bss[i] == conf)
+ break;
+
+ if (i == iconf->num_bss)
+ return;
+
+ for (i++; i < iconf->num_bss; i++)
+ iconf->bss[i - 1] = iconf->bss[i];
+ iconf->num_bss--;
+}
+
+
+static uc_value_t *
+uc_hostapd_bss_delete(uc_vm_t *vm, size_t nargs)
+{
+ struct hostapd_data *hapd = uc_fn_thisval("hostapd.bss");
+ struct hostapd_iface *iface;
+ int i, idx;
+
+ if (!hapd || hapd == hapd->iface->bss[0])
+ return NULL;
+
+ iface = hapd->iface;
+ for (idx = 0; idx < iface->num_bss; idx++)
+ if (iface->bss[idx] == hapd)
+ break;
+
+ if (idx == iface->num_bss)
+ return NULL;
+
+ for (i = idx + 1; i < iface->num_bss; i++)
+ iface->bss[i - 1] = iface->bss[i];
+ iface->num_bss--;
+
+ hostapd_drv_stop_ap(hapd);
+ hostapd_bss_deinit(hapd);
+ hostapd_remove_iface_bss_conf(iface->conf, hapd->conf);
+ hostapd_config_free_bss(hapd->conf);
+ os_free(hapd);
+
+ hostapd_ucode_update_bss_list(iface);
+ ucv_gc(vm);
+
+ return NULL;
+}
+
+static uc_value_t *
+uc_hostapd_iface_add_bss(uc_vm_t *vm, size_t nargs)
+{
+ struct hostapd_iface *iface = uc_fn_thisval("hostapd.iface");
+ struct hostapd_bss_config *bss;
+ struct hostapd_config *conf;
+ struct hostapd_data *hapd;
+ uc_value_t *file = uc_fn_arg(0);
+ uc_value_t *index = uc_fn_arg(1);
+ unsigned int idx = 0;
+ uc_value_t *ret = NULL;
+
+ if (!iface || ucv_type(file) != UC_STRING)
+ goto out;
+
+ if (ucv_type(index) == UC_INTEGER)
+ idx = ucv_int64_get(index);
+
+ conf = interfaces->config_read_cb(ucv_string_get(file));
+ if (!conf || idx > conf->num_bss || !conf->bss[idx])
+ goto out;
+
+ bss = conf->bss[idx];
+ hapd = hostapd_alloc_bss_data(iface, iface->conf, bss);
+ if (!hapd)
+ goto out;
+
+ hapd->driver = iface->bss[0]->driver;
+ hapd->drv_priv = iface->bss[0]->drv_priv;
+ if (interfaces->ctrl_iface_init &&
+ interfaces->ctrl_iface_init(hapd) < 0)
+ goto free_hapd;
+
+ if (iface->state == HAPD_IFACE_ENABLED &&
+ hostapd_setup_bss(hapd, -1, true))
+ goto deinit_ctrl;
+
+ iface->bss = os_realloc_array(iface->bss, iface->num_bss + 1,
+ sizeof(*iface->bss));
+ iface->bss[iface->num_bss++] = hapd;
+
+ iface->conf->bss = os_realloc_array(iface->conf->bss,
+ iface->conf->num_bss + 1,
+ sizeof(*iface->conf->bss));
+ iface->conf->bss[iface->conf->num_bss] = bss;
+ conf->bss[idx] = NULL;
+ ret = hostapd_ucode_bss_get_uval(hapd);
+ hostapd_ucode_update_bss_list(iface);
+ goto out;
+
+deinit_ctrl:
+ if (interfaces->ctrl_iface_deinit)
+ interfaces->ctrl_iface_deinit(hapd);
+free_hapd:
+ hostapd_free_hapd_data(hapd);
+ os_free(hapd);
+out:
+ hostapd_config_free(conf);
+ return ret;
+}
+
+static uc_value_t *
+uc_hostapd_bss_ctrl(uc_vm_t *vm, size_t nargs)
+{
+ struct hostapd_data *hapd = uc_fn_thisval("hostapd.bss");
+ uc_value_t *arg = uc_fn_arg(0);
+ struct sockaddr_storage from = {};
+ static char reply[4096];
+ int reply_len;
+
+ if (!hapd || !interfaces->ctrl_iface_recv ||
+ ucv_type(arg) != UC_STRING)
+ return NULL;
+
+ reply_len = interfaces->ctrl_iface_recv(hapd, ucv_string_get(arg),
+ reply, sizeof(reply),
+ &from, sizeof(from));
+ if (reply_len < 0)
+ return NULL;
+
+ if (reply_len && reply[reply_len - 1] == '\n')
+ reply_len--;
+
+ return ucv_string_new_length(reply, reply_len);
+}
+
+int hostapd_ucode_init(struct hapd_interfaces *ifaces)
+{
+ static const uc_function_list_t global_fns[] = {
+ { "printf", uc_wpa_printf },
+ { "getpid", uc_wpa_getpid },
+ { "sha1", uc_wpa_sha1 },
+ { "add_iface", uc_hostapd_add_iface },
+ { "remove_iface", uc_hostapd_remove_iface },
+ };
+ static const uc_function_list_t bss_fns[] = {
+ { "ctrl", uc_hostapd_bss_ctrl },
+ { "set_config", uc_hostapd_bss_set_config },
+ { "delete", uc_hostapd_bss_delete },
+ };
+ static const uc_function_list_t iface_fns[] = {
+ { "add_bss", uc_hostapd_iface_add_bss }
+ };
+ uc_value_t *data, *proto;
+
+ interfaces = ifaces;
+ vm = wpa_ucode_create_vm();
+
+ global_type = uc_type_declare(vm, "hostapd.global", global_fns, NULL);
+ bss_type = uc_type_declare(vm, "hostapd.bss", bss_fns, NULL);
+ iface_type = uc_type_declare(vm, "hostapd.iface", iface_fns, NULL);
+
+ bss_registry = ucv_array_new(vm);
+ uc_vm_registry_set(vm, "hostap.bss_registry", bss_registry);
+
+ iface_registry = ucv_array_new(vm);
+ uc_vm_registry_set(vm, "hostap.iface_registry", iface_registry);
+
+ global = wpa_ucode_global_init("hostapd", global_type);
+
+ if (wpa_ucode_run(HOSTAPD_UC_PATH "hostapd.uc"))
+ goto free_vm;
+ ucv_gc(vm);
+
+ return 0;
+
+free_vm:
+ wpa_ucode_free_vm();
+ return -1;
+}
+
+void hostapd_ucode_free(void)
+{
+ if (wpa_ucode_call_prepare("shutdown") == 0)
+ ucv_put(wpa_ucode_call(0));
+ wpa_ucode_free_vm();
+}
+
+void hostapd_ucode_free_iface(struct hostapd_iface *iface)
+{
+ wpa_ucode_registry_remove(iface_registry, iface->ucode.idx);
+}
+
+void hostapd_ucode_add_bss(struct hostapd_data *hapd)
+{
+ uc_value_t *val;
+
+ if (wpa_ucode_call_prepare("bss_add"))
+ return;
+
+ val = hostapd_ucode_bss_get_uval(hapd);
+ uc_value_push(ucv_get(ucv_string_new(hapd->conf->iface)));
+ uc_value_push(ucv_get(val));
+ ucv_put(wpa_ucode_call(2));
+ ucv_gc(vm);
+}
+
+void hostapd_ucode_reload_bss(struct hostapd_data *hapd, int reconf)
+{
+ uc_value_t *val;
+
+ if (wpa_ucode_call_prepare("bss_reload"))
+ return;
+
+ val = hostapd_ucode_bss_get_uval(hapd);
+ uc_value_push(ucv_get(ucv_string_new(hapd->conf->iface)));
+ uc_value_push(ucv_get(val));
+ uc_value_push(ucv_int64_new(reconf));
+ ucv_put(wpa_ucode_call(3));
+ ucv_gc(vm);
+}
+
+void hostapd_ucode_free_bss(struct hostapd_data *hapd)
+{
+ uc_value_t *val;
+
+ val = wpa_ucode_registry_remove(bss_registry, hapd->ucode.idx);
+ if (!val)
+ return;
+
+ hapd->ucode.idx = 0;
+ if (wpa_ucode_call_prepare("bss_remove"))
+ return;
+
+ uc_value_push(ucv_string_new(hapd->conf->iface));
+ uc_value_push(ucv_get(val));
+ ucv_put(wpa_ucode_call(2));
+ ucv_gc(vm);
+}
diff --git a/recipes-wifi/wpa-supplicant/files/src-2.10.3/src/ap/ucode.h b/recipes-wifi/wpa-supplicant/files/src-2.10.3/src/ap/ucode.h
new file mode 100644
index 0000000..dbc49e6
--- /dev/null
+++ b/recipes-wifi/wpa-supplicant/files/src-2.10.3/src/ap/ucode.h
@@ -0,0 +1,54 @@
+#ifndef __HOSTAPD_AP_UCODE_H
+#define __HOSTAPD_AP_UCODE_H
+
+#include "utils/ucode.h"
+
+struct hostapd_data;
+
+struct hostapd_ucode_bss {
+#ifdef UCODE_SUPPORT
+ int idx;
+#endif
+};
+
+struct hostapd_ucode_iface {
+#ifdef UCODE_SUPPORT
+ int idx;
+#endif
+};
+
+#ifdef UCODE_SUPPORT
+
+int hostapd_ucode_init(struct hapd_interfaces *ifaces);
+
+void hostapd_ucode_free(void);
+void hostapd_ucode_free_iface(struct hostapd_iface *iface);
+void hostapd_ucode_add_bss(struct hostapd_data *hapd);
+void hostapd_ucode_free_bss(struct hostapd_data *hapd);
+void hostapd_ucode_reload_bss(struct hostapd_data *hapd, int reconf);
+
+#else
+
+static inline int hostapd_ucode_init(struct hapd_interfaces *ifaces)
+{
+ return -EINVAL;
+}
+static inline void hostapd_ucode_free(void)
+{
+}
+static inline void hostapd_ucode_free_iface(struct hostapd_iface *iface)
+{
+}
+static inline void hostapd_ucode_reload_bss(struct hostapd_data *hapd, int reconf)
+{
+}
+static inline void hostapd_ucode_add_bss(struct hostapd_data *hapd)
+{
+}
+static inline void hostapd_ucode_free_bss(struct hostapd_data *hapd)
+{
+}
+
+#endif
+
+#endif
diff --git a/recipes-wifi/wpa-supplicant/files/src-2.10.3/src/utils/build_features.h b/recipes-wifi/wpa-supplicant/files/src-2.10.3/src/utils/build_features.h
new file mode 100644
index 0000000..553769e
--- /dev/null
+++ b/recipes-wifi/wpa-supplicant/files/src-2.10.3/src/utils/build_features.h
@@ -0,0 +1,65 @@
+#ifndef BUILD_FEATURES_H
+#define BUILD_FEATURES_H
+
+static inline int has_feature(const char *feat)
+{
+#if defined(IEEE8021X_EAPOL) || (defined(HOSTAPD) && !defined(CONFIG_NO_RADIUS))
+ if (!strcmp(feat, "eap"))
+ return 1;
+#endif
+#ifdef CONFIG_IEEE80211AC
+ if (!strcmp(feat, "11ac"))
+ return 1;
+#endif
+#ifdef CONFIG_IEEE80211AX
+ if (!strcmp(feat, "11ax"))
+ return 1;
+#endif
+#ifdef CONFIG_IEEE80211R
+ if (!strcmp(feat, "11r"))
+ return 1;
+#endif
+#ifdef CONFIG_ACS
+ if (!strcmp(feat, "acs"))
+ return 1;
+#endif
+#ifdef CONFIG_SAE
+ if (!strcmp(feat, "sae"))
+ return 1;
+#endif
+#ifdef CONFIG_OWE
+ if (!strcmp(feat, "owe"))
+ return 1;
+#endif
+#ifdef CONFIG_SUITEB192
+ if (!strcmp(feat, "suiteb192"))
+ return 1;
+#endif
+#ifdef CONFIG_WEP
+ if (!strcmp(feat, "wep"))
+ return 1;
+#endif
+#ifdef CONFIG_HS20
+ if (!strcmp(feat, "hs20"))
+ return 1;
+#endif
+#ifdef CONFIG_WPS
+ if (!strcmp(feat, "wps"))
+ return 1;
+#endif
+#ifdef CONFIG_FILS
+ if (!strcmp(feat, "fils"))
+ return 1;
+#endif
+#ifdef CONFIG_OCV
+ if (!strcmp(feat, "ocv"))
+ return 1;
+#endif
+#ifdef CONFIG_MESH
+ if (!strcmp(feat, "mesh"))
+ return 1;
+#endif
+ return 0;
+}
+
+#endif /* BUILD_FEATURES_H */
diff --git a/recipes-wifi/wpa-supplicant/files/src-2.10.3/src/utils/ucode.c b/recipes-wifi/wpa-supplicant/files/src-2.10.3/src/utils/ucode.c
new file mode 100644
index 0000000..a92913a
--- /dev/null
+++ b/recipes-wifi/wpa-supplicant/files/src-2.10.3/src/utils/ucode.c
@@ -0,0 +1,251 @@
+#include <unistd.h>
+#include "ucode.h"
+#include "utils/eloop.h"
+#include "crypto/crypto.h"
+#include "crypto/sha1.h"
+#include <libubox/uloop.h>
+#include <ucode/compiler.h>
+
+static uc_value_t *registry;
+static uc_vm_t vm;
+static struct uloop_timeout gc_timer;
+
+static void uc_gc_timer(struct uloop_timeout *timeout)
+{
+ ucv_gc(&vm);
+}
+
+uc_value_t *uc_wpa_printf(uc_vm_t *vm, size_t nargs)
+{
+ uc_value_t *level = uc_fn_arg(0);
+ uc_value_t *ret, **args;
+ uc_cfn_ptr_t _sprintf;
+ int l = MSG_INFO;
+ int i, start = 0;
+
+ _sprintf = uc_stdlib_function("sprintf");
+ if (!sprintf)
+ return NULL;
+
+ if (ucv_type(level) == UC_INTEGER) {
+ l = ucv_int64_get(level);
+ start++;
+ }
+
+ if (nargs <= start)
+ return NULL;
+
+ ret = _sprintf(vm, nargs - start);
+ if (ucv_type(ret) != UC_STRING)
+ return NULL;
+
+ wpa_printf(l, "%s", ucv_string_get(ret));
+ ucv_put(ret);
+
+ return NULL;
+}
+
+uc_value_t *uc_wpa_getpid(uc_vm_t *vm, size_t nargs)
+{
+ return ucv_int64_new(getpid());
+}
+
+uc_value_t *uc_wpa_sha1(uc_vm_t *vm, size_t nargs)
+{
+ u8 hash[SHA1_MAC_LEN];
+ char hash_hex[2 * ARRAY_SIZE(hash) + 1];
+ uc_value_t *val;
+ size_t *lens;
+ const u8 **args;
+ int i;
+
+ if (!nargs)
+ return NULL;
+
+ args = alloca(nargs * sizeof(*args));
+ lens = alloca(nargs * sizeof(*lens));
+ for (i = 0; i < nargs; i++) {
+ val = uc_fn_arg(i);
+ if (ucv_type(val) != UC_STRING)
+ return NULL;
+
+ args[i] = ucv_string_get(val);
+ lens[i] = ucv_string_length(val);
+ }
+
+ if (sha1_vector(nargs, args, lens, hash))
+ return NULL;
+
+ for (i = 0; i < ARRAY_SIZE(hash); i++)
+ sprintf(hash_hex + 2 * i, "%02x", hash[i]);
+
+ return ucv_string_new_length(hash_hex, 2 * ARRAY_SIZE(hash));
+}
+
+uc_vm_t *wpa_ucode_create_vm(void)
+{
+ static uc_parse_config_t config = {
+ .strict_declarations = true,
+ .lstrip_blocks = true,
+ .trim_blocks = true,
+ .raw_mode = true
+ };
+
+ uc_search_path_init(&config.module_search_path);
+ uc_search_path_add(&config.module_search_path, HOSTAPD_UC_PATH "*.so");
+ uc_search_path_add(&config.module_search_path, HOSTAPD_UC_PATH "*.uc");
+
+ uc_vm_init(&vm, &config);
+
+ uc_stdlib_load(uc_vm_scope_get(&vm));
+ eloop_add_uloop();
+ gc_timer.cb = uc_gc_timer;
+
+ return &vm;
+}
+
+int wpa_ucode_run(const char *script)
+{
+ uc_source_t *source;
+ uc_program_t *prog;
+ uc_value_t *ops;
+ char *err;
+ int ret;
+
+ source = uc_source_new_file(script);
+ if (!source)
+ return -1;
+
+ prog = uc_compile(vm.config, source, &err);
+ uc_source_put(source);
+ if (!prog) {
+ wpa_printf(MSG_ERROR, "Error loading ucode: %s\n", err);
+ return -1;
+ }
+
+ ret = uc_vm_execute(&vm, prog, &ops);
+ uc_program_put(prog);
+ if (ret || !ops)
+ return -1;
+
+ registry = ucv_array_new(&vm);
+ uc_vm_registry_set(&vm, "hostap.registry", registry);
+ ucv_array_set(registry, 0, ucv_get(ops));
+
+ return 0;
+}
+
+int wpa_ucode_call_prepare(const char *fname)
+{
+ uc_value_t *obj, *func;
+
+ if (!registry)
+ return -1;
+
+ obj = ucv_array_get(registry, 0);
+ if (!obj)
+ return -1;
+
+ func = ucv_object_get(obj, fname, NULL);
+ if (!ucv_is_callable(func))
+ return -1;
+
+ uc_vm_stack_push(&vm, ucv_get(obj));
+ uc_vm_stack_push(&vm, ucv_get(func));
+
+ return 0;
+}
+
+uc_value_t *wpa_ucode_global_init(const char *name, uc_resource_type_t *global_type)
+{
+ uc_value_t *global = uc_resource_new(global_type, NULL);
+ uc_value_t *proto;
+
+ uc_vm_registry_set(&vm, "hostap.global", global);
+ proto = ucv_prototype_get(global);
+ ucv_object_add(proto, "data", ucv_get(ucv_object_new(&vm)));
+
+#define ADD_CONST(x) ucv_object_add(proto, #x, ucv_int64_new(x))
+ ADD_CONST(MSG_EXCESSIVE);
+ ADD_CONST(MSG_MSGDUMP);
+ ADD_CONST(MSG_DEBUG);
+ ADD_CONST(MSG_INFO);
+ ADD_CONST(MSG_WARNING);
+ ADD_CONST(MSG_ERROR);
+#undef ADD_CONST
+
+ ucv_object_add(uc_vm_scope_get(&vm), name, ucv_get(global));
+
+ return global;
+}
+
+static uc_value_t *wpa_ucode_prototype_clone(uc_value_t *uval)
+{
+ uc_value_t *proto, *proto_new;
+
+ proto = ucv_prototype_get(uval);
+ proto_new = ucv_object_new(&vm);
+
+ ucv_object_foreach(proto, key, val)
+ ucv_object_add(proto_new, key, ucv_get(val));
+ ucv_prototype_set(uval, ucv_get(proto));
+
+ return proto;
+}
+
+void wpa_ucode_registry_add(uc_value_t *reg, uc_value_t *val, int *idx)
+{
+ uc_value_t *data;
+ int i = 0;
+
+ while (ucv_array_get(reg, i))
+ i++;
+
+ ucv_array_set(reg, i, ucv_get(val));
+
+ data = ucv_object_new(&vm);
+ ucv_object_add(wpa_ucode_prototype_clone(val), "data", ucv_get(data));
+
+ *idx = i + 1;
+}
+
+uc_value_t *wpa_ucode_registry_get(uc_value_t *reg, int idx)
+{
+ if (!idx)
+ return NULL;
+
+ return ucv_array_get(reg, idx - 1);
+}
+
+uc_value_t *wpa_ucode_registry_remove(uc_value_t *reg, int idx)
+{
+ uc_value_t *val = wpa_ucode_registry_get(reg, idx);
+
+ if (val)
+ ucv_array_set(reg, idx - 1, NULL);
+
+ return val;
+}
+
+
+uc_value_t *wpa_ucode_call(size_t nargs)
+{
+ if (uc_vm_call(&vm, true, nargs) != EXCEPTION_NONE)
+ return NULL;
+
+ if (!gc_timer.pending)
+ uloop_timeout_set(&gc_timer, 10);
+
+ return uc_vm_stack_pop(&vm);
+}
+
+void wpa_ucode_free_vm(void)
+{
+ if (!vm.config)
+ return;
+
+ uc_search_path_free(&vm.config->module_search_path);
+ uc_vm_free(&vm);
+ registry = NULL;
+ vm = (uc_vm_t){};
+}
diff --git a/recipes-wifi/wpa-supplicant/files/src-2.10.3/src/utils/ucode.h b/recipes-wifi/wpa-supplicant/files/src-2.10.3/src/utils/ucode.h
new file mode 100644
index 0000000..4caf8ad
--- /dev/null
+++ b/recipes-wifi/wpa-supplicant/files/src-2.10.3/src/utils/ucode.h
@@ -0,0 +1,28 @@
+#ifndef __HOSTAPD_UTILS_UCODE_H
+#define __HOSTAPD_UTILS_UCODE_H
+
+#include "utils/includes.h"
+#include "utils/common.h"
+#include <ucode/lib.h>
+#include <ucode/vm.h>
+
+#define HOSTAPD_UC_PATH "/usr/share/hostap/"
+
+extern uc_value_t *uc_registry;
+uc_vm_t *wpa_ucode_create_vm(void);
+int wpa_ucode_run(const char *script);
+int wpa_ucode_call_prepare(const char *fname);
+uc_value_t *wpa_ucode_call(size_t nargs);
+void wpa_ucode_free_vm(void);
+
+uc_value_t *wpa_ucode_global_init(const char *name, uc_resource_type_t *global_type);
+
+void wpa_ucode_registry_add(uc_value_t *reg, uc_value_t *val, int *idx);
+uc_value_t *wpa_ucode_registry_get(uc_value_t *reg, int idx);
+uc_value_t *wpa_ucode_registry_remove(uc_value_t *reg, int idx);
+
+uc_value_t *uc_wpa_printf(uc_vm_t *vm, size_t nargs);
+uc_value_t *uc_wpa_getpid(uc_vm_t *vm, size_t nargs);
+uc_value_t *uc_wpa_sha1(uc_vm_t *vm, size_t nargs);
+
+#endif
diff --git a/recipes-wifi/wpa-supplicant/files/src-2.10.3/wpa_supplicant/ubus.c b/recipes-wifi/wpa-supplicant/files/src-2.10.3/wpa_supplicant/ubus.c
new file mode 100644
index 0000000..1c477f0
--- /dev/null
+++ b/recipes-wifi/wpa-supplicant/files/src-2.10.3/wpa_supplicant/ubus.c
@@ -0,0 +1,280 @@
+/*
+ * wpa_supplicant / ubus support
+ * Copyright (c) 2018, Daniel Golle <daniel@makrotopia.org>
+ * Copyright (c) 2013, Felix Fietkau <nbd@nbd.name>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "utils/wpabuf.h"
+#include "common/ieee802_11_defs.h"
+#include "wpa_supplicant_i.h"
+#include "wps_supplicant.h"
+#include "ubus.h"
+
+static struct ubus_context *ctx;
+static struct blob_buf b;
+static int ctx_ref;
+
+static inline struct wpa_global *get_wpa_global_from_object(struct ubus_object *obj)
+{
+ return container_of(obj, struct wpa_global, ubus_global);
+}
+
+static inline struct wpa_supplicant *get_wpas_from_object(struct ubus_object *obj)
+{
+ return container_of(obj, struct wpa_supplicant, ubus.obj);
+}
+
+static void ubus_reconnect_timeout(void *eloop_data, void *user_ctx)
+{
+ if (ubus_reconnect(ctx, NULL)) {
+ eloop_register_timeout(1, 0, ubus_reconnect_timeout, ctx, NULL);
+ return;
+ }
+
+ ubus_add_uloop(ctx);
+}
+
+static void wpas_ubus_connection_lost(struct ubus_context *ctx)
+{
+ uloop_fd_delete(&ctx->sock);
+ eloop_register_timeout(1, 0, ubus_reconnect_timeout, ctx, NULL);
+}
+
+static bool wpas_ubus_init(void)
+{
+ if (ctx)
+ return true;
+
+ eloop_add_uloop();
+ ctx = ubus_connect(NULL);
+ if (!ctx)
+ return false;
+
+ ctx->connection_lost = wpas_ubus_connection_lost;
+ ubus_add_uloop(ctx);
+
+ return true;
+}
+
+static void wpas_ubus_ref_inc(void)
+{
+ ctx_ref++;
+}
+
+static void wpas_ubus_ref_dec(void)
+{
+ ctx_ref--;
+ if (!ctx)
+ return;
+
+ if (ctx_ref)
+ return;
+
+ uloop_fd_delete(&ctx->sock);
+ ubus_free(ctx);
+ ctx = NULL;
+}
+
+static int
+wpas_bss_get_features(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *req, const char *method,
+ struct blob_attr *msg)
+{
+ struct wpa_supplicant *wpa_s = get_wpas_from_object(obj);
+
+ blob_buf_init(&b, 0);
+ blobmsg_add_u8(&b, "ht_supported", ht_supported(wpa_s->hw.modes));
+ blobmsg_add_u8(&b, "vht_supported", vht_supported(wpa_s->hw.modes));
+ ubus_send_reply(ctx, req, b.head);
+
+ return 0;
+}
+
+static int
+wpas_bss_reload(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *req, const char *method,
+ struct blob_attr *msg)
+{
+ struct wpa_supplicant *wpa_s = get_wpas_from_object(obj);
+
+ if (wpa_supplicant_reload_configuration(wpa_s))
+ return UBUS_STATUS_UNKNOWN_ERROR;
+ else
+ return 0;
+}
+
+#ifdef CONFIG_WPS
+enum {
+ WPS_START_MULTI_AP,
+ __WPS_START_MAX
+};
+
+static const struct blobmsg_policy wps_start_policy[] = {
+ [WPS_START_MULTI_AP] = { "multi_ap", BLOBMSG_TYPE_BOOL },
+};
+
+static int
+wpas_bss_wps_start(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *req, const char *method,
+ struct blob_attr *msg)
+{
+ int rc;
+ struct wpa_supplicant *wpa_s = get_wpas_from_object(obj);
+ struct blob_attr *tb[__WPS_START_MAX], *cur;
+ int multi_ap = 0;
+
+ blobmsg_parse(wps_start_policy, __WPS_START_MAX, tb, blobmsg_data(msg), blobmsg_data_len(msg));
+
+ if (tb[WPS_START_MULTI_AP])
+ multi_ap = blobmsg_get_bool(tb[WPS_START_MULTI_AP]);
+
+ rc = wpas_wps_start_pbc(wpa_s, NULL, 0, multi_ap);
+
+ if (rc != 0)
+ return UBUS_STATUS_NOT_SUPPORTED;
+
+ return 0;
+}
+
+static int
+wpas_bss_wps_cancel(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *req, const char *method,
+ struct blob_attr *msg)
+{
+ int rc;
+ struct wpa_supplicant *wpa_s = get_wpas_from_object(obj);
+
+ rc = wpas_wps_cancel(wpa_s);
+
+ if (rc != 0)
+ return UBUS_STATUS_NOT_SUPPORTED;
+
+ return 0;
+}
+#endif
+
+static const struct ubus_method bss_methods[] = {
+ UBUS_METHOD_NOARG("reload", wpas_bss_reload),
+ UBUS_METHOD_NOARG("get_features", wpas_bss_get_features),
+#ifdef CONFIG_WPS
+ UBUS_METHOD_NOARG("wps_start", wpas_bss_wps_start),
+ UBUS_METHOD_NOARG("wps_cancel", wpas_bss_wps_cancel),
+#endif
+};
+
+static struct ubus_object_type bss_object_type =
+ UBUS_OBJECT_TYPE("wpas_bss", bss_methods);
+
+void wpas_ubus_add_bss(struct wpa_supplicant *wpa_s)
+{
+ struct ubus_object *obj = &wpa_s->ubus.obj;
+ char *name;
+ int ret;
+
+ if (!wpas_ubus_init())
+ return;
+
+ if (asprintf(&name, "wpa_supplicant.%s", wpa_s->ifname) < 0)
+ return;
+
+ obj->name = name;
+ obj->type = &bss_object_type;
+ obj->methods = bss_object_type.methods;
+ obj->n_methods = bss_object_type.n_methods;
+ ret = ubus_add_object(ctx, obj);
+ wpas_ubus_ref_inc();
+}
+
+void wpas_ubus_free_bss(struct wpa_supplicant *wpa_s)
+{
+ struct ubus_object *obj = &wpa_s->ubus.obj;
+ char *name = (char *) obj->name;
+
+ if (!ctx)
+ return;
+
+ if (obj->id) {
+ ubus_remove_object(ctx, obj);
+ wpas_ubus_ref_dec();
+ }
+
+ free(name);
+}
+
+#ifdef CONFIG_WPS
+void wpas_ubus_notify(struct wpa_supplicant *wpa_s, const struct wps_credential *cred)
+{
+ u16 auth_type;
+ char *ifname, *encryption, *ssid, *key;
+ size_t ifname_len;
+
+ if (!cred)
+ return;
+
+ auth_type = cred->auth_type;
+
+ if (auth_type == (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK))
+ auth_type = WPS_AUTH_WPA2PSK;
+
+ if (auth_type != WPS_AUTH_OPEN &&
+ auth_type != WPS_AUTH_WPAPSK &&
+ auth_type != WPS_AUTH_WPA2PSK) {
+ wpa_printf(MSG_DEBUG, "WPS: Ignored credentials for "
+ "unsupported authentication type 0x%x",
+ auth_type);
+ return;
+ }
+
+ if (auth_type == WPS_AUTH_WPAPSK || auth_type == WPS_AUTH_WPA2PSK) {
+ if (cred->key_len < 8 || cred->key_len > 2 * PMK_LEN) {
+ wpa_printf(MSG_ERROR, "WPS: Reject PSK credential with "
+ "invalid Network Key length %lu",
+ (unsigned long) cred->key_len);
+ return;
+ }
+ }
+
+ blob_buf_init(&b, 0);
+
+ ifname_len = strlen(wpa_s->ifname);
+ ifname = blobmsg_alloc_string_buffer(&b, "ifname", ifname_len + 1);
+ memcpy(ifname, wpa_s->ifname, ifname_len + 1);
+ ifname[ifname_len] = '\0';
+ blobmsg_add_string_buffer(&b);
+
+ switch (auth_type) {
+ case WPS_AUTH_WPA2PSK:
+ encryption = "psk2";
+ break;
+ case WPS_AUTH_WPAPSK:
+ encryption = "psk";
+ break;
+ default:
+ encryption = "none";
+ break;
+ }
+
+ blobmsg_add_string(&b, "encryption", encryption);
+
+ ssid = blobmsg_alloc_string_buffer(&b, "ssid", cred->ssid_len + 1);
+ memcpy(ssid, cred->ssid, cred->ssid_len);
+ ssid[cred->ssid_len] = '\0';
+ blobmsg_add_string_buffer(&b);
+
+ if (cred->key_len > 0) {
+ key = blobmsg_alloc_string_buffer(&b, "key", cred->key_len + 1);
+ memcpy(key, cred->key, cred->key_len);
+ key[cred->key_len] = '\0';
+ blobmsg_add_string_buffer(&b);
+ }
+
+// ubus_notify(ctx, &wpa_s->ubus.obj, "wps_credentials", b.head, -1);
+ ubus_send_event(ctx, "wps_credentials", b.head);
+}
+#endif /* CONFIG_WPS */
diff --git a/recipes-wifi/wpa-supplicant/files/src-2.10.3/wpa_supplicant/ubus.h b/recipes-wifi/wpa-supplicant/files/src-2.10.3/wpa_supplicant/ubus.h
new file mode 100644
index 0000000..f6681cb
--- /dev/null
+++ b/recipes-wifi/wpa-supplicant/files/src-2.10.3/wpa_supplicant/ubus.h
@@ -0,0 +1,55 @@
+/*
+ * wpa_supplicant / ubus support
+ * Copyright (c) 2018, Daniel Golle <daniel@makrotopia.org>
+ * Copyright (c) 2013, Felix Fietkau <nbd@nbd.name>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+#ifndef __WPAS_UBUS_H
+#define __WPAS_UBUS_H
+
+struct wpa_supplicant;
+struct wpa_global;
+
+#include "wps_supplicant.h"
+
+#ifdef UBUS_SUPPORT
+#include <libubus.h>
+
+struct wpas_ubus_bss {
+ struct ubus_object obj;
+};
+
+void wpas_ubus_add_bss(struct wpa_supplicant *wpa_s);
+void wpas_ubus_free_bss(struct wpa_supplicant *wpa_s);
+
+#ifdef CONFIG_WPS
+void wpas_ubus_notify(struct wpa_supplicant *wpa_s, const struct wps_credential *cred);
+#endif
+
+#else
+struct wpas_ubus_bss {};
+
+static inline void wpas_ubus_add_bss(struct wpa_supplicant *wpa_s)
+{
+}
+
+static inline void wpas_ubus_free_bss(struct wpa_supplicant *wpa_s)
+{
+}
+
+static inline void wpas_ubus_notify(struct wpa_supplicant *wpa_s, struct wps_credential *cred)
+{
+}
+
+static inline void wpas_ubus_add(struct wpa_global *global)
+{
+}
+
+static inline void wpas_ubus_free(struct wpa_global *global)
+{
+}
+#endif
+
+#endif
diff --git a/recipes-wifi/wpa-supplicant/files/src-2.10.3/wpa_supplicant/ucode.c b/recipes-wifi/wpa-supplicant/files/src-2.10.3/wpa_supplicant/ucode.c
new file mode 100644
index 0000000..eec3980
--- /dev/null
+++ b/recipes-wifi/wpa-supplicant/files/src-2.10.3/wpa_supplicant/ucode.c
@@ -0,0 +1,177 @@
+#include "utils/includes.h"
+#include "utils/common.h"
+#include "utils/ucode.h"
+#include "wpa_supplicant_i.h"
+#include "wps_supplicant.h"
+#include "ucode.h"
+
+static struct wpa_global *wpa_global;
+static uc_resource_type_t *global_type, *iface_type;
+static uc_value_t *global, *iface_registry;
+static uc_vm_t *vm;
+
+static uc_value_t *
+wpas_ucode_iface_get_uval(struct wpa_supplicant *wpa_s)
+{
+ uc_value_t *val;
+
+ if (wpa_s->ucode.idx)
+ return wpa_ucode_registry_get(iface_registry, wpa_s->ucode.idx);
+
+ val = uc_resource_new(iface_type, wpa_s);
+ wpa_ucode_registry_add(iface_registry, val, &wpa_s->ucode.idx);
+
+ return val;
+}
+
+static void
+wpas_ucode_update_interfaces(void)
+{
+ uc_value_t *ifs = ucv_object_new(vm);
+ struct wpa_supplicant *wpa_s;
+ int i;
+
+ for (wpa_s = wpa_global->ifaces; wpa_s; wpa_s = wpa_s->next)
+ ucv_object_add(ifs, wpa_s->ifname, ucv_get(wpas_ucode_iface_get_uval(wpa_s)));
+
+ ucv_object_add(ucv_prototype_get(global), "interfaces", ucv_get(ifs));
+ ucv_gc(vm);
+}
+
+void wpas_ucode_add_bss(struct wpa_supplicant *wpa_s)
+{
+ uc_value_t *val;
+
+ if (wpa_ucode_call_prepare("iface_add"))
+ return;
+
+ uc_value_push(ucv_get(ucv_string_new(wpa_s->ifname)));
+ uc_value_push(ucv_get(wpas_ucode_iface_get_uval(wpa_s)));
+ ucv_put(wpa_ucode_call(2));
+ ucv_gc(vm);
+}
+
+void wpas_ucode_free_bss(struct wpa_supplicant *wpa_s)
+{
+ uc_value_t *val;
+
+ val = wpa_ucode_registry_remove(iface_registry, wpa_s->ucode.idx);
+ if (!val)
+ return;
+
+ wpa_s->ucode.idx = 0;
+ if (wpa_ucode_call_prepare("iface_remove"))
+ return;
+
+ uc_value_push(ucv_get(ucv_string_new(wpa_s->ifname)));
+ uc_value_push(ucv_get(val));
+ ucv_put(wpa_ucode_call(2));
+ ucv_gc(vm);
+}
+
+static const char *obj_stringval(uc_value_t *obj, const char *name)
+{
+ uc_value_t *val = ucv_object_get(obj, name, NULL);
+
+ return ucv_string_get(val);
+}
+
+static uc_value_t *
+uc_wpas_add_iface(uc_vm_t *vm, size_t nargs)
+{
+ uc_value_t *info = uc_fn_arg(0);
+ uc_value_t *ifname = ucv_object_get(info, "iface", NULL);
+ uc_value_t *bridge = ucv_object_get(info, "bridge", NULL);
+ uc_value_t *config = ucv_object_get(info, "config", NULL);
+ uc_value_t *ctrl = ucv_object_get(info, "ctrl", NULL);
+ uc_value_t *hapd_ctrl = ucv_object_get(info, "hostapd_ctrl", NULL);
+ struct wpa_interface iface;
+ int ret = -1;
+
+ if (ucv_type(info) != UC_OBJECT)
+ goto out;
+
+ iface = (struct wpa_interface){
+ .driver = "nl80211",
+ .ifname = ucv_string_get(ifname),
+ .bridge_ifname = ucv_string_get(bridge),
+ .confname = ucv_string_get(config),
+ .ctrl_interface = ucv_string_get(ctrl),
+ .hostapd_ctrl = ucv_string_get(hapd_ctrl),
+ };
+
+ if (!iface.ifname || !iface.confname)
+ goto out;
+
+ ret = wpa_supplicant_add_iface(wpa_global, &iface, 0) ? 0 : -1;
+ wpas_ucode_update_interfaces();
+
+out:
+ return ucv_int64_new(ret);
+}
+
+static uc_value_t *
+uc_wpas_remove_iface(uc_vm_t *vm, size_t nargs)
+{
+ struct wpa_supplicant *wpa_s = NULL;
+ uc_value_t *ifname_arg = uc_fn_arg(0);
+ const char *ifname = ucv_string_get(ifname_arg);
+ int ret = -1;
+
+ if (!ifname)
+ goto out;
+
+ for (wpa_s = wpa_global->ifaces; wpa_s; wpa_s = wpa_s->next)
+ if (!strcmp(wpa_s->ifname, ifname))
+ break;
+
+ if (!wpa_s)
+ goto out;
+
+ ret = wpa_supplicant_remove_iface(wpa_global, wpa_s, 0);
+ wpas_ucode_update_interfaces();
+
+out:
+ return ucv_int64_new(ret);
+}
+
+int wpas_ucode_init(struct wpa_global *gl)
+{
+ static const uc_function_list_t global_fns[] = {
+ { "printf", uc_wpa_printf },
+ { "getpid", uc_wpa_getpid },
+ { "add_iface", uc_wpas_add_iface },
+ { "remove_iface", uc_wpas_remove_iface },
+ };
+ static const uc_function_list_t iface_fns[] = {
+ };
+ uc_value_t *data, *proto;
+
+ wpa_global = gl;
+ vm = wpa_ucode_create_vm();
+
+ global_type = uc_type_declare(vm, "wpas.global", global_fns, NULL);
+ iface_type = uc_type_declare(vm, "hostapd.iface", iface_fns, NULL);
+
+ iface_registry = ucv_array_new(vm);
+ uc_vm_registry_set(vm, "hostap.iface_registry", iface_registry);
+
+ global = wpa_ucode_global_init("wpas", global_type);
+
+ if (wpa_ucode_run(HOSTAPD_UC_PATH "wpa_supplicant.uc"))
+ goto free_vm;
+
+ ucv_gc(vm);
+ return 0;
+
+free_vm:
+ wpa_ucode_free_vm();
+ return -1;
+}
+
+void wpas_ucode_free(void)
+{
+ if (wpa_ucode_call_prepare("shutdown") == 0)
+ ucv_put(wpa_ucode_call(0));
+ wpa_ucode_free_vm();
+}
diff --git a/recipes-wifi/wpa-supplicant/files/src-2.10.3/wpa_supplicant/ucode.h b/recipes-wifi/wpa-supplicant/files/src-2.10.3/wpa_supplicant/ucode.h
new file mode 100644
index 0000000..fcd2313
--- /dev/null
+++ b/recipes-wifi/wpa-supplicant/files/src-2.10.3/wpa_supplicant/ucode.h
@@ -0,0 +1,38 @@
+#ifndef __WPAS_UCODE_H
+#define __WPAS_UCODE_H
+
+#include "utils/ucode.h"
+
+struct wpa_global;
+struct wpa_supplicant;
+
+struct wpas_ucode_bss {
+#ifdef UCODE_SUPPORT
+ unsigned int idx;
+#endif
+};
+
+#ifdef UCODE_SUPPORT
+int wpas_ucode_init(struct wpa_global *gl);
+void wpas_ucode_free(void);
+void wpas_ucode_add_bss(struct wpa_supplicant *wpa_s);
+void wpas_ucode_free_bss(struct wpa_supplicant *wpa_s);
+#else
+static inline int wpas_ucode_init(struct wpa_global *gl)
+{
+ return -EINVAL;
+}
+static inline void wpas_ucode_free(void)
+{
+}
+static inline void wpas_ucode_add_bss(struct wpa_supplicant *wpa_s)
+{
+}
+
+static inline void wpas_ucode_free_bss(struct wpa_supplicant *wpa_s)
+{
+}
+
+#endif
+
+#endif
diff --git a/recipes-wifi/wpa-supplicant/files/wpa_supplicant.uc b/recipes-wifi/wpa-supplicant/files/wpa_supplicant.uc
new file mode 100644
index 0000000..22cb130
--- /dev/null
+++ b/recipes-wifi/wpa-supplicant/files/wpa_supplicant.uc
@@ -0,0 +1,161 @@
+let libubus = require("ubus");
+import { open, readfile } from "fs";
+import { wdev_create, wdev_remove, is_equal, vlist_new } from "common";
+
+let ubus = libubus.connect();
+
+wpas.data.config = {};
+
+function iface_stop(iface)
+{
+ let ifname = iface.config.iface;
+
+ wpas.remove_iface(ifname);
+ wdev_remove(ifname);
+ iface.running = false;
+}
+
+function iface_start(phy, iface)
+{
+ if (iface.running)
+ return;
+
+ let ifname = iface.config.iface;
+
+ wdev_remove(ifname);
+ let ret = wdev_create(phy, ifname, iface.config);
+ if (ret)
+ wpas.printf(`Failed to create device ${ifname}: ${ret}`);
+ wpas.add_iface(iface.config);
+ iface.running = true;
+}
+
+function iface_cb(new_if, old_if)
+{
+ if (old_if && new_if && is_equal(old_if.config, new_if.config)) {
+ new_if.running = old_if.running;
+ return;
+ }
+
+ if (old_if && old_if.running)
+ iface_stop(old_if);
+}
+
+function prepare_config(config)
+{
+ config.config_data = readfile(config.config);
+
+ return { config: config };
+}
+
+function set_config(phy_name, config_list)
+{
+ let phy = wpas.data.config[phy_name];
+
+ if (!phy) {
+ phy = vlist_new(iface_cb, false);
+ wpas.data.config[phy_name] = phy;
+ }
+
+ let values = [];
+ for (let config in config_list)
+ push(values, [ config.iface, prepare_config(config) ]);
+
+ phy.update(values);
+}
+
+function start_pending(phy_name)
+{
+ let phy = wpas.data.config[phy_name];
+
+ for (let ifname in phy.data)
+ iface_start(phy_name, phy.data[ifname]);
+}
+
+let main_obj = {
+ config_set: {
+ args: {
+ phy: "",
+ config: [],
+ defer: true,
+ },
+ call: function(req) {
+ if (!req.args.phy)
+ return libubus.STATUS_INVALID_ARGUMENT;
+
+ try {
+ if (req.args.config)
+ set_config(req.args.phy, req.args.config);
+
+ if (!req.args.defer)
+ start_pending(req.args.phy);
+ } catch (e) {
+ wpas.printf(`Error loading config: ${e}\n${e.stacktrace[0].context}`);
+ return libubus.STATUS_INVALID_ARGUMENT;
+ }
+
+ return {
+ pid: wpas.getpid()
+ };
+ }
+ },
+ config_add: {
+ args: {
+ driver: "",
+ iface: "",
+ bridge: "",
+ hostapd_ctrl: "",
+ ctrl: "",
+ config: "",
+ },
+ call: function(req) {
+ if (!req.args.iface || !req.args.config)
+ return libubus.STATUS_INVALID_ARGUMENT;
+
+ if (wpas.add_iface(req.args) < 0)
+ return libubus.STATUS_INVALID_ARGUMENT;
+
+ return {
+ pid: wpas.getpid()
+ };
+ }
+ },
+ config_remove: {
+ args: {
+ iface: ""
+ },
+ call: function(req) {
+ if (!req.args.iface)
+ return libubus.STATUS_INVALID_ARGUMENT;
+
+ wpas.remove_iface(req.args.iface);
+ return 0;
+ }
+ },
+};
+
+wpas.data.ubus = ubus;
+wpas.data.obj = ubus.publish("wpa_supplicant", main_obj);
+
+function iface_event(type, name, data) {
+ let ubus = wpas.data.ubus;
+
+ data ??= {};
+ data.name = name;
+ wpas.data.obj.notify(`iface.${type}`, data, null, null, null, -1);
+ ubus.call("service", "event", { type: `wpa_supplicant.${name}.${type}`, data: {} });
+}
+
+return {
+ shutdown: function() {
+ for (let phy in wpas.data.config)
+ set_config(phy, []);
+ wpas.ubus.disconnect();
+ },
+ iface_add: function(name, obj) {
+ iface_event("add", name);
+ },
+ iface_remove: function(name, obj) {
+ iface_event("remove", name);
+ }
+};
diff --git a/recipes-wifi/wpa-supplicant/wpa-supplicant_2.10.3.bb b/recipes-wifi/wpa-supplicant/wpa-supplicant_2.10.3.bb
index 0f446aa..f3bb828 100644
--- a/recipes-wifi/wpa-supplicant/wpa-supplicant_2.10.3.bb
+++ b/recipes-wifi/wpa-supplicant/wpa-supplicant_2.10.3.bb
@@ -6,7 +6,7 @@
LICENSE = "BSD-3-Clause"
LIC_FILES_CHKSUM = "file://hostapd/README;md5=c905478466c90f1cefc0df987c40e172"
-DEPENDS = "dbus libnl ubus"
+DEPENDS = "dbus libnl ubus ucode"
FILESEXTRAPATHS_prepend := "${THISDIR}/files:"
FILESEXTRAPATHS_prepend := "${THISDIR}/files/patches-${PV}:"
@@ -17,8 +17,9 @@
file://wpa_supplicant.conf-sane \
file://99_wpa_supplicant \
file://wpa_supplicant-full.config \
- file://src \
- file://001-rdkb-remove-ubus-support.patch;apply=no \
+ file://wpa_supplicant.uc \
+ file://src-${PV} \
+ file://002-rdkb-add-ucode-support.patch;apply=no \
"
require files/patches-${PV}/patches.inc
@@ -38,13 +39,13 @@
}
do_copy_openwrt_src() {
- cp -Rfp ${WORKDIR}/src/* ${S}/
+ cp -Rfp ${WORKDIR}/src-${PV}/* ${S}/
}
do_filogic_patches() {
cd ${S}
if [ ! -e patch_applied ]; then
- patch -p1 < ${WORKDIR}/001-rdkb-remove-ubus-support.patch
+ patch -p1 < ${WORKDIR}/002-rdkb-add-ucode-support.patch
touch patch_applied
fi
}
@@ -83,8 +84,10 @@
echo "CONFIG_AP=y" >> wpa_supplicant/.config
echo "CONFIG_MESH=y" >> wpa_supplicant/.config
echo "CONFIG_IEEE80211BE=y" >> wpa_supplicant/.config
+ echo "CONFIG_IEEE80211AC=y" >> wpa_supplicant/.config
echo "CONFIG_HE_OVERRIDES=y" >> wpa_supplicant/.config
echo "CONFIG_EHT_OVERRIDES=y" >> wpa_supplicant/.config
+ echo "CONFIG_UCODE=y" >> wpa_supplicant/.config
}
do_compile () {
@@ -125,6 +128,9 @@
install -d ${D}${libdir}
install -m 0644 ${S}/wpa_supplicant/libwpa_client.so ${D}${libdir}
+
+ install -d ${D}${datadir}/hostap
+ install -m 0755 ${WORKDIR}/wpa_supplicant.uc ${D}${datadir}/hostap
}
pkg_postinst:${PN} () {
@@ -144,7 +150,7 @@
FILES:${PN}-passphrase = "${sbindir}/wpa_passphrase"
FILES:${PN}-cli = "${sbindir}/wpa_cli"
-FILES:${PN} += "${datadir}/dbus-1/system-services/* ${systemd_system_unitdir}/*"
+FILES:${PN} += "${datadir}/dbus-1/system-services/* ${systemd_system_unitdir}/* ${datadir}/hostap/*"
FILES:${PN}-dbg += "${sbindir}/.debug ${libdir}/.debug"
CONFFILES:${PN} += "${sysconfdir}/wpa_supplicant.conf"