16c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt/*
26c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * Generic Snooping for Proxy ARP
36c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * Copyright (c) 2014, Qualcomm Atheros, Inc.
46c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt *
56c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * This software may be distributed under the terms of the BSD license.
66c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * See README for more details.
76c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt */
86c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
96c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#include "utils/includes.h"
106c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
116c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#include "utils/common.h"
126c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#include "hostapd.h"
136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#include "sta_info.h"
146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#include "ap_drv_ops.h"
156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#include "x_snoop.h"
166c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
176c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtint x_snoop_init(struct hostapd_data *hapd)
196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{
206c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct hostapd_bss_config *conf = hapd->conf;
216c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
226c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!conf->isolate) {
236c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG,
246c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   "x_snoop: ap_isolate must be enabled for x_snoop");
256c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -1;
266c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
286c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (conf->bridge[0] == '\0') {
296c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG,
306c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   "x_snoop: Bridge must be configured for x_snoop");
316c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -1;
326c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
336c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
346c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (hostapd_drv_br_port_set_attr(hapd, DRV_BR_PORT_ATTR_HAIRPIN_MODE,
356c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					 1)) {
366c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG,
376c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   "x_snoop: Failed to enable hairpin_mode on the bridge port");
386c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -1;
396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
406c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
416c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (hostapd_drv_br_port_set_attr(hapd, DRV_BR_PORT_ATTR_PROXYARP, 1)) {
426c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG,
436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   "x_snoop: Failed to enable proxyarp on the bridge port");
446c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -1;
456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
466c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
476c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (hostapd_drv_br_set_net_param(hapd, DRV_BR_NET_PARAM_GARP_ACCEPT,
486c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					 1)) {
496c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG,
506c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   "x_snoop: Failed to enable accepting gratuitous ARP on the bridge");
516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -1;
526c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
548347444e0bfb85e4550817fc99903f38ce8f5bccDmitry Shmidt#ifdef CONFIG_IPV6
558347444e0bfb85e4550817fc99903f38ce8f5bccDmitry Shmidt	if (hostapd_drv_br_set_net_param(hapd, DRV_BR_MULTICAST_SNOOPING, 1)) {
568347444e0bfb85e4550817fc99903f38ce8f5bccDmitry Shmidt		wpa_printf(MSG_DEBUG,
578347444e0bfb85e4550817fc99903f38ce8f5bccDmitry Shmidt			   "x_snoop: Failed to enable multicast snooping on the bridge");
588347444e0bfb85e4550817fc99903f38ce8f5bccDmitry Shmidt		return -1;
598347444e0bfb85e4550817fc99903f38ce8f5bccDmitry Shmidt	}
608347444e0bfb85e4550817fc99903f38ce8f5bccDmitry Shmidt#endif /* CONFIG_IPV6 */
618347444e0bfb85e4550817fc99903f38ce8f5bccDmitry Shmidt
626c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return 0;
636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}
646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstruct l2_packet_data *
676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtx_snoop_get_l2_packet(struct hostapd_data *hapd,
686c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		      void (*handler)(void *ctx, const u8 *src_addr,
696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				      const u8 *buf, size_t len),
706c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		      enum l2_packet_filter_type type)
716c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{
726c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct hostapd_bss_config *conf = hapd->conf;
736c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct l2_packet_data *l2;
746c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	l2 = l2_packet_init(conf->bridge, NULL, ETH_P_ALL, handler, hapd, 1);
766c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (l2 == NULL) {
776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG,
786c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   "x_snoop: Failed to initialize L2 packet processing %s",
796c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   strerror(errno));
806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return NULL;
816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (l2_packet_set_packet_filter(l2, type)) {
846c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG,
856c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   "x_snoop: Failed to set L2 packet filter for type: %d",
866c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   type);
876c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		l2_packet_deinit(l2);
886c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return NULL;
896c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
906c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
916c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return l2;
926c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}
936c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
946c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
956c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtvoid x_snoop_mcast_to_ucast_convert_send(struct hostapd_data *hapd,
966c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					 struct sta_info *sta, u8 *buf,
976c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					 size_t len)
986c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{
996c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	int res;
1006c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	u8 addr[ETH_ALEN];
1016c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	u8 *dst_addr = buf;
1026c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
1036c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!(dst_addr[0] & 0x01))
1046c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return;
1056c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
1066c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	wpa_printf(MSG_EXCESSIVE, "x_snoop: Multicast-to-unicast conversion "
1076c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		   MACSTR " -> " MACSTR " (len %u)",
1086c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		   MAC2STR(dst_addr), MAC2STR(sta->addr), (unsigned int) len);
1096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
1106c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	/* save the multicast destination address for restoring it later */
1116c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	os_memcpy(addr, buf, ETH_ALEN);
1126c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
1136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	os_memcpy(buf, sta->addr, ETH_ALEN);
1146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	res = l2_packet_send(hapd->sock_dhcp, NULL, 0, buf, len);
1156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (res < 0) {
1166c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG,
1176c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   "x_snoop: Failed to send mcast to ucast converted packet to "
1186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   MACSTR, MAC2STR(sta->addr));
1196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
1206c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
1216c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	/* restore the multicast destination address */
1226c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	os_memcpy(buf, addr, ETH_ALEN);
1236c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}
1246c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
1256c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
1266c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtvoid x_snoop_deinit(struct hostapd_data *hapd)
1276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{
1286c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	hostapd_drv_br_set_net_param(hapd, DRV_BR_NET_PARAM_GARP_ACCEPT, 0);
1296c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	hostapd_drv_br_port_set_attr(hapd, DRV_BR_PORT_ATTR_PROXYARP, 0);
1306c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	hostapd_drv_br_port_set_attr(hapd, DRV_BR_PORT_ATTR_HAIRPIN_MODE, 0);
1316c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}
132