e4015440af
Skip the x_snoop_deinit() operations if hostapd did not actually configure the parameters in the first place. While clearing these specific parameters is unlikely to change how they were set outside the scope of hostapd, it is better to leave them as-is to avoid surprises if hostapd was not configured to use ProxyARP. Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
136 lines
3.3 KiB
C
136 lines
3.3 KiB
C
/*
|
|
* Generic Snooping for Proxy ARP
|
|
* Copyright (c) 2014, Qualcomm Atheros, Inc.
|
|
*
|
|
* 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 "hostapd.h"
|
|
#include "sta_info.h"
|
|
#include "ap_drv_ops.h"
|
|
#include "x_snoop.h"
|
|
|
|
|
|
int x_snoop_init(struct hostapd_data *hapd)
|
|
{
|
|
struct hostapd_bss_config *conf = hapd->conf;
|
|
|
|
if (!conf->isolate) {
|
|
wpa_printf(MSG_DEBUG,
|
|
"x_snoop: ap_isolate must be enabled for x_snoop");
|
|
return -1;
|
|
}
|
|
|
|
if (conf->bridge[0] == '\0') {
|
|
wpa_printf(MSG_DEBUG,
|
|
"x_snoop: Bridge must be configured for x_snoop");
|
|
return -1;
|
|
}
|
|
|
|
hapd->x_snoop_initialized = true;
|
|
|
|
if (hostapd_drv_br_port_set_attr(hapd, DRV_BR_PORT_ATTR_HAIRPIN_MODE,
|
|
1)) {
|
|
wpa_printf(MSG_DEBUG,
|
|
"x_snoop: Failed to enable hairpin_mode on the bridge port");
|
|
return -1;
|
|
}
|
|
|
|
if (hostapd_drv_br_port_set_attr(hapd, DRV_BR_PORT_ATTR_PROXYARP, 1)) {
|
|
wpa_printf(MSG_DEBUG,
|
|
"x_snoop: Failed to enable proxyarp on the bridge port");
|
|
return -1;
|
|
}
|
|
|
|
if (hostapd_drv_br_set_net_param(hapd, DRV_BR_NET_PARAM_GARP_ACCEPT,
|
|
1)) {
|
|
wpa_printf(MSG_DEBUG,
|
|
"x_snoop: Failed to enable accepting gratuitous ARP on the bridge");
|
|
return -1;
|
|
}
|
|
|
|
#ifdef CONFIG_IPV6
|
|
if (hostapd_drv_br_set_net_param(hapd, DRV_BR_MULTICAST_SNOOPING, 1)) {
|
|
wpa_printf(MSG_DEBUG,
|
|
"x_snoop: Failed to enable multicast snooping on the bridge");
|
|
return -1;
|
|
}
|
|
#endif /* CONFIG_IPV6 */
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
struct l2_packet_data *
|
|
x_snoop_get_l2_packet(struct hostapd_data *hapd,
|
|
void (*handler)(void *ctx, const u8 *src_addr,
|
|
const u8 *buf, size_t len),
|
|
enum l2_packet_filter_type type)
|
|
{
|
|
struct hostapd_bss_config *conf = hapd->conf;
|
|
struct l2_packet_data *l2;
|
|
|
|
l2 = l2_packet_init(conf->bridge, NULL, ETH_P_ALL, handler, hapd, 1);
|
|
if (l2 == NULL) {
|
|
wpa_printf(MSG_DEBUG,
|
|
"x_snoop: Failed to initialize L2 packet processing %s",
|
|
strerror(errno));
|
|
return NULL;
|
|
}
|
|
|
|
if (l2_packet_set_packet_filter(l2, type)) {
|
|
wpa_printf(MSG_DEBUG,
|
|
"x_snoop: Failed to set L2 packet filter for type: %d",
|
|
type);
|
|
l2_packet_deinit(l2);
|
|
return NULL;
|
|
}
|
|
|
|
return l2;
|
|
}
|
|
|
|
|
|
void x_snoop_mcast_to_ucast_convert_send(struct hostapd_data *hapd,
|
|
struct sta_info *sta, u8 *buf,
|
|
size_t len)
|
|
{
|
|
int res;
|
|
u8 addr[ETH_ALEN];
|
|
u8 *dst_addr = buf;
|
|
|
|
if (!(dst_addr[0] & 0x01))
|
|
return;
|
|
|
|
wpa_printf(MSG_EXCESSIVE, "x_snoop: Multicast-to-unicast conversion "
|
|
MACSTR " -> " MACSTR " (len %u)",
|
|
MAC2STR(dst_addr), MAC2STR(sta->addr), (unsigned int) len);
|
|
|
|
/* save the multicast destination address for restoring it later */
|
|
os_memcpy(addr, buf, ETH_ALEN);
|
|
|
|
os_memcpy(buf, sta->addr, ETH_ALEN);
|
|
res = l2_packet_send(hapd->sock_dhcp, NULL, 0, buf, len);
|
|
if (res < 0) {
|
|
wpa_printf(MSG_DEBUG,
|
|
"x_snoop: Failed to send mcast to ucast converted packet to "
|
|
MACSTR, MAC2STR(sta->addr));
|
|
}
|
|
|
|
/* restore the multicast destination address */
|
|
os_memcpy(buf, addr, ETH_ALEN);
|
|
}
|
|
|
|
|
|
void x_snoop_deinit(struct hostapd_data *hapd)
|
|
{
|
|
if (!hapd->x_snoop_initialized)
|
|
return;
|
|
hostapd_drv_br_set_net_param(hapd, DRV_BR_NET_PARAM_GARP_ACCEPT, 0);
|
|
hostapd_drv_br_port_set_attr(hapd, DRV_BR_PORT_ATTR_PROXYARP, 0);
|
|
hostapd_drv_br_port_set_attr(hapd, DRV_BR_PORT_ATTR_HAIRPIN_MODE, 0);
|
|
hapd->x_snoop_initialized = false;
|
|
}
|