2 * WPA Supplicant - Layer2 packet handling
3 * Copyright (c) 2003-2004, Jouni Malinen <jkmaline@cc.hut.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.
15 * $FreeBSD: src/usr.sbin/wpa/l2_packet.c,v 1.4 2007/07/09 15:57:10 sam Exp $
16 * $DragonFly: src/usr.sbin/802_11/l2_packet.c,v 1.4 2007/08/07 11:25:36 sephe Exp $
20 * DragonFlyBSD-specific implementation.
22 #include <sys/types.h>
23 #include <sys/ioctl.h>
24 #include <sys/socket.h>
25 #include <sys/sysctl.h>
28 #include <net/if_dl.h>
30 #include <net/route.h>
31 #include <netinet/in.h>
32 #include <arpa/inet.h>
42 #include "l2_packet.h"
44 static const u8 pae_group_addr
[ETH_ALEN
] =
45 { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 };
47 struct l2_packet_data
{
50 u8 own_addr
[ETH_ALEN
];
51 void (*rx_callback
)(void *ctx
, const u8
*src_addr
,
52 const u8
*buf
, size_t len
);
53 void *rx_callback_ctx
;
54 int l2_hdr
; /* whether to include layer 2 (Ethernet) header data
59 l2_packet_get_own_addr(struct l2_packet_data
*l2
, u8
*addr
)
61 memcpy(addr
, l2
->own_addr
, ETH_ALEN
);
66 l2_packet_get_ip_addr(struct l2_packet_data
*l2
, char *buf
, size_t len
)
68 pcap_if_t
*devs
, *dev
;
69 struct pcap_addr
*addr
;
70 struct sockaddr_in
*saddr
;
72 char err
[PCAP_ERRBUF_SIZE
+ 1];
74 if (pcap_findalldevs(&devs
, err
) < 0) {
75 wpa_printf(MSG_DEBUG
, "pcap_findalldevs: %s\n", err
);
79 for (dev
= devs
; dev
&& !found
; dev
= dev
->next
) {
80 if (strcmp(dev
->name
, l2
->ifname
) != 0)
83 addr
= dev
->addresses
;
85 saddr
= (struct sockaddr_in
*) addr
->addr
;
86 if (saddr
&& saddr
->sin_family
== AF_INET
) {
87 snprintf(buf
, len
, "%s",
88 inet_ntoa(saddr
->sin_addr
));
96 pcap_freealldevs(devs
);
98 return found
? 0 : -1;
102 l2_packet_notify_auth_start(struct l2_packet_data
*l2
)
107 l2_packet_send(struct l2_packet_data
*l2
,
108 const u8
*dst_addr
, u16 proto
, const u8
*buf
, size_t len
)
112 struct l2_ethhdr
*eth
= malloc(sizeof(*eth
) + len
);
115 memcpy(eth
->h_dest
, dst_addr
, ETH_ALEN
);
116 memcpy(eth
->h_source
, l2
->own_addr
, ETH_ALEN
);
117 eth
->h_proto
= htons(proto
);
118 memcpy(eth
+ 1, buf
, len
);
119 ret
= pcap_inject(l2
->pcap
, (u8
*) eth
, len
+ sizeof(*eth
));
123 return pcap_inject(l2
->pcap
, buf
, len
);
128 l2_packet_receive(int sock
, void *eloop_ctx
, void *sock_ctx
)
130 struct l2_packet_data
*l2
= eloop_ctx
;
131 pcap_t
*pcap
= sock_ctx
;
132 struct pcap_pkthdr hdr
;
133 const u_char
*packet
;
134 struct l2_ethhdr
*ethhdr
;
138 packet
= pcap_next(pcap
, &hdr
);
140 if (packet
== NULL
|| hdr
.caplen
< sizeof(*ethhdr
))
143 ethhdr
= (struct l2_ethhdr
*) packet
;
145 buf
= (unsigned char *) ethhdr
;
148 buf
= (unsigned char *) (ethhdr
+ 1);
149 len
= hdr
.caplen
- sizeof(*ethhdr
);
151 l2
->rx_callback(l2
->rx_callback_ctx
, ethhdr
->h_source
, buf
, len
);
155 l2_packet_init_libpcap(struct l2_packet_data
*l2
, unsigned short protocol
)
157 bpf_u_int32 pcap_maskp
, pcap_netp
;
158 char pcap_filter
[200], pcap_err
[PCAP_ERRBUF_SIZE
];
159 struct bpf_program pcap_fp
;
161 pcap_lookupnet(l2
->ifname
, &pcap_netp
, &pcap_maskp
, pcap_err
);
162 l2
->pcap
= pcap_open_live(l2
->ifname
, 2500, 0, 10, pcap_err
);
163 if (l2
->pcap
== NULL
) {
164 fprintf(stderr
, "pcap_open_live: %s\n", pcap_err
);
165 fprintf(stderr
, "ifname='%s'\n", l2
->ifname
);
168 if (pcap_datalink(l2
->pcap
) != DLT_EN10MB
&&
169 pcap_set_datalink(l2
->pcap
, DLT_EN10MB
) < 0) {
170 fprintf(stderr
, "pcap_set_datalink(DLT_EN10MB): %s\n",
171 pcap_geterr(l2
->pcap
));
174 snprintf(pcap_filter
, sizeof(pcap_filter
),
175 "not ether src " MACSTR
" and "
176 "( ether dst " MACSTR
" or ether dst " MACSTR
" ) and "
178 MAC2STR(l2
->own_addr
), /* do not receive own packets */
179 MAC2STR(l2
->own_addr
), MAC2STR(pae_group_addr
),
181 if (pcap_compile(l2
->pcap
, &pcap_fp
, pcap_filter
, 1, pcap_netp
) < 0) {
182 fprintf(stderr
, "pcap_compile: %s\n", pcap_geterr(l2
->pcap
));
186 if (pcap_setfilter(l2
->pcap
, &pcap_fp
) < 0) {
187 fprintf(stderr
, "pcap_setfilter: %s\n", pcap_geterr(l2
->pcap
));
191 pcap_freecode(&pcap_fp
);
193 * When libpcap uses BPF we must enable "immediate mode" to
194 * receive frames right away; otherwise the system may
195 * buffer them for us.
197 { unsigned int on
= 1;
198 if (ioctl(pcap_fileno(l2
->pcap
), BIOCIMMEDIATE
, &on
) < 0) {
199 fprintf(stderr
, "%s: cannot enable immediate mode on "
200 "interface %s: %s\n",
201 __func__
, l2
->ifname
, strerror(errno
));
202 /* XXX should we fail? */
206 eloop_register_read_sock(pcap_get_selectable_fd(l2
->pcap
),
207 l2_packet_receive
, l2
, l2
->pcap
);
213 l2_packet_deinit_libpcap(struct l2_packet_data
*l2
)
215 if (l2
->pcap
!= NULL
) {
216 eloop_unregister_read_sock(pcap_get_selectable_fd(l2
->pcap
));
217 pcap_close(l2
->pcap
);
223 eth_get(const char *device
, u8 ea
[ETH_ALEN
])
225 struct if_msghdr
*ifm
;
226 struct sockaddr_dl
*sdl
;
229 int mib
[] = { CTL_NET
, AF_ROUTE
, 0, AF_LINK
, NET_RT_IFLIST
, 0 };
231 if (sysctl(mib
, 6, NULL
, &len
, NULL
, 0) < 0)
233 if ((buf
= malloc(len
)) == NULL
)
235 if (sysctl(mib
, 6, buf
, &len
, NULL
, 0) < 0) {
239 for (p
= buf
; p
< buf
+ len
; p
+= ifm
->ifm_msglen
) {
240 ifm
= (struct if_msghdr
*)p
;
241 sdl
= (struct sockaddr_dl
*)(ifm
+ 1);
242 if (ifm
->ifm_type
!= RTM_IFINFO
||
243 (ifm
->ifm_addrs
& RTA_IFP
) == 0)
245 if (sdl
->sdl_family
!= AF_LINK
|| sdl
->sdl_nlen
== 0 ||
246 memcmp(sdl
->sdl_data
, device
, sdl
->sdl_nlen
) != 0)
248 memcpy(ea
, LLADDR(sdl
), sdl
->sdl_alen
);
253 if (p
>= buf
+ len
) {
260 struct l2_packet_data
*
261 l2_packet_init(const char *ifname
, const u8
*own_addr
, unsigned short protocol
,
262 void (*rx_callback
)(void *ctx
, const u8
*src_addr
,
263 const u8
*buf
, size_t len
),
264 void *rx_callback_ctx
, int l2_hdr
)
266 struct l2_packet_data
*l2
;
268 l2
= malloc(sizeof(struct l2_packet_data
));
271 memset(l2
, 0, sizeof(*l2
));
272 strncpy(l2
->ifname
, ifname
, sizeof(l2
->ifname
));
273 l2
->rx_callback
= rx_callback
;
274 l2
->rx_callback_ctx
= rx_callback_ctx
;
277 if (eth_get(l2
->ifname
, l2
->own_addr
) < 0) {
278 fprintf(stderr
, "Failed to get link-level address for "
279 "interface '%s'.\n", l2
->ifname
);
284 if (l2_packet_init_libpcap(l2
, protocol
) != 0) {
292 l2_packet_deinit(struct l2_packet_data
*l2
)
295 l2_packet_deinit_libpcap(l2
);