15b9c547cSRui Paulo /*
25b9c547cSRui Paulo * Generic Snooping for Proxy ARP
35b9c547cSRui Paulo * Copyright (c) 2014, Qualcomm Atheros, Inc.
45b9c547cSRui Paulo *
55b9c547cSRui Paulo * This software may be distributed under the terms of the BSD license.
65b9c547cSRui Paulo * See README for more details.
75b9c547cSRui Paulo */
85b9c547cSRui Paulo
95b9c547cSRui Paulo #include "utils/includes.h"
105b9c547cSRui Paulo
115b9c547cSRui Paulo #include "utils/common.h"
125b9c547cSRui Paulo #include "hostapd.h"
135b9c547cSRui Paulo #include "sta_info.h"
145b9c547cSRui Paulo #include "ap_drv_ops.h"
155b9c547cSRui Paulo #include "x_snoop.h"
165b9c547cSRui Paulo
175b9c547cSRui Paulo
x_snoop_init(struct hostapd_data * hapd)185b9c547cSRui Paulo int x_snoop_init(struct hostapd_data *hapd)
195b9c547cSRui Paulo {
205b9c547cSRui Paulo struct hostapd_bss_config *conf = hapd->conf;
215b9c547cSRui Paulo
225b9c547cSRui Paulo if (!conf->isolate) {
235b9c547cSRui Paulo wpa_printf(MSG_DEBUG,
245b9c547cSRui Paulo "x_snoop: ap_isolate must be enabled for x_snoop");
255b9c547cSRui Paulo return -1;
265b9c547cSRui Paulo }
275b9c547cSRui Paulo
285b9c547cSRui Paulo if (conf->bridge[0] == '\0') {
295b9c547cSRui Paulo wpa_printf(MSG_DEBUG,
305b9c547cSRui Paulo "x_snoop: Bridge must be configured for x_snoop");
315b9c547cSRui Paulo return -1;
325b9c547cSRui Paulo }
335b9c547cSRui Paulo
34*a90b9d01SCy Schubert hapd->x_snoop_initialized = true;
35*a90b9d01SCy Schubert
365b9c547cSRui Paulo if (hostapd_drv_br_port_set_attr(hapd, DRV_BR_PORT_ATTR_HAIRPIN_MODE,
375b9c547cSRui Paulo 1)) {
385b9c547cSRui Paulo wpa_printf(MSG_DEBUG,
395b9c547cSRui Paulo "x_snoop: Failed to enable hairpin_mode on the bridge port");
405b9c547cSRui Paulo return -1;
415b9c547cSRui Paulo }
425b9c547cSRui Paulo
435b9c547cSRui Paulo if (hostapd_drv_br_port_set_attr(hapd, DRV_BR_PORT_ATTR_PROXYARP, 1)) {
445b9c547cSRui Paulo wpa_printf(MSG_DEBUG,
455b9c547cSRui Paulo "x_snoop: Failed to enable proxyarp on the bridge port");
465b9c547cSRui Paulo return -1;
475b9c547cSRui Paulo }
485b9c547cSRui Paulo
495b9c547cSRui Paulo if (hostapd_drv_br_set_net_param(hapd, DRV_BR_NET_PARAM_GARP_ACCEPT,
505b9c547cSRui Paulo 1)) {
515b9c547cSRui Paulo wpa_printf(MSG_DEBUG,
525b9c547cSRui Paulo "x_snoop: Failed to enable accepting gratuitous ARP on the bridge");
535b9c547cSRui Paulo return -1;
545b9c547cSRui Paulo }
555b9c547cSRui Paulo
56325151a3SRui Paulo #ifdef CONFIG_IPV6
57325151a3SRui Paulo if (hostapd_drv_br_set_net_param(hapd, DRV_BR_MULTICAST_SNOOPING, 1)) {
58325151a3SRui Paulo wpa_printf(MSG_DEBUG,
59325151a3SRui Paulo "x_snoop: Failed to enable multicast snooping on the bridge");
60325151a3SRui Paulo return -1;
61325151a3SRui Paulo }
62325151a3SRui Paulo #endif /* CONFIG_IPV6 */
63325151a3SRui Paulo
645b9c547cSRui Paulo return 0;
655b9c547cSRui Paulo }
665b9c547cSRui Paulo
675b9c547cSRui Paulo
685b9c547cSRui Paulo 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)695b9c547cSRui Paulo x_snoop_get_l2_packet(struct hostapd_data *hapd,
705b9c547cSRui Paulo void (*handler)(void *ctx, const u8 *src_addr,
715b9c547cSRui Paulo const u8 *buf, size_t len),
725b9c547cSRui Paulo enum l2_packet_filter_type type)
735b9c547cSRui Paulo {
745b9c547cSRui Paulo struct hostapd_bss_config *conf = hapd->conf;
755b9c547cSRui Paulo struct l2_packet_data *l2;
765b9c547cSRui Paulo
775b9c547cSRui Paulo l2 = l2_packet_init(conf->bridge, NULL, ETH_P_ALL, handler, hapd, 1);
785b9c547cSRui Paulo if (l2 == NULL) {
795b9c547cSRui Paulo wpa_printf(MSG_DEBUG,
805b9c547cSRui Paulo "x_snoop: Failed to initialize L2 packet processing %s",
815b9c547cSRui Paulo strerror(errno));
825b9c547cSRui Paulo return NULL;
835b9c547cSRui Paulo }
845b9c547cSRui Paulo
855b9c547cSRui Paulo if (l2_packet_set_packet_filter(l2, type)) {
865b9c547cSRui Paulo wpa_printf(MSG_DEBUG,
875b9c547cSRui Paulo "x_snoop: Failed to set L2 packet filter for type: %d",
885b9c547cSRui Paulo type);
895b9c547cSRui Paulo l2_packet_deinit(l2);
905b9c547cSRui Paulo return NULL;
915b9c547cSRui Paulo }
925b9c547cSRui Paulo
935b9c547cSRui Paulo return l2;
945b9c547cSRui Paulo }
955b9c547cSRui Paulo
965b9c547cSRui Paulo
x_snoop_mcast_to_ucast_convert_send(struct hostapd_data * hapd,struct sta_info * sta,u8 * buf,size_t len)975b9c547cSRui Paulo void x_snoop_mcast_to_ucast_convert_send(struct hostapd_data *hapd,
985b9c547cSRui Paulo struct sta_info *sta, u8 *buf,
995b9c547cSRui Paulo size_t len)
1005b9c547cSRui Paulo {
1015b9c547cSRui Paulo int res;
1025b9c547cSRui Paulo u8 addr[ETH_ALEN];
1035b9c547cSRui Paulo u8 *dst_addr = buf;
1045b9c547cSRui Paulo
1055b9c547cSRui Paulo if (!(dst_addr[0] & 0x01))
1065b9c547cSRui Paulo return;
1075b9c547cSRui Paulo
1085b9c547cSRui Paulo wpa_printf(MSG_EXCESSIVE, "x_snoop: Multicast-to-unicast conversion "
1095b9c547cSRui Paulo MACSTR " -> " MACSTR " (len %u)",
1105b9c547cSRui Paulo MAC2STR(dst_addr), MAC2STR(sta->addr), (unsigned int) len);
1115b9c547cSRui Paulo
1125b9c547cSRui Paulo /* save the multicast destination address for restoring it later */
1135b9c547cSRui Paulo os_memcpy(addr, buf, ETH_ALEN);
1145b9c547cSRui Paulo
1155b9c547cSRui Paulo os_memcpy(buf, sta->addr, ETH_ALEN);
1165b9c547cSRui Paulo res = l2_packet_send(hapd->sock_dhcp, NULL, 0, buf, len);
1175b9c547cSRui Paulo if (res < 0) {
1185b9c547cSRui Paulo wpa_printf(MSG_DEBUG,
1195b9c547cSRui Paulo "x_snoop: Failed to send mcast to ucast converted packet to "
1205b9c547cSRui Paulo MACSTR, MAC2STR(sta->addr));
1215b9c547cSRui Paulo }
1225b9c547cSRui Paulo
1235b9c547cSRui Paulo /* restore the multicast destination address */
1245b9c547cSRui Paulo os_memcpy(buf, addr, ETH_ALEN);
1255b9c547cSRui Paulo }
1265b9c547cSRui Paulo
1275b9c547cSRui Paulo
x_snoop_deinit(struct hostapd_data * hapd)1285b9c547cSRui Paulo void x_snoop_deinit(struct hostapd_data *hapd)
1295b9c547cSRui Paulo {
130*a90b9d01SCy Schubert if (!hapd->x_snoop_initialized)
131*a90b9d01SCy Schubert return;
1325b9c547cSRui Paulo hostapd_drv_br_set_net_param(hapd, DRV_BR_NET_PARAM_GARP_ACCEPT, 0);
1335b9c547cSRui Paulo hostapd_drv_br_port_set_attr(hapd, DRV_BR_PORT_ATTR_PROXYARP, 0);
1345b9c547cSRui Paulo hostapd_drv_br_port_set_attr(hapd, DRV_BR_PORT_ATTR_HAIRPIN_MODE, 0);
135*a90b9d01SCy Schubert hapd->x_snoop_initialized = false;
1365b9c547cSRui Paulo }
137