2 * WPA Supplicant - Layer2 packet handling with libpcap/libdnet and WinPcap
3 * Copyright (c) 2003-2006, Jouni Malinen <j@w1.fi>
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
10 #ifndef CONFIG_NATIVE_WINDOWS
11 #include <sys/ioctl.h>
12 #endif /* CONFIG_NATIVE_WINDOWS */
14 #ifndef CONFIG_WINPCAP
16 #endif /* CONFIG_WINPCAP */
20 #include "l2_packet.h"
23 static const u8 pae_group_addr
[ETH_ALEN
] =
24 { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 };
26 struct l2_packet_data
{
29 unsigned int num_fast_poll
;
30 #else /* CONFIG_WINPCAP */
32 #endif /* CONFIG_WINPCAP */
34 u8 own_addr
[ETH_ALEN
];
35 void (*rx_callback
)(void *ctx
, const u8
*src_addr
,
36 const u8
*buf
, size_t len
);
37 void *rx_callback_ctx
;
38 int l2_hdr
; /* whether to include layer 2 (Ethernet) header in calls
43 int l2_packet_get_own_addr(struct l2_packet_data
*l2
, u8
*addr
)
45 os_memcpy(addr
, l2
->own_addr
, ETH_ALEN
);
50 #ifndef CONFIG_WINPCAP
51 static int l2_packet_init_libdnet(struct l2_packet_data
*l2
)
55 l2
->eth
= eth_open(l2
->ifname
);
58 "Failed to open interface '%s' - eth_open: %s",
59 l2
->ifname
, strerror(errno
));
63 if (eth_get(l2
->eth
, &own_addr
) < 0) {
65 "Failed to get own hw address from interface '%s' - eth_get: %s",
66 l2
->ifname
, strerror(errno
));
71 os_memcpy(l2
->own_addr
, own_addr
.data
, ETH_ALEN
);
75 #endif /* CONFIG_WINPCAP */
78 int l2_packet_send(struct l2_packet_data
*l2
, const u8
*dst_addr
, u16 proto
,
79 const u8
*buf
, size_t len
)
82 struct l2_ethhdr
*eth
;
89 ret
= pcap_sendpacket(l2
->pcap
, buf
, len
);
90 #else /* CONFIG_WINPCAP */
91 ret
= eth_send(l2
->eth
, buf
, len
);
92 #endif /* CONFIG_WINPCAP */
94 size_t mlen
= sizeof(*eth
) + len
;
95 eth
= os_malloc(mlen
);
99 os_memcpy(eth
->h_dest
, dst_addr
, ETH_ALEN
);
100 os_memcpy(eth
->h_source
, l2
->own_addr
, ETH_ALEN
);
101 eth
->h_proto
= htons(proto
);
102 os_memcpy(eth
+ 1, buf
, len
);
104 #ifdef CONFIG_WINPCAP
105 ret
= pcap_sendpacket(l2
->pcap
, (u8
*) eth
, mlen
);
106 #else /* CONFIG_WINPCAP */
107 ret
= eth_send(l2
->eth
, (u8
*) eth
, mlen
);
108 #endif /* CONFIG_WINPCAP */
117 #ifndef CONFIG_WINPCAP
118 static void l2_packet_receive(int sock
, void *eloop_ctx
, void *sock_ctx
)
120 struct l2_packet_data
*l2
= eloop_ctx
;
121 pcap_t
*pcap
= sock_ctx
;
122 struct pcap_pkthdr hdr
;
123 const u_char
*packet
;
124 struct l2_ethhdr
*ethhdr
;
128 packet
= pcap_next(pcap
, &hdr
);
130 if (packet
== NULL
|| hdr
.caplen
< sizeof(*ethhdr
))
133 ethhdr
= (struct l2_ethhdr
*) packet
;
135 buf
= (unsigned char *) ethhdr
;
138 buf
= (unsigned char *) (ethhdr
+ 1);
139 len
= hdr
.caplen
- sizeof(*ethhdr
);
141 l2
->rx_callback(l2
->rx_callback_ctx
, ethhdr
->h_source
, buf
, len
);
143 #endif /* CONFIG_WINPCAP */
146 #ifdef CONFIG_WINPCAP
147 static void l2_packet_receive_cb(u_char
*user
, const struct pcap_pkthdr
*hdr
,
148 const u_char
*pkt_data
)
150 struct l2_packet_data
*l2
= (struct l2_packet_data
*) user
;
151 struct l2_ethhdr
*ethhdr
;
155 if (pkt_data
== NULL
|| hdr
->caplen
< sizeof(*ethhdr
))
158 ethhdr
= (struct l2_ethhdr
*) pkt_data
;
160 buf
= (unsigned char *) ethhdr
;
163 buf
= (unsigned char *) (ethhdr
+ 1);
164 len
= hdr
->caplen
- sizeof(*ethhdr
);
166 l2
->rx_callback(l2
->rx_callback_ctx
, ethhdr
->h_source
, buf
, len
);
168 * Use shorter poll interval for 3 seconds to reduce latency during key
171 l2
->num_fast_poll
= 3 * 50;
175 static void l2_packet_receive_timeout(void *eloop_ctx
, void *timeout_ctx
)
177 struct l2_packet_data
*l2
= eloop_ctx
;
178 pcap_t
*pcap
= timeout_ctx
;
181 if (l2
->num_fast_poll
> 0) {
187 /* Register new timeout before calling l2_packet_receive() since
188 * receive handler may free this l2_packet instance (which will
189 * cancel this timeout). */
190 eloop_register_timeout(0, timeout
, l2_packet_receive_timeout
,
192 pcap_dispatch(pcap
, 10, l2_packet_receive_cb
, (u_char
*) l2
);
194 #endif /* CONFIG_WINPCAP */
197 static int l2_packet_init_libpcap(struct l2_packet_data
*l2
,
198 unsigned short protocol
)
200 bpf_u_int32 pcap_maskp
, pcap_netp
;
201 char pcap_filter
[200], pcap_err
[PCAP_ERRBUF_SIZE
];
202 struct bpf_program pcap_fp
;
204 #ifdef CONFIG_WINPCAP
206 os_snprintf(ifname
, sizeof(ifname
), "\\Device\\NPF_%s", l2
->ifname
);
207 pcap_lookupnet(ifname
, &pcap_netp
, &pcap_maskp
, pcap_err
);
208 l2
->pcap
= pcap_open_live(ifname
, 2500, 0, 10, pcap_err
);
209 if (l2
->pcap
== NULL
) {
210 fprintf(stderr
, "pcap_open_live: %s\n", pcap_err
);
211 fprintf(stderr
, "ifname='%s'\n", ifname
);
214 if (pcap_setnonblock(l2
->pcap
, 1, pcap_err
) < 0)
215 fprintf(stderr
, "pcap_setnonblock: %s\n",
216 pcap_geterr(l2
->pcap
));
217 #else /* CONFIG_WINPCAP */
218 pcap_lookupnet(l2
->ifname
, &pcap_netp
, &pcap_maskp
, pcap_err
);
219 l2
->pcap
= pcap_open_live(l2
->ifname
, 2500, 0, 10, pcap_err
);
220 if (l2
->pcap
== NULL
) {
221 fprintf(stderr
, "pcap_open_live: %s\n", pcap_err
);
222 fprintf(stderr
, "ifname='%s'\n", l2
->ifname
);
225 if (pcap_datalink(l2
->pcap
) != DLT_EN10MB
&&
226 pcap_set_datalink(l2
->pcap
, DLT_EN10MB
) < 0) {
227 fprintf(stderr
, "pcap_set_datalink(DLT_EN10MB): %s\n",
228 pcap_geterr(l2
->pcap
));
231 #endif /* CONFIG_WINPCAP */
232 os_snprintf(pcap_filter
, sizeof(pcap_filter
),
233 "not ether src " MACSTR
" and "
234 "( ether dst " MACSTR
" or ether dst " MACSTR
" ) and "
236 MAC2STR(l2
->own_addr
), /* do not receive own packets */
237 MAC2STR(l2
->own_addr
), MAC2STR(pae_group_addr
),
239 if (pcap_compile(l2
->pcap
, &pcap_fp
, pcap_filter
, 1, pcap_netp
) < 0) {
240 fprintf(stderr
, "pcap_compile: %s\n", pcap_geterr(l2
->pcap
));
244 if (pcap_setfilter(l2
->pcap
, &pcap_fp
) < 0) {
245 fprintf(stderr
, "pcap_setfilter: %s\n", pcap_geterr(l2
->pcap
));
249 pcap_freecode(&pcap_fp
);
252 * When libpcap uses BPF we must enable "immediate mode" to
253 * receive frames right away; otherwise the system may
254 * buffer them for us.
258 if (ioctl(pcap_fileno(l2
->pcap
), BIOCIMMEDIATE
, &on
) < 0) {
259 fprintf(stderr
, "%s: cannot enable immediate mode on "
260 "interface %s: %s\n",
261 __func__
, l2
->ifname
, strerror(errno
));
262 /* XXX should we fail? */
265 #endif /* BIOCIMMEDIATE */
267 #ifdef CONFIG_WINPCAP
268 eloop_register_timeout(0, 100000, l2_packet_receive_timeout
,
270 #else /* CONFIG_WINPCAP */
271 eloop_register_read_sock(pcap_get_selectable_fd(l2
->pcap
),
272 l2_packet_receive
, l2
, l2
->pcap
);
273 #endif /* CONFIG_WINPCAP */
279 struct l2_packet_data
* l2_packet_init(
280 const char *ifname
, const u8
*own_addr
, unsigned short protocol
,
281 void (*rx_callback
)(void *ctx
, const u8
*src_addr
,
282 const u8
*buf
, size_t len
),
283 void *rx_callback_ctx
, int l2_hdr
)
285 struct l2_packet_data
*l2
;
287 l2
= os_zalloc(sizeof(struct l2_packet_data
));
290 os_strlcpy(l2
->ifname
, ifname
, sizeof(l2
->ifname
));
291 l2
->rx_callback
= rx_callback
;
292 l2
->rx_callback_ctx
= rx_callback_ctx
;
295 #ifdef CONFIG_WINPCAP
297 os_memcpy(l2
->own_addr
, own_addr
, ETH_ALEN
);
298 #else /* CONFIG_WINPCAP */
299 if (l2_packet_init_libdnet(l2
))
301 #endif /* CONFIG_WINPCAP */
303 if (l2_packet_init_libpcap(l2
, protocol
)) {
304 #ifndef CONFIG_WINPCAP
306 #endif /* CONFIG_WINPCAP */
315 struct l2_packet_data
* l2_packet_init_bridge(
316 const char *br_ifname
, const char *ifname
, const u8
*own_addr
,
317 unsigned short protocol
,
318 void (*rx_callback
)(void *ctx
, const u8
*src_addr
,
319 const u8
*buf
, size_t len
),
320 void *rx_callback_ctx
, int l2_hdr
)
322 return l2_packet_init(br_ifname
, own_addr
, protocol
, rx_callback
,
323 rx_callback_ctx
, l2_hdr
);
327 void l2_packet_deinit(struct l2_packet_data
*l2
)
332 #ifdef CONFIG_WINPCAP
333 eloop_cancel_timeout(l2_packet_receive_timeout
, l2
, l2
->pcap
);
334 #else /* CONFIG_WINPCAP */
337 eloop_unregister_read_sock(pcap_get_selectable_fd(l2
->pcap
));
338 #endif /* CONFIG_WINPCAP */
340 pcap_close(l2
->pcap
);
345 int l2_packet_get_ip_addr(struct l2_packet_data
*l2
, char *buf
, size_t len
)
347 pcap_if_t
*devs
, *dev
;
348 struct pcap_addr
*addr
;
349 struct sockaddr_in
*saddr
;
351 char err
[PCAP_ERRBUF_SIZE
+ 1];
353 if (pcap_findalldevs(&devs
, err
) < 0) {
354 wpa_printf(MSG_DEBUG
, "pcap_findalldevs: %s\n", err
);
358 for (dev
= devs
; dev
&& !found
; dev
= dev
->next
) {
359 if (os_strcmp(dev
->name
, l2
->ifname
) != 0)
362 addr
= dev
->addresses
;
364 saddr
= (struct sockaddr_in
*) addr
->addr
;
365 if (saddr
&& saddr
->sin_family
== AF_INET
) {
366 os_strlcpy(buf
, inet_ntoa(saddr
->sin_addr
),
375 pcap_freealldevs(devs
);
377 return found
? 0 : -1;
381 void l2_packet_notify_auth_start(struct l2_packet_data
*l2
)
383 #ifdef CONFIG_WINPCAP
385 * Use shorter poll interval for 3 seconds to reduce latency during key
388 l2
->num_fast_poll
= 3 * 50;
389 eloop_cancel_timeout(l2_packet_receive_timeout
, l2
, l2
->pcap
);
390 eloop_register_timeout(0, 10000, l2_packet_receive_timeout
,
392 #endif /* CONFIG_WINPCAP */
396 int l2_packet_set_packet_filter(struct l2_packet_data
*l2
,
397 enum l2_packet_filter_type type
)