diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h index 53033501e..7cea317a0 100644 --- a/src/ap/ap_drv_ops.h +++ b/src/ap/ap_drv_ops.h @@ -300,6 +300,16 @@ static inline int hostapd_drv_br_delete_ip_neigh(struct hostapd_data *hapd, return hapd->driver->br_delete_ip_neigh(hapd->drv_priv, ipaddr); } +static inline int hostapd_drv_br_port_set_attr(struct hostapd_data *hapd, + enum drv_br_port_attr attr, + unsigned int val) +{ + if (hapd->driver == NULL || hapd->drv_priv == NULL || + hapd->driver->br_port_set_attr == NULL) + return -1; + return hapd->driver->br_port_set_attr(hapd->drv_priv, attr, val); +} + static inline int hostapd_drv_vendor_cmd(struct hostapd_data *hapd, int vendor_id, int subcmd, const u8 *data, size_t data_len, diff --git a/src/drivers/driver.h b/src/drivers/driver.h index 78db6a11e..4c9bbc8a8 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -1373,6 +1373,11 @@ struct macsec_init_params { }; #endif /* CONFIG_MACSEC */ +enum drv_br_port_attr { + DRV_BR_PORT_ATTR_PROXYARP, + DRV_BR_PORT_ATTR_HAIRPIN_MODE, +}; + /** * struct wpa_driver_ops - Driver interface API definition @@ -2619,6 +2624,15 @@ struct wpa_driver_ops { */ int (*br_delete_ip_neigh)(void *priv, be32 ipaddr); + /** + * br_port_set_attr - Set a bridge port attribute + * @attr: Bridge port attribute to set + * @val: Value to be set + * Returns: 0 on success, negative (<0) on failure + */ + int (*br_port_set_attr)(void *priv, enum drv_br_port_attr attr, + unsigned int val); + /** * set_wowlan - Set wake-on-wireless triggers * @priv: Private driver interface data diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index 4ffb313c3..d40a44aeb 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -12,6 +12,7 @@ #include "includes.h" #include +#include #include #include #include @@ -8974,6 +8975,66 @@ errout: } +static int linux_write_system_file(const char *path, unsigned int val) +{ + char buf[50]; + int fd, len; + + len = os_snprintf(buf, sizeof(buf), "%u\n", val); + if (len < 0) + return -1; + + fd = open(path, O_WRONLY); + if (fd < 0) + return -1; + + if (write(fd, buf, len) < 0) { + wpa_printf(MSG_DEBUG, + "nl80211: Failed to write Linux system file: %s with the value of %d", + path, val); + close(fd); + return -1; + } + close(fd); + + return 0; +} + + +static const char * drv_br_port_attr_str(enum drv_br_port_attr attr) +{ + switch (attr) { + case DRV_BR_PORT_ATTR_PROXYARP: + return "proxyarp"; + case DRV_BR_PORT_ATTR_HAIRPIN_MODE: + return "hairpin_mode"; + } + + return NULL; +} + + +static int wpa_driver_br_port_set_attr(void *priv, enum drv_br_port_attr attr, + unsigned int val) +{ + struct i802_bss *bss = priv; + char path[128]; + const char *attr_txt; + + attr_txt = drv_br_port_attr_str(attr); + if (attr_txt == NULL) + return -EINVAL; + + os_snprintf(path, sizeof(path), "/sys/class/net/%s/brport/%s", + bss->ifname, attr_txt); + + if (linux_write_system_file(path, val)) + return -1; + + return 0; +} + + const struct wpa_driver_ops wpa_driver_nl80211_ops = { .name = "nl80211", .desc = "Linux nl80211/cfg80211", @@ -9074,4 +9135,5 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = { #endif /* CONFIG_MESH */ .br_add_ip_neigh = wpa_driver_br_add_ip_neigh, .br_delete_ip_neigh = wpa_driver_br_delete_ip_neigh, + .br_port_set_attr = wpa_driver_br_port_set_attr, };