Line data Source code
1 : /*
2 : * WPA Supplicant - Layer2 packet handling with Linux packet sockets
3 : * Copyright (c) 2003-2015, 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 "includes.h"
10 : #include <sys/ioctl.h>
11 : #include <netpacket/packet.h>
12 : #include <net/if.h>
13 : #include <linux/filter.h>
14 :
15 : #include "common.h"
16 : #include "eloop.h"
17 : #include "l2_packet.h"
18 :
19 :
20 : struct l2_packet_data {
21 : int fd; /* packet socket for EAPOL frames */
22 : char ifname[IFNAMSIZ + 1];
23 : int ifindex;
24 : u8 own_addr[ETH_ALEN];
25 : void (*rx_callback)(void *ctx, const u8 *src_addr,
26 : const u8 *buf, size_t len);
27 : void *rx_callback_ctx;
28 : int l2_hdr; /* whether to include layer 2 (Ethernet) header data
29 : * buffers */
30 :
31 : /* For working around Linux packet socket behavior and regression. */
32 : int fd_br_rx;
33 : };
34 :
35 : /* Generated by 'sudo tcpdump -s 3000 -dd greater 278 and ip and udp and
36 : * src port bootps and dst port bootpc'
37 : */
38 : static struct sock_filter dhcp_sock_filter_insns[] = {
39 : { 0x80, 0, 0, 0x00000000 },
40 : { 0x35, 0, 12, 0x00000116 },
41 : { 0x28, 0, 0, 0x0000000c },
42 : { 0x15, 0, 10, 0x00000800 },
43 : { 0x30, 0, 0, 0x00000017 },
44 : { 0x15, 0, 8, 0x00000011 },
45 : { 0x28, 0, 0, 0x00000014 },
46 : { 0x45, 6, 0, 0x00001fff },
47 : { 0xb1, 0, 0, 0x0000000e },
48 : { 0x48, 0, 0, 0x0000000e },
49 : { 0x15, 0, 3, 0x00000043 },
50 : { 0x48, 0, 0, 0x00000010 },
51 : { 0x15, 0, 1, 0x00000044 },
52 : { 0x6, 0, 0, 0x00000bb8 },
53 : { 0x6, 0, 0, 0x00000000 },
54 : };
55 :
56 : static const struct sock_fprog dhcp_sock_filter = {
57 : .len = ARRAY_SIZE(dhcp_sock_filter_insns),
58 : .filter = dhcp_sock_filter_insns,
59 : };
60 :
61 :
62 : /* Generated by 'sudo tcpdump -dd -s 1500 multicast and ip6[6]=58' */
63 : static struct sock_filter ndisc_sock_filter_insns[] = {
64 : { 0x30, 0, 0, 0x00000000 },
65 : { 0x45, 0, 5, 0x00000001 },
66 : { 0x28, 0, 0, 0x0000000c },
67 : { 0x15, 0, 3, 0x000086dd },
68 : { 0x30, 0, 0, 0x00000014 },
69 : { 0x15, 0, 1, 0x0000003a },
70 : { 0x6, 0, 0, 0x000005dc },
71 : { 0x6, 0, 0, 0x00000000 },
72 : };
73 :
74 : static const struct sock_fprog ndisc_sock_filter = {
75 : .len = ARRAY_SIZE(ndisc_sock_filter_insns),
76 : .filter = ndisc_sock_filter_insns,
77 : };
78 :
79 :
80 211 : int l2_packet_get_own_addr(struct l2_packet_data *l2, u8 *addr)
81 : {
82 211 : os_memcpy(addr, l2->own_addr, ETH_ALEN);
83 211 : return 0;
84 : }
85 :
86 :
87 11372 : int l2_packet_send(struct l2_packet_data *l2, const u8 *dst_addr, u16 proto,
88 : const u8 *buf, size_t len)
89 : {
90 : int ret;
91 11372 : if (l2 == NULL)
92 0 : return -1;
93 11372 : if (l2->l2_hdr) {
94 3324 : ret = send(l2->fd, buf, len, 0);
95 3324 : if (ret < 0)
96 0 : wpa_printf(MSG_ERROR, "l2_packet_send - send: %s",
97 0 : strerror(errno));
98 : } else {
99 : struct sockaddr_ll ll;
100 8048 : os_memset(&ll, 0, sizeof(ll));
101 8048 : ll.sll_family = AF_PACKET;
102 8048 : ll.sll_ifindex = l2->ifindex;
103 8048 : ll.sll_protocol = htons(proto);
104 8048 : ll.sll_halen = ETH_ALEN;
105 8048 : os_memcpy(ll.sll_addr, dst_addr, ETH_ALEN);
106 8048 : ret = sendto(l2->fd, buf, len, 0, (struct sockaddr *) &ll,
107 : sizeof(ll));
108 8048 : if (ret < 0) {
109 0 : wpa_printf(MSG_ERROR, "l2_packet_send - sendto: %s",
110 0 : strerror(errno));
111 : }
112 : }
113 11372 : return ret;
114 : }
115 :
116 :
117 14164 : static void l2_packet_receive(int sock, void *eloop_ctx, void *sock_ctx)
118 : {
119 14164 : struct l2_packet_data *l2 = eloop_ctx;
120 : u8 buf[2300];
121 : int res;
122 : struct sockaddr_ll ll;
123 : socklen_t fromlen;
124 :
125 14164 : os_memset(&ll, 0, sizeof(ll));
126 14164 : fromlen = sizeof(ll);
127 14164 : res = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *) &ll,
128 : &fromlen);
129 14164 : if (res < 0) {
130 182 : wpa_printf(MSG_DEBUG, "l2_packet_receive - recvfrom: %s",
131 182 : strerror(errno));
132 14346 : return;
133 : }
134 :
135 13982 : l2->rx_callback(l2->rx_callback_ctx, ll.sll_addr, buf, res);
136 :
137 13982 : if (l2->fd_br_rx >= 0) {
138 0 : wpa_printf(MSG_DEBUG, "l2_packet_receive: Main packet socket for %s seems to have working RX - close workaround bridge socket",
139 0 : l2->ifname);
140 0 : eloop_unregister_read_sock(l2->fd_br_rx);
141 0 : close(l2->fd_br_rx);
142 0 : l2->fd_br_rx = -1;
143 : }
144 : }
145 :
146 :
147 4 : static void l2_packet_receive_br(int sock, void *eloop_ctx, void *sock_ctx)
148 : {
149 4 : struct l2_packet_data *l2 = eloop_ctx;
150 : u8 buf[2300];
151 : int res;
152 : struct sockaddr_ll ll;
153 : socklen_t fromlen;
154 :
155 4 : os_memset(&ll, 0, sizeof(ll));
156 4 : fromlen = sizeof(ll);
157 4 : res = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *) &ll,
158 : &fromlen);
159 4 : if (res < 0) {
160 0 : wpa_printf(MSG_DEBUG, "l2_packet_receive_br - recvfrom: %s",
161 0 : strerror(errno));
162 4 : return;
163 : }
164 :
165 4 : l2->rx_callback(l2->rx_callback_ctx, ll.sll_addr, buf, res);
166 : }
167 :
168 :
169 2925 : struct l2_packet_data * l2_packet_init(
170 : const char *ifname, const u8 *own_addr, unsigned short protocol,
171 : void (*rx_callback)(void *ctx, const u8 *src_addr,
172 : const u8 *buf, size_t len),
173 : void *rx_callback_ctx, int l2_hdr)
174 : {
175 : struct l2_packet_data *l2;
176 : struct ifreq ifr;
177 : struct sockaddr_ll ll;
178 :
179 2925 : l2 = os_zalloc(sizeof(struct l2_packet_data));
180 2925 : if (l2 == NULL)
181 3 : return NULL;
182 2922 : os_strlcpy(l2->ifname, ifname, sizeof(l2->ifname));
183 2922 : l2->rx_callback = rx_callback;
184 2922 : l2->rx_callback_ctx = rx_callback_ctx;
185 2922 : l2->l2_hdr = l2_hdr;
186 2922 : l2->fd_br_rx = -1;
187 :
188 2922 : l2->fd = socket(PF_PACKET, l2_hdr ? SOCK_RAW : SOCK_DGRAM,
189 2922 : htons(protocol));
190 2922 : if (l2->fd < 0) {
191 0 : wpa_printf(MSG_ERROR, "%s: socket(PF_PACKET): %s",
192 0 : __func__, strerror(errno));
193 0 : os_free(l2);
194 0 : return NULL;
195 : }
196 2922 : os_memset(&ifr, 0, sizeof(ifr));
197 2922 : os_strlcpy(ifr.ifr_name, l2->ifname, sizeof(ifr.ifr_name));
198 2922 : if (ioctl(l2->fd, SIOCGIFINDEX, &ifr) < 0) {
199 1 : wpa_printf(MSG_ERROR, "%s: ioctl[SIOCGIFINDEX]: %s",
200 1 : __func__, strerror(errno));
201 1 : close(l2->fd);
202 1 : os_free(l2);
203 1 : return NULL;
204 : }
205 2921 : l2->ifindex = ifr.ifr_ifindex;
206 :
207 2921 : os_memset(&ll, 0, sizeof(ll));
208 2921 : ll.sll_family = PF_PACKET;
209 2921 : ll.sll_ifindex = ifr.ifr_ifindex;
210 2921 : ll.sll_protocol = htons(protocol);
211 2921 : if (bind(l2->fd, (struct sockaddr *) &ll, sizeof(ll)) < 0) {
212 0 : wpa_printf(MSG_ERROR, "%s: bind[PF_PACKET]: %s",
213 0 : __func__, strerror(errno));
214 0 : close(l2->fd);
215 0 : os_free(l2);
216 0 : return NULL;
217 : }
218 :
219 2921 : if (ioctl(l2->fd, SIOCGIFHWADDR, &ifr) < 0) {
220 0 : wpa_printf(MSG_ERROR, "%s: ioctl[SIOCGIFHWADDR]: %s",
221 0 : __func__, strerror(errno));
222 0 : close(l2->fd);
223 0 : os_free(l2);
224 0 : return NULL;
225 : }
226 2921 : os_memcpy(l2->own_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
227 :
228 2921 : eloop_register_read_sock(l2->fd, l2_packet_receive, l2, NULL);
229 :
230 2921 : return l2;
231 : }
232 :
233 :
234 3 : struct l2_packet_data * l2_packet_init_bridge(
235 : const char *br_ifname, const char *ifname, const u8 *own_addr,
236 : unsigned short protocol,
237 : void (*rx_callback)(void *ctx, const u8 *src_addr,
238 : const u8 *buf, size_t len),
239 : void *rx_callback_ctx, int l2_hdr)
240 : {
241 : struct l2_packet_data *l2;
242 3 : struct sock_filter ethertype_sock_filter_insns[] = {
243 : /* Load ethertype */
244 : BPF_STMT(BPF_LD | BPF_H | BPF_ABS, 2 * ETH_ALEN),
245 : /* Jump over next statement if ethertype does not match */
246 : BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, protocol, 0, 1),
247 : /* Ethertype match - return all */
248 : BPF_STMT(BPF_RET | BPF_K, ~0),
249 : /* No match - drop */
250 : BPF_STMT(BPF_RET | BPF_K, 0)
251 : };
252 3 : const struct sock_fprog ethertype_sock_filter = {
253 : .len = ARRAY_SIZE(ethertype_sock_filter_insns),
254 : .filter = ethertype_sock_filter_insns,
255 : };
256 : struct sockaddr_ll ll;
257 :
258 3 : l2 = l2_packet_init(br_ifname, own_addr, protocol, rx_callback,
259 : rx_callback_ctx, l2_hdr);
260 3 : if (!l2)
261 1 : return NULL;
262 :
263 : /*
264 : * The Linux packet socket behavior has changed over the years and there
265 : * is an inconvenient regression in it that breaks RX for a specific
266 : * protocol from interfaces in a bridge when that interface is not in
267 : * fully operation state (i.e., when in station mode and not completed
268 : * authorization). To work around this, register ETH_P_ALL version of
269 : * the packet socket bound to the real netdev and use socket filter to
270 : * match the ethertype value. This version is less efficient, but
271 : * required for functionality with many kernel version. If the main
272 : * packet socket is found to be working, this less efficient version
273 : * gets closed automatically.
274 : */
275 :
276 2 : l2->fd_br_rx = socket(PF_PACKET, l2_hdr ? SOCK_RAW : SOCK_DGRAM,
277 2 : htons(ETH_P_ALL));
278 2 : if (l2->fd_br_rx < 0) {
279 0 : wpa_printf(MSG_DEBUG, "%s: socket(PF_PACKET-fd_br_rx): %s",
280 0 : __func__, strerror(errno));
281 : /* try to continue without the workaround RX socket */
282 0 : return l2;
283 : }
284 :
285 2 : os_memset(&ll, 0, sizeof(ll));
286 2 : ll.sll_family = PF_PACKET;
287 2 : ll.sll_ifindex = if_nametoindex(ifname);
288 2 : ll.sll_protocol = htons(ETH_P_ALL);
289 2 : if (bind(l2->fd_br_rx, (struct sockaddr *) &ll, sizeof(ll)) < 0) {
290 0 : wpa_printf(MSG_DEBUG, "%s: bind[PF_PACKET-fd_br_rx]: %s",
291 0 : __func__, strerror(errno));
292 : /* try to continue without the workaround RX socket */
293 0 : close(l2->fd_br_rx);
294 0 : l2->fd_br_rx = -1;
295 0 : return l2;
296 : }
297 :
298 2 : if (setsockopt(l2->fd_br_rx, SOL_SOCKET, SO_ATTACH_FILTER,
299 : ðertype_sock_filter, sizeof(struct sock_fprog))) {
300 0 : wpa_printf(MSG_DEBUG,
301 : "l2_packet_linux: setsockopt(SO_ATTACH_FILTER) failed: %s",
302 0 : strerror(errno));
303 : /* try to continue without the workaround RX socket */
304 0 : close(l2->fd_br_rx);
305 0 : l2->fd_br_rx = -1;
306 0 : return l2;
307 : }
308 :
309 2 : eloop_register_read_sock(l2->fd_br_rx, l2_packet_receive_br, l2, NULL);
310 :
311 2 : return l2;
312 : }
313 :
314 :
315 6788 : void l2_packet_deinit(struct l2_packet_data *l2)
316 : {
317 6788 : if (l2 == NULL)
318 10655 : return;
319 :
320 2921 : if (l2->fd >= 0) {
321 2921 : eloop_unregister_read_sock(l2->fd);
322 2921 : close(l2->fd);
323 : }
324 :
325 2921 : if (l2->fd_br_rx >= 0) {
326 2 : eloop_unregister_read_sock(l2->fd_br_rx);
327 2 : close(l2->fd_br_rx);
328 : }
329 :
330 2921 : os_free(l2);
331 : }
332 :
333 :
334 2517 : int l2_packet_get_ip_addr(struct l2_packet_data *l2, char *buf, size_t len)
335 : {
336 : int s;
337 : struct ifreq ifr;
338 : struct sockaddr_in *saddr;
339 : size_t res;
340 :
341 2517 : s = socket(PF_INET, SOCK_DGRAM, 0);
342 2517 : if (s < 0) {
343 0 : wpa_printf(MSG_ERROR, "%s: socket: %s",
344 0 : __func__, strerror(errno));
345 0 : return -1;
346 : }
347 2517 : os_memset(&ifr, 0, sizeof(ifr));
348 2517 : os_strlcpy(ifr.ifr_name, l2->ifname, sizeof(ifr.ifr_name));
349 2517 : if (ioctl(s, SIOCGIFADDR, &ifr) < 0) {
350 2516 : if (errno != EADDRNOTAVAIL)
351 0 : wpa_printf(MSG_ERROR, "%s: ioctl[SIOCGIFADDR]: %s",
352 0 : __func__, strerror(errno));
353 2516 : close(s);
354 2516 : return -1;
355 : }
356 1 : close(s);
357 1 : saddr = aliasing_hide_typecast(&ifr.ifr_addr, struct sockaddr_in);
358 1 : if (saddr->sin_family != AF_INET)
359 0 : return -1;
360 1 : res = os_strlcpy(buf, inet_ntoa(saddr->sin_addr), len);
361 1 : if (res >= len)
362 0 : return -1;
363 1 : return 0;
364 : }
365 :
366 :
367 2472 : void l2_packet_notify_auth_start(struct l2_packet_data *l2)
368 : {
369 2472 : }
370 :
371 :
372 10 : int l2_packet_set_packet_filter(struct l2_packet_data *l2,
373 : enum l2_packet_filter_type type)
374 : {
375 : const struct sock_fprog *sock_filter;
376 :
377 10 : switch (type) {
378 : case L2_PACKET_FILTER_DHCP:
379 5 : sock_filter = &dhcp_sock_filter;
380 5 : break;
381 : case L2_PACKET_FILTER_NDISC:
382 5 : sock_filter = &ndisc_sock_filter;
383 5 : break;
384 : default:
385 0 : return -1;
386 : }
387 :
388 10 : if (setsockopt(l2->fd, SOL_SOCKET, SO_ATTACH_FILTER,
389 : sock_filter, sizeof(struct sock_fprog))) {
390 0 : wpa_printf(MSG_ERROR,
391 : "l2_packet_linux: setsockopt(SO_ATTACH_FILTER) failed: %s",
392 0 : strerror(errno));
393 0 : return -1;
394 : }
395 :
396 10 : return 0;
397 : }
|