1/* 2 * Generic Snooping for Proxy ARP 3 * Copyright (c) 2014, Qualcomm Atheros, Inc. 4 * 5 * This software may be distributed under the terms of the BSD license. 6 * See README for more details. 7 */ 8 9#include "utils/includes.h" 10 11#include "utils/common.h" 12#include "hostapd.h" 13#include "sta_info.h" 14#include "ap_drv_ops.h" 15#include "x_snoop.h" 16 17 18int x_snoop_init(struct hostapd_data *hapd) 19{ 20 struct hostapd_bss_config *conf = hapd->conf; 21 22 if (!conf->isolate) { 23 wpa_printf(MSG_DEBUG, 24 "x_snoop: ap_isolate must be enabled for x_snoop"); 25 return -1; 26 } 27 28 if (conf->bridge[0] == '\0') { 29 wpa_printf(MSG_DEBUG, 30 "x_snoop: Bridge must be configured for x_snoop"); 31 return -1; 32 } 33 34 if (hostapd_drv_br_port_set_attr(hapd, DRV_BR_PORT_ATTR_HAIRPIN_MODE, 35 1)) { 36 wpa_printf(MSG_DEBUG, 37 "x_snoop: Failed to enable hairpin_mode on the bridge port"); 38 return -1; 39 } 40 41 if (hostapd_drv_br_port_set_attr(hapd, DRV_BR_PORT_ATTR_PROXYARP, 1)) { 42 wpa_printf(MSG_DEBUG, 43 "x_snoop: Failed to enable proxyarp on the bridge port"); 44 return -1; 45 } 46 47 if (hostapd_drv_br_set_net_param(hapd, DRV_BR_NET_PARAM_GARP_ACCEPT, 48 1)) { 49 wpa_printf(MSG_DEBUG, 50 "x_snoop: Failed to enable accepting gratuitous ARP on the bridge"); 51 return -1; 52 } 53 54#ifdef CONFIG_IPV6 55 if (hostapd_drv_br_set_net_param(hapd, DRV_BR_MULTICAST_SNOOPING, 1)) { 56 wpa_printf(MSG_DEBUG, 57 "x_snoop: Failed to enable multicast snooping on the bridge"); 58 return -1; 59 } 60#endif /* CONFIG_IPV6 */ 61 62 return 0; 63} 64 65 66struct l2_packet_data * 67x_snoop_get_l2_packet(struct hostapd_data *hapd, 68 void (*handler)(void *ctx, const u8 *src_addr, 69 const u8 *buf, size_t len), 70 enum l2_packet_filter_type type) 71{ 72 struct hostapd_bss_config *conf = hapd->conf; 73 struct l2_packet_data *l2; 74 75 l2 = l2_packet_init(conf->bridge, NULL, ETH_P_ALL, handler, hapd, 1); 76 if (l2 == NULL) { 77 wpa_printf(MSG_DEBUG, 78 "x_snoop: Failed to initialize L2 packet processing %s", 79 strerror(errno)); 80 return NULL; 81 } 82 83 if (l2_packet_set_packet_filter(l2, type)) { 84 wpa_printf(MSG_DEBUG, 85 "x_snoop: Failed to set L2 packet filter for type: %d", 86 type); 87 l2_packet_deinit(l2); 88 return NULL; 89 } 90 91 return l2; 92} 93 94 95void x_snoop_mcast_to_ucast_convert_send(struct hostapd_data *hapd, 96 struct sta_info *sta, u8 *buf, 97 size_t len) 98{ 99 int res; 100 u8 addr[ETH_ALEN]; 101 u8 *dst_addr = buf; 102 103 if (!(dst_addr[0] & 0x01)) 104 return; 105 106 wpa_printf(MSG_EXCESSIVE, "x_snoop: Multicast-to-unicast conversion " 107 MACSTR " -> " MACSTR " (len %u)", 108 MAC2STR(dst_addr), MAC2STR(sta->addr), (unsigned int) len); 109 110 /* save the multicast destination address for restoring it later */ 111 os_memcpy(addr, buf, ETH_ALEN); 112 113 os_memcpy(buf, sta->addr, ETH_ALEN); 114 res = l2_packet_send(hapd->sock_dhcp, NULL, 0, buf, len); 115 if (res < 0) { 116 wpa_printf(MSG_DEBUG, 117 "x_snoop: Failed to send mcast to ucast converted packet to " 118 MACSTR, MAC2STR(sta->addr)); 119 } 120 121 /* restore the multicast destination address */ 122 os_memcpy(buf, addr, ETH_ALEN); 123} 124 125 126void x_snoop_deinit(struct hostapd_data *hapd) 127{ 128 hostapd_drv_br_set_net_param(hapd, DRV_BR_NET_PARAM_GARP_ACCEPT, 0); 129 hostapd_drv_br_port_set_attr(hapd, DRV_BR_PORT_ATTR_PROXYARP, 0); 130 hostapd_drv_br_port_set_attr(hapd, DRV_BR_PORT_ATTR_HAIRPIN_MODE, 0); 131} 132