2 * WPA Supplicant - Layer2 packet handling with FreeBSD
3 * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
4 * Copyright (c) 2005, Sam Leffler <sam@errno.com>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
10 * Alternatively, this software may be distributed under the terms of BSD
13 * See README and COPYING for more details.
19 #endif /* __APPLE__ */
22 #include <sys/ioctl.h>
23 #include <sys/sysctl.h>
26 #include <net/if_dl.h>
27 #include <net/route.h>
28 #include <netinet/in.h>
32 #include "l2_packet.h"
35 static const u8 pae_group_addr
[ETH_ALEN
] =
36 { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 };
38 struct l2_packet_data
{
41 u8 own_addr
[ETH_ALEN
];
42 void (*rx_callback
)(void *ctx
, const u8
*src_addr
,
43 const u8
*buf
, size_t len
);
44 void *rx_callback_ctx
;
45 int l2_hdr
; /* whether to include layer 2 (Ethernet) header data
50 int l2_packet_get_own_addr(struct l2_packet_data
*l2
, u8
*addr
)
52 os_memcpy(addr
, l2
->own_addr
, ETH_ALEN
);
57 int l2_packet_send(struct l2_packet_data
*l2
, const u8
*dst_addr
, u16 proto
,
58 const u8
*buf
, size_t len
)
62 struct l2_ethhdr
*eth
= os_malloc(sizeof(*eth
) + len
);
65 os_memcpy(eth
->h_dest
, dst_addr
, ETH_ALEN
);
66 os_memcpy(eth
->h_source
, l2
->own_addr
, ETH_ALEN
);
67 eth
->h_proto
= htons(proto
);
68 os_memcpy(eth
+ 1, buf
, len
);
69 ret
= pcap_inject(l2
->pcap
, (u8
*) eth
, len
+ sizeof(*eth
));
73 return pcap_inject(l2
->pcap
, buf
, len
);
77 static void l2_packet_receive(int sock
, void *eloop_ctx
, void *sock_ctx
)
79 struct l2_packet_data
*l2
= eloop_ctx
;
80 pcap_t
*pcap
= sock_ctx
;
81 struct pcap_pkthdr hdr
;
83 struct l2_ethhdr
*ethhdr
;
87 packet
= pcap_next(pcap
, &hdr
);
89 if (packet
== NULL
|| hdr
.caplen
< sizeof(*ethhdr
))
92 ethhdr
= (struct l2_ethhdr
*) packet
;
94 buf
= (unsigned char *) ethhdr
;
97 buf
= (unsigned char *) (ethhdr
+ 1);
98 len
= hdr
.caplen
- sizeof(*ethhdr
);
100 l2
->rx_callback(l2
->rx_callback_ctx
, ethhdr
->h_source
, buf
, len
);
104 static int l2_packet_init_libpcap(struct l2_packet_data
*l2
,
105 unsigned short protocol
)
107 bpf_u_int32 pcap_maskp
, pcap_netp
;
108 char pcap_filter
[200], pcap_err
[PCAP_ERRBUF_SIZE
];
109 struct bpf_program pcap_fp
;
111 pcap_lookupnet(l2
->ifname
, &pcap_netp
, &pcap_maskp
, pcap_err
);
112 l2
->pcap
= pcap_open_live(l2
->ifname
, 2500, 0, 10, pcap_err
);
113 if (l2
->pcap
== NULL
) {
114 fprintf(stderr
, "pcap_open_live: %s\n", pcap_err
);
115 fprintf(stderr
, "ifname='%s'\n", l2
->ifname
);
118 if (pcap_datalink(l2
->pcap
) != DLT_EN10MB
&&
119 pcap_set_datalink(l2
->pcap
, DLT_EN10MB
) < 0) {
120 fprintf(stderr
, "pcap_set_datalink(DLT_EN10MB): %s\n",
121 pcap_geterr(l2
->pcap
));
124 os_snprintf(pcap_filter
, sizeof(pcap_filter
),
125 "not ether src " MACSTR
" and "
126 "( ether dst " MACSTR
" or ether dst " MACSTR
" ) and "
128 MAC2STR(l2
->own_addr
), /* do not receive own packets */
129 MAC2STR(l2
->own_addr
), MAC2STR(pae_group_addr
),
131 if (pcap_compile(l2
->pcap
, &pcap_fp
, pcap_filter
, 1, pcap_netp
) < 0) {
132 fprintf(stderr
, "pcap_compile: %s\n", pcap_geterr(l2
->pcap
));
136 if (pcap_setfilter(l2
->pcap
, &pcap_fp
) < 0) {
137 fprintf(stderr
, "pcap_setfilter: %s\n", pcap_geterr(l2
->pcap
));
141 pcap_freecode(&pcap_fp
);
143 * When libpcap uses BPF we must enable "immediate mode" to
144 * receive frames right away; otherwise the system may
145 * buffer them for us.
149 if (ioctl(pcap_fileno(l2
->pcap
), BIOCIMMEDIATE
, &on
) < 0) {
150 fprintf(stderr
, "%s: cannot enable immediate mode on "
151 "interface %s: %s\n",
152 __func__
, l2
->ifname
, strerror(errno
));
153 /* XXX should we fail? */
157 eloop_register_read_sock(pcap_get_selectable_fd(l2
->pcap
),
158 l2_packet_receive
, l2
, l2
->pcap
);
164 static int eth_get(const char *device
, u8 ea
[ETH_ALEN
])
166 struct if_msghdr
*ifm
;
167 struct sockaddr_dl
*sdl
;
170 int mib
[] = { CTL_NET
, AF_ROUTE
, 0, AF_LINK
, NET_RT_IFLIST
, 0 };
172 if (sysctl(mib
, 6, NULL
, &len
, NULL
, 0) < 0)
174 if ((buf
= os_malloc(len
)) == NULL
)
176 if (sysctl(mib
, 6, buf
, &len
, NULL
, 0) < 0) {
180 for (p
= buf
; p
< buf
+ len
; p
+= ifm
->ifm_msglen
) {
181 ifm
= (struct if_msghdr
*)p
;
182 sdl
= (struct sockaddr_dl
*)(ifm
+ 1);
183 if (ifm
->ifm_type
!= RTM_IFINFO
||
184 (ifm
->ifm_addrs
& RTA_IFP
) == 0)
186 if (sdl
->sdl_family
!= AF_LINK
|| sdl
->sdl_nlen
== 0 ||
187 os_memcmp(sdl
->sdl_data
, device
, sdl
->sdl_nlen
) != 0)
189 os_memcpy(ea
, LLADDR(sdl
), sdl
->sdl_alen
);
194 if (p
>= buf
+ len
) {
202 struct l2_packet_data
* l2_packet_init(
203 const char *ifname
, const u8
*own_addr
, unsigned short protocol
,
204 void (*rx_callback
)(void *ctx
, const u8
*src_addr
,
205 const u8
*buf
, size_t len
),
206 void *rx_callback_ctx
, int l2_hdr
)
208 struct l2_packet_data
*l2
;
210 l2
= os_zalloc(sizeof(struct l2_packet_data
));
213 os_strlcpy(l2
->ifname
, ifname
, sizeof(l2
->ifname
));
214 l2
->rx_callback
= rx_callback
;
215 l2
->rx_callback_ctx
= rx_callback_ctx
;
218 if (eth_get(l2
->ifname
, l2
->own_addr
) < 0) {
219 fprintf(stderr
, "Failed to get link-level address for "
220 "interface '%s'.\n", l2
->ifname
);
225 if (l2_packet_init_libpcap(l2
, protocol
)) {
234 void l2_packet_deinit(struct l2_packet_data
*l2
)
238 eloop_unregister_read_sock(
239 pcap_get_selectable_fd(l2
->pcap
));
240 pcap_close(l2
->pcap
);
247 int l2_packet_get_ip_addr(struct l2_packet_data
*l2
, char *buf
, size_t len
)
249 pcap_if_t
*devs
, *dev
;
250 struct pcap_addr
*addr
;
251 struct sockaddr_in
*saddr
;
253 char err
[PCAP_ERRBUF_SIZE
+ 1];
255 if (pcap_findalldevs(&devs
, err
) < 0) {
256 wpa_printf(MSG_DEBUG
, "pcap_findalldevs: %s\n", err
);
260 for (dev
= devs
; dev
&& !found
; dev
= dev
->next
) {
261 if (os_strcmp(dev
->name
, l2
->ifname
) != 0)
264 addr
= dev
->addresses
;
266 saddr
= (struct sockaddr_in
*) addr
->addr
;
267 if (saddr
&& saddr
->sin_family
== AF_INET
) {
268 os_strlcpy(buf
, inet_ntoa(saddr
->sin_addr
),
277 pcap_freealldevs(devs
);
279 return found
? 0 : -1;
283 void l2_packet_notify_auth_start(struct l2_packet_data
*l2
)