xref: /dragonfly/contrib/wpa_supplicant/src/ap/x_snoop.c (revision 3a84a4273475ed07d0ab1c2dfeffdfedef35d9cd)
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 
x_snoop_init(struct hostapd_data * hapd)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 #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 
66 struct l2_packet_data *
x_snoop_get_l2_packet(struct hostapd_data * hapd,void (* handler)(void * ctx,const u8 * src_addr,const u8 * buf,size_t len),enum l2_packet_filter_type type)67 x_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 
x_snoop_mcast_to_ucast_convert_send(struct hostapd_data * hapd,struct sta_info * sta,u8 * buf,size_t len)95 void 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 
x_snoop_deinit(struct hostapd_data * hapd)126 void 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