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 18 int 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 hapd->x_snoop_initialized = true; 35 36 if (hostapd_drv_br_port_set_attr(hapd, DRV_BR_PORT_ATTR_HAIRPIN_MODE, 37 1)) { 38 wpa_printf(MSG_DEBUG, 39 "x_snoop: Failed to enable hairpin_mode on the bridge port"); 40 return -1; 41 } 42 43 if (hostapd_drv_br_port_set_attr(hapd, DRV_BR_PORT_ATTR_PROXYARP, 1)) { 44 wpa_printf(MSG_DEBUG, 45 "x_snoop: Failed to enable proxyarp on the bridge port"); 46 return -1; 47 } 48 49 if (hostapd_drv_br_set_net_param(hapd, DRV_BR_NET_PARAM_GARP_ACCEPT, 50 1)) { 51 wpa_printf(MSG_DEBUG, 52 "x_snoop: Failed to enable accepting gratuitous ARP on the bridge"); 53 return -1; 54 } 55 56 #ifdef CONFIG_IPV6 57 if (hostapd_drv_br_set_net_param(hapd, DRV_BR_MULTICAST_SNOOPING, 1)) { 58 wpa_printf(MSG_DEBUG, 59 "x_snoop: Failed to enable multicast snooping on the bridge"); 60 return -1; 61 } 62 #endif /* CONFIG_IPV6 */ 63 64 return 0; 65 } 66 67 68 struct l2_packet_data * 69 x_snoop_get_l2_packet(struct hostapd_data *hapd, 70 void (*handler)(void *ctx, const u8 *src_addr, 71 const u8 *buf, size_t len), 72 enum l2_packet_filter_type type) 73 { 74 struct hostapd_bss_config *conf = hapd->conf; 75 struct l2_packet_data *l2; 76 77 l2 = l2_packet_init(conf->bridge, NULL, ETH_P_ALL, handler, hapd, 1); 78 if (l2 == NULL) { 79 wpa_printf(MSG_DEBUG, 80 "x_snoop: Failed to initialize L2 packet processing %s", 81 strerror(errno)); 82 return NULL; 83 } 84 85 if (l2_packet_set_packet_filter(l2, type)) { 86 wpa_printf(MSG_DEBUG, 87 "x_snoop: Failed to set L2 packet filter for type: %d", 88 type); 89 l2_packet_deinit(l2); 90 return NULL; 91 } 92 93 return l2; 94 } 95 96 97 void x_snoop_mcast_to_ucast_convert_send(struct hostapd_data *hapd, 98 struct sta_info *sta, u8 *buf, 99 size_t len) 100 { 101 int res; 102 u8 addr[ETH_ALEN]; 103 u8 *dst_addr = buf; 104 105 if (!(dst_addr[0] & 0x01)) 106 return; 107 108 wpa_printf(MSG_EXCESSIVE, "x_snoop: Multicast-to-unicast conversion " 109 MACSTR " -> " MACSTR " (len %u)", 110 MAC2STR(dst_addr), MAC2STR(sta->addr), (unsigned int) len); 111 112 /* save the multicast destination address for restoring it later */ 113 os_memcpy(addr, buf, ETH_ALEN); 114 115 os_memcpy(buf, sta->addr, ETH_ALEN); 116 res = l2_packet_send(hapd->sock_dhcp, NULL, 0, buf, len); 117 if (res < 0) { 118 wpa_printf(MSG_DEBUG, 119 "x_snoop: Failed to send mcast to ucast converted packet to " 120 MACSTR, MAC2STR(sta->addr)); 121 } 122 123 /* restore the multicast destination address */ 124 os_memcpy(buf, addr, ETH_ALEN); 125 } 126 127 128 void x_snoop_deinit(struct hostapd_data *hapd) 129 { 130 if (!hapd->x_snoop_initialized) 131 return; 132 hostapd_drv_br_set_net_param(hapd, DRV_BR_NET_PARAM_GARP_ACCEPT, 0); 133 hostapd_drv_br_port_set_attr(hapd, DRV_BR_PORT_ATTR_PROXYARP, 0); 134 hostapd_drv_br_port_set_attr(hapd, DRV_BR_PORT_ATTR_HAIRPIN_MODE, 0); 135 hapd->x_snoop_initialized = false; 136 } 137