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 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 return 0; 55 } 56 57 58 struct l2_packet_data * 59 x_snoop_get_l2_packet(struct hostapd_data *hapd, 60 void (*handler)(void *ctx, const u8 *src_addr, 61 const u8 *buf, size_t len), 62 enum l2_packet_filter_type type) 63 { 64 struct hostapd_bss_config *conf = hapd->conf; 65 struct l2_packet_data *l2; 66 67 l2 = l2_packet_init(conf->bridge, NULL, ETH_P_ALL, handler, hapd, 1); 68 if (l2 == NULL) { 69 wpa_printf(MSG_DEBUG, 70 "x_snoop: Failed to initialize L2 packet processing %s", 71 strerror(errno)); 72 return NULL; 73 } 74 75 if (l2_packet_set_packet_filter(l2, type)) { 76 wpa_printf(MSG_DEBUG, 77 "x_snoop: Failed to set L2 packet filter for type: %d", 78 type); 79 l2_packet_deinit(l2); 80 return NULL; 81 } 82 83 return l2; 84 } 85 86 87 void x_snoop_mcast_to_ucast_convert_send(struct hostapd_data *hapd, 88 struct sta_info *sta, u8 *buf, 89 size_t len) 90 { 91 int res; 92 u8 addr[ETH_ALEN]; 93 u8 *dst_addr = buf; 94 95 if (!(dst_addr[0] & 0x01)) 96 return; 97 98 wpa_printf(MSG_EXCESSIVE, "x_snoop: Multicast-to-unicast conversion " 99 MACSTR " -> " MACSTR " (len %u)", 100 MAC2STR(dst_addr), MAC2STR(sta->addr), (unsigned int) len); 101 102 /* save the multicast destination address for restoring it later */ 103 os_memcpy(addr, buf, ETH_ALEN); 104 105 os_memcpy(buf, sta->addr, ETH_ALEN); 106 res = l2_packet_send(hapd->sock_dhcp, NULL, 0, buf, len); 107 if (res < 0) { 108 wpa_printf(MSG_DEBUG, 109 "x_snoop: Failed to send mcast to ucast converted packet to " 110 MACSTR, MAC2STR(sta->addr)); 111 } 112 113 /* restore the multicast destination address */ 114 os_memcpy(buf, addr, ETH_ALEN); 115 } 116 117 118 void x_snoop_deinit(struct hostapd_data *hapd) 119 { 120 hostapd_drv_br_set_net_param(hapd, DRV_BR_NET_PARAM_GARP_ACCEPT, 0); 121 hostapd_drv_br_port_set_attr(hapd, DRV_BR_PORT_ATTR_PROXYARP, 0); 122 hostapd_drv_br_port_set_attr(hapd, DRV_BR_PORT_ATTR_HAIRPIN_MODE, 0); 123 } 124