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