1 /*
2 * WPA Supplicant - Layer2 packet handling with Linux packet sockets
3 * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
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/common.h"
10 #include "utils/eloop.h"
11 #ifdef CONFIG_DRIVER_SOC
12 #include "driver_soc_ioctl.h"
13 #endif /* CONFIG_DRIVER_SOC */
14 #include "securec.h"
15
16 struct l2_packet_data {
17 struct dl_list list;
18 struct l2_packet_netif *netif;
19
20 u16 protocol;
21 void (*rx_callback)(void *ctx, const u8 *src_addr, const u8 *buf, size_t len);
22 void *rx_callback_ctx;
23 int l2_hdr; /* whether to include layer 2 (Ethernet) header data
24 * buffers */
25 };
26
27 struct l2_packet_netif {
28 struct dl_list list;
29 struct dl_list datalist;
30
31 void *eloop_event;
32 char ifname[IFNAMSIZ + 1];
33 u8 own_addr[ETH_ALEN];
34 };
35
36 static struct dl_list g_l2_packet_list = {0};
37
l2_packet_get_own_addr(const struct l2_packet_data * l2,u8 * addr,size_t len)38 int l2_packet_get_own_addr(const struct l2_packet_data *l2, u8 *addr, size_t len)
39 {
40 (void)len;
41 if (l2 == NULL || l2->netif == NULL || addr == NULL)
42 return -1;
43 (void)os_memcpy(addr, l2->netif->own_addr, sizeof(l2->netif->own_addr));
44
45 return 0;
46 }
47
l2_packet_send(const struct l2_packet_data * l2,const u8 * dst_addr,u16 proto,const u8 * buf,size_t len)48 int l2_packet_send(const struct l2_packet_data *l2, const u8 *dst_addr, u16 proto,
49 const u8 *buf, size_t len)
50 {
51 int ret = 0;
52
53 (void)proto;
54 if (l2 == NULL || l2->netif == NULL)
55 return -1;
56 #ifdef CONFIG_DRIVER_SOC
57 ret = drv_soc_eapol_packet_send(l2->netif->ifname, l2->netif->own_addr, dst_addr, (unsigned char *)buf, len);
58 #endif /* CONFIG_DRIVER_SOC */
59 return ret;
60 }
61
l2_packet_receive(void * eloop_ctx,void * sock_ctx)62 static void l2_packet_receive(void *eloop_ctx, void *sock_ctx)
63 {
64 struct l2_packet_netif *netif = eloop_ctx;
65 struct l2_packet_data *tmp = NULL;
66 struct l2_packet_data *nxt = NULL;
67 unsigned short ether_type;
68
69 (void)sock_ctx;
70 if ((netif == NULL) || (netif->eloop_event == NULL)) {
71 return;
72 }
73
74 #ifdef CONFIG_DRIVER_SOC
75 ext_rx_eapol_stru st_rx_eapol;
76 unsigned char *puc_src = NULL;
77
78 /* eloop_post_event is invoked each time an eapol frame is received.
79 Therefore, eloop_post_event is called to release the memory applied for by eloop_post_event
80 when eapol data is read from the driver code. */
81 (void)eloop_read_event(netif->eloop_event, 0);
82 /* Callback is called only once per multiple packets, drain all of them */
83 while (drv_soc_eapol_packet_receive(netif->ifname, &st_rx_eapol) == EXT_SUCC) {
84 puc_src = (unsigned char *)(st_rx_eapol.buf + ETH_ALEN);
85 ether_type = *(unsigned short *)(st_rx_eapol.buf + ETH_ALEN + ETH_ALEN);
86
87 dl_list_for_each_safe(tmp, nxt, &netif->datalist, struct l2_packet_data, list) {
88 if (ntohs(ether_type) != tmp->protocol) {
89 continue;
90 }
91 if (tmp->rx_callback != NULL && st_rx_eapol.len <= EAPOL_PKT_BUF_SIZE) {
92 tmp->rx_callback(tmp->rx_callback_ctx, puc_src, st_rx_eapol.buf, st_rx_eapol.len);
93 }
94 break;
95 }
96
97 os_free(st_rx_eapol.buf);
98 st_rx_eapol.buf = NULL;
99 }
100
101 if (st_rx_eapol.buf != NULL) {
102 os_free(st_rx_eapol.buf);
103 st_rx_eapol.buf = NULL;
104 }
105 #endif /* CONFIG_DRIVER_SOC */
106 }
107
l2_packet_eapol_callback(void * ctx,void * context)108 static void l2_packet_eapol_callback(void *ctx, void *context)
109 {
110 struct l2_packet_netif *netif = (struct l2_packet_netif *)context;
111 (void)ctx;
112
113 if (netif == NULL)
114 return;
115
116 (void)eloop_post_event(netif->eloop_event, NULL, 1);
117 }
118
l2_packet_init(const char * ifname,const u8 * own_addr,unsigned short protocol,void (* rx_callback)(void * ctx,const u8 * src_addr,const u8 * buf,size_t len),void * rx_callback_ctx,int l2_hdr)119 struct l2_packet_data * l2_packet_init(
120 const char *ifname, const u8 *own_addr, unsigned short protocol,
121 void (*rx_callback)(void *ctx, const u8 *src_addr, const u8 *buf, size_t len),
122 void *rx_callback_ctx, int l2_hdr)
123 {
124 struct l2_packet_data *l2 = NULL;
125 struct l2_packet_netif *netif = NULL;
126 struct l2_packet_netif *tmp = NULL;
127
128 (void)own_addr;
129 if (ifname == NULL)
130 return NULL;
131
132 /* Init for device environment */
133 if (g_l2_packet_list.next == NULL || g_l2_packet_list.prev == NULL) {
134 dl_list_init(&g_l2_packet_list);
135 }
136
137 l2 = os_zalloc(sizeof(struct l2_packet_data));
138 if (l2 == NULL) {
139 return NULL;
140 }
141
142 if (dl_list_len(&g_l2_packet_list) != 0) {
143 dl_list_for_each(tmp, &g_l2_packet_list, struct l2_packet_netif, list) {
144 if (os_strcmp(ifname, tmp->ifname) == 0) {
145 netif = tmp;
146 break;
147 }
148 }
149 }
150
151 if (netif == NULL) {
152 netif = os_zalloc(sizeof(struct l2_packet_netif));
153 if (netif == NULL) {
154 os_free(l2);
155 return NULL;
156 }
157 if (os_strlcpy(netif->ifname, ifname, sizeof(netif->ifname)) >= sizeof(netif->ifname)) {
158 os_free(netif);
159 os_free(l2);
160 wpa_error_log0(MSG_ERROR, "l2_packet_init strcpy_s failed.");
161 return NULL;
162 }
163 (void)eloop_register_event(&netif->eloop_event, sizeof(void *), l2_packet_receive, netif, NULL);
164 if (netif->eloop_event == NULL) {
165 os_free(netif);
166 os_free(l2);
167 wpa_error_log0(MSG_ERROR, "l2_packet_init eloop register failed.");
168 return NULL;
169 }
170 #ifdef CONFIG_DRIVER_SOC
171 (void)drv_soc_eapol_enable(netif->ifname, l2_packet_eapol_callback, netif);
172 (void)drv_soc_ioctl_get_own_mac(netif->ifname, (char *)netif->own_addr);
173 #endif /* CONFIG_DRIVER_SOC */
174
175 dl_list_init(&netif->datalist);
176
177 dl_list_add_tail(&g_l2_packet_list, &netif->list);
178 }
179
180 l2->netif = netif;
181 l2->protocol = protocol;
182 l2->rx_callback = rx_callback;
183 l2->rx_callback_ctx = rx_callback_ctx;
184 l2->l2_hdr = l2_hdr;
185 dl_list_add_tail(&netif->datalist, &l2->list);
186 return l2;
187 }
188
l2_packet_init_bridge(const char * br_ifname,const char * ifname,const u8 * own_addr,unsigned short protocol,void (* rx_callback)(void * ctx,const u8 * src_addr,const u8 * buf,size_t len),void * rx_callback_ctx,int l2_hdr)189 struct l2_packet_data * l2_packet_init_bridge(
190 const char *br_ifname, const char *ifname, const u8 *own_addr,
191 unsigned short protocol,
192 void (*rx_callback)(void *ctx, const u8 *src_addr, const u8 *buf, size_t len),
193 void *rx_callback_ctx, int l2_hdr)
194 {
195 (void)ifname;
196 return l2_packet_init(br_ifname, own_addr, protocol, rx_callback,
197 rx_callback_ctx, l2_hdr);
198 }
199
l2_packet_deinit(struct l2_packet_data * l2)200 void l2_packet_deinit(struct l2_packet_data *l2)
201 {
202 struct l2_packet_netif *netif = NULL;
203
204 if (l2 == NULL || l2->netif == NULL) {
205 return;
206 }
207
208 netif = l2->netif;
209 dl_list_del(&l2->list);
210 os_free(l2);
211 l2 = NULL;
212
213 if (dl_list_len(&netif->datalist) == 0) {
214 if (netif->eloop_event != NULL) {
215 eloop_unregister_event(netif->eloop_event, 0); // 0:useless
216 netif->eloop_event = NULL;
217 }
218 #ifdef CONFIG_DRIVER_SOC
219 (void)drv_soc_eapol_disable(netif->ifname);
220 #endif /* CONFIG_DRIVER_SOC */
221 dl_list_del(&netif->list);
222 os_free(netif);
223 }
224 }
225
l2_packet_get_ip_addr(struct l2_packet_data * l2,char * buf,size_t len)226 int l2_packet_get_ip_addr(struct l2_packet_data *l2, char *buf, size_t len)
227 {
228 (void)l2;
229 (void)buf;
230 (void)len;
231 return 0;
232 }
233
l2_packet_notify_auth_start(struct l2_packet_data * l2)234 void l2_packet_notify_auth_start(struct l2_packet_data *l2)
235 {
236 (void)l2;
237 }
238