xref: /freebsd/contrib/wpa/src/ap/x_snoop.c (revision 87b759f0fa1f7554d50ce640c40138512bbded44)
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