• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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