1 /*
2  * Copyright (c) 2023 Nordic Semiconductor ASA
3  *
4  * This software may be distributed under the terms of the BSD license.
5  * See README for more details.
6  */
7 
8 #include <zephyr/kernel.h>
9 #include <zephyr/linker/sections.h>
10 #include <zephyr/toolchain.h>
11 #include <zephyr/net/net_core.h>
12 #include <zephyr/net/net_ip.h>
13 #include <zephyr/net/net_pkt.h>
14 
15 #include "includes.h"
16 #include "common.h"
17 #include "eloop.h"
18 #include "l2_packet.h"
19 #include "common/eapol_common.h"
20 
21 struct l2_packet_data {
22 	char ifname[17];
23 	u8 own_addr[ETH_ALEN];
24 	int ifindex;
25 	struct net_if *iface;
26 	void (*rx_callback)(void *ctx, const u8 *src_addr, const u8 *buf,
27 			    size_t len);
28 	void *rx_callback_ctx;
29 	int l2_hdr; /* whether to include layer 2 (Ethernet) header data
30 		     * buffers */
31 	int fd;
32 	unsigned short protocol;
33 };
34 
l2_packet_get_own_addr(struct l2_packet_data * l2,u8 * addr)35 int l2_packet_get_own_addr(struct l2_packet_data *l2, u8 *addr)
36 {
37 	os_memcpy(addr, l2->own_addr, ETH_ALEN);
38 	return 0;
39 }
40 
l2_packet_send(struct l2_packet_data * l2,const u8 * dst_addr,u16 proto,const u8 * buf,size_t len)41 int l2_packet_send(struct l2_packet_data *l2, const u8 *dst_addr, u16 proto,
42 		   const u8 *buf, size_t len)
43 {
44 	int ret;
45 
46 	if (l2 == NULL) {
47 		return -1;
48 	}
49 
50 	if (l2->l2_hdr) {
51 		ret = send(l2->fd, buf, len, 0);
52 		if (ret < 0) {
53 			wpa_printf(MSG_ERROR, "l2_packet_send - send: %s",
54 				   strerror(errno));
55 		}
56 	} else {
57 		struct sockaddr_ll ll;
58 
59 		os_memset(&ll, 0, sizeof(ll));
60 		ll.sll_family = AF_PACKET;
61 		ll.sll_ifindex = l2->ifindex;
62 		ll.sll_protocol = htons(proto);
63 		ll.sll_halen = ETH_ALEN;
64 		os_memcpy(ll.sll_addr, dst_addr, ETH_ALEN);
65 		// TODO: This takes up too much stack, call wifi driver TX directly?
66 		ret = sendto(l2->fd, buf, len, 0, (struct sockaddr *) &ll,
67 			     sizeof(ll));
68 		if (ret < 0) {
69 			wpa_printf(MSG_ERROR, "l2_packet_send - sendto: %s",
70 				   strerror(errno));
71 		}
72 	}
73 	return ret;
74 }
75 
l2_packet_receive(int sock,void * eloop_ctx,void * sock_ctx)76 static void l2_packet_receive(int sock, void *eloop_ctx, void *sock_ctx)
77 {
78 	struct l2_packet_data *l2 = eloop_ctx;
79 	u8 buf[2300];
80 	int res;
81 	struct sockaddr_ll ll;
82 	socklen_t fromlen;
83 	const struct ieee802_1x_hdr *hdr;
84 
85 	os_memset(&ll, 0, sizeof(ll));
86 	fromlen = sizeof(ll);
87 	res = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *)&ll,
88 		       &fromlen);
89 	if (res < 0) {
90 		wpa_printf(MSG_ERROR, "RAW : failed to recv error %d", errno);
91 		return;
92 	}
93 
94 	// FIXME: sll_addr is not being filled as L2 header is not removed
95 	hdr = (const struct ieee802_1x_hdr *) buf;
96 
97 	if (ll.sll_protocol != ETH_P_EAPOL) {
98 		return;
99 	}
100 
101 	// FIXME: We should only get registered protcols from networking stack
102 	// but for some reason ETH_P_ALL is being set (bind_default)
103 	l2->rx_callback(l2->rx_callback_ctx, ll.sll_addr, buf, res);
104 }
105 
106 struct l2_packet_data *
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)107 l2_packet_init(const char *ifname, const u8 *own_addr, unsigned short protocol,
108 	       void (*rx_callback)(void *ctx, const u8 *src_addr, const u8 *buf,
109 				   size_t len),
110 	       void *rx_callback_ctx, int l2_hdr)
111 {
112 	struct l2_packet_data *l2;
113 	struct sockaddr_ll ll;
114 	int ret = 0;
115 	struct net_linkaddr *link_addr = NULL;
116 	struct net_if *iface;
117 
118 	iface = net_if_get_by_index(net_if_get_by_name(ifname));
119 	if (!iface) {
120 		wpa_printf(MSG_ERROR, "Cannot get interface for: %s", ifname);
121 		return NULL;
122 	}
123 
124 	l2 = os_zalloc(sizeof(struct l2_packet_data));
125 	if (l2 == NULL) {
126 		return NULL;
127 	}
128 	os_strlcpy(l2->ifname, ifname, sizeof(l2->ifname));
129 	l2->rx_callback = rx_callback;
130 	l2->rx_callback_ctx = rx_callback_ctx;
131 	l2->l2_hdr = l2_hdr;
132 	l2->protocol = protocol;
133 	l2->iface = iface;
134 	l2->ifindex = net_if_get_by_iface(l2->iface);
135 
136 	if (!l2->ifindex) {
137 		wpa_printf(MSG_ERROR, "Cannot get  interface index for: %s\n",
138 			   l2->ifname);
139 		os_free(l2);
140 		return NULL;
141 	}
142 
143 	link_addr = &iface->if_dev->link_addr;
144 	os_memcpy(l2->own_addr, link_addr->addr, link_addr->len);
145 
146 	l2->fd = socket(AF_PACKET, l2_hdr ? SOCK_RAW : SOCK_DGRAM,
147 			htons(protocol));
148 	if (l2->fd < 0) {
149 		wpa_printf(MSG_ERROR,
150 			   "Failed to open socket: %s, proto: %d, af: %d",
151 			   strerror(errno), htons(protocol), AF_PACKET);
152 		goto fail;
153 	}
154 
155 	os_memset(&ll, 0, sizeof(ll));
156 	ll.sll_family = AF_PACKET;
157 
158 	ll.sll_ifindex = l2->ifindex;
159 	ll.sll_protocol = htons(protocol);
160 
161 	// FIXME: This should skip bind_default to ETH_P_ALL, but its not.
162 	memcpy(ll.sll_addr, l2->own_addr, ETH_ALEN);
163 
164 	ret = bind(l2->fd, (const struct sockaddr *) &ll, sizeof(ll));
165 	if (ret < 0) {
166 		goto fail;
167 	}
168 
169 	if (rx_callback) {
170 		eloop_register_read_sock(l2->fd, l2_packet_receive, l2, NULL);
171 	}
172 
173 	wpa_printf(MSG_DEBUG, "l2_packet_init: iface %s ifindex %d", l2->ifname,
174 		   l2->ifindex);
175 
176 	return l2;
177 fail:
178 	if (l2->fd >= 0)
179 		close(l2->fd);
180 	os_free(l2);
181 	wpa_printf(MSG_ERROR, "Failed to create l2_packet: %d\n", ret);
182 	return NULL;
183 }
184 
185 struct l2_packet_data *
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)186 l2_packet_init_bridge(const char *br_ifname, const char *ifname,
187 		      const u8 *own_addr, unsigned short protocol,
188 		      void (*rx_callback)(void *ctx, const u8 *src_addr,
189 					  const u8 *buf, size_t len),
190 		      void *rx_callback_ctx, int l2_hdr)
191 {
192 	return l2_packet_init(br_ifname, own_addr, protocol, rx_callback,
193 			      rx_callback_ctx, l2_hdr);
194 }
195 
l2_packet_deinit(struct l2_packet_data * l2)196 void l2_packet_deinit(struct l2_packet_data *l2)
197 {
198 	if (l2 == NULL) {
199 		return;
200 	}
201 
202 	if (l2->fd >= 0) {
203 		eloop_unregister_read_sock(l2->fd);
204 		close(l2->fd);
205 	}
206 
207 	os_free(l2);
208 }
209 
l2_packet_get_ip_addr(struct l2_packet_data * l2,char * buf,size_t len)210 int l2_packet_get_ip_addr(struct l2_packet_data *l2, char *buf, size_t len)
211 {
212 #ifdef CONFIG_NET_IPV4
213 	char addr_buf[NET_IPV4_ADDR_LEN];
214 	os_strlcpy(buf, net_addr_ntop(AF_INET,
215 				&l2->iface->config.ip.ipv4->unicast[0].ipv4.address.in_addr.s_addr,
216 				addr_buf, sizeof(addr_buf)), len);
217 	return 0;
218 #else
219 	return -1;
220 #endif
221 }
222 
l2_packet_notify_auth_start(struct l2_packet_data * l2)223 void l2_packet_notify_auth_start(struct l2_packet_data *l2)
224 {
225 	/* This function can be left empty */
226 }
227 
l2_packet_set_packet_filter(struct l2_packet_data * l2,enum l2_packet_filter_type type)228 int l2_packet_set_packet_filter(struct l2_packet_data *l2,
229 				enum l2_packet_filter_type type)
230 {
231 	/* TODO: Set filter */
232 	return 0;
233 }
234