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.5 2007/11/25 01:28:23 swildner 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>
43 #include "l2_packet.h"
45 static const u8 pae_group_addr
[ETH_ALEN
] =
46 { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 };
48 struct l2_packet_data
{
51 u8 own_addr
[ETH_ALEN
];
52 void (*rx_callback
)(void *ctx
, const u8
*src_addr
,
53 const u8
*buf
, size_t len
);
54 void *rx_callback_ctx
;
55 int l2_hdr
; /* whether to include layer 2 (Ethernet) header data
60 l2_packet_get_own_addr(struct l2_packet_data
*l2
, u8
*addr
)
62 memcpy(addr
, l2
->own_addr
, ETH_ALEN
);
67 l2_packet_get_ip_addr(struct l2_packet_data
*l2
, char *buf
, size_t len
)
69 pcap_if_t
*devs
, *dev
;
70 struct pcap_addr
*addr
;
71 struct sockaddr_in
*saddr
;
73 char err
[PCAP_ERRBUF_SIZE
+ 1];
75 if (pcap_findalldevs(&devs
, err
) < 0) {
76 wpa_printf(MSG_DEBUG
, "pcap_findalldevs: %s\n", err
);
80 for (dev
= devs
; dev
&& !found
; dev
= dev
->next
) {
81 if (strcmp(dev
->name
, l2
->ifname
) != 0)
84 addr
= dev
->addresses
;
86 saddr
= (struct sockaddr_in
*) addr
->addr
;
87 if (saddr
&& saddr
->sin_family
== AF_INET
) {
88 snprintf(buf
, len
, "%s",
89 inet_ntoa(saddr
->sin_addr
));
97 pcap_freealldevs(devs
);
99 return found
? 0 : -1;
103 l2_packet_notify_auth_start(struct l2_packet_data
*l2
)
108 l2_packet_send(struct l2_packet_data
*l2
,
109 const u8
*dst_addr
, u16 proto
, const u8
*buf
, size_t len
)
113 struct l2_ethhdr
*eth
= malloc(sizeof(*eth
) + len
);
116 memcpy(eth
->h_dest
, dst_addr
, ETH_ALEN
);
117 memcpy(eth
->h_source
, l2
->own_addr
, ETH_ALEN
);
118 eth
->h_proto
= htons(proto
);
119 memcpy(eth
+ 1, buf
, len
);
120 ret
= pcap_inject(l2
->pcap
, (u8
*) eth
, len
+ sizeof(*eth
));
124 return pcap_inject(l2
->pcap
, buf
, len
);
129 l2_packet_receive(int sock
, void *eloop_ctx
, void *sock_ctx
)
131 struct l2_packet_data
*l2
= eloop_ctx
;
132 pcap_t
*pcap
= sock_ctx
;
133 struct pcap_pkthdr hdr
;
134 const u_char
*packet
;
135 struct l2_ethhdr
*ethhdr
;
139 packet
= pcap_next(pcap
, &hdr
);
141 if (packet
== NULL
|| hdr
.caplen
< sizeof(*ethhdr
))
144 ethhdr
= (struct l2_ethhdr
*) packet
;
146 buf
= (unsigned char *) ethhdr
;
149 buf
= (unsigned char *) (ethhdr
+ 1);
150 len
= hdr
.caplen
- sizeof(*ethhdr
);
152 l2
->rx_callback(l2
->rx_callback_ctx
, ethhdr
->h_source
, buf
, len
);
156 l2_packet_init_libpcap(struct l2_packet_data
*l2
, unsigned short protocol
)
158 bpf_u_int32 pcap_maskp
, pcap_netp
;
159 char pcap_filter
[200], pcap_err
[PCAP_ERRBUF_SIZE
];
160 struct bpf_program pcap_fp
;
162 pcap_lookupnet(l2
->ifname
, &pcap_netp
, &pcap_maskp
, pcap_err
);
163 l2
->pcap
= pcap_open_live(l2
->ifname
, 2500, 0, 10, pcap_err
);
164 if (l2
->pcap
== NULL
) {
165 fprintf(stderr
, "pcap_open_live: %s\n", pcap_err
);
166 fprintf(stderr
, "ifname='%s'\n", l2
->ifname
);
169 if (pcap_datalink(l2
->pcap
) != DLT_EN10MB
&&
170 pcap_set_datalink(l2
->pcap
, DLT_EN10MB
) < 0) {
171 fprintf(stderr
, "pcap_set_datalink(DLT_EN10MB): %s\n",
172 pcap_geterr(l2
->pcap
));
175 snprintf(pcap_filter
, sizeof(pcap_filter
),
176 "not ether src " MACSTR
" and "
177 "( ether dst " MACSTR
" or ether dst " MACSTR
" ) and "
179 MAC2STR(l2
->own_addr
), /* do not receive own packets */
180 MAC2STR(l2
->own_addr
), MAC2STR(pae_group_addr
),
182 if (pcap_compile(l2
->pcap
, &pcap_fp
, pcap_filter
, 1, pcap_netp
) < 0) {
183 fprintf(stderr
, "pcap_compile: %s\n", pcap_geterr(l2
->pcap
));
187 if (pcap_setfilter(l2
->pcap
, &pcap_fp
) < 0) {
188 fprintf(stderr
, "pcap_setfilter: %s\n", pcap_geterr(l2
->pcap
));
192 pcap_freecode(&pcap_fp
);
194 * When libpcap uses BPF we must enable "immediate mode" to
195 * receive frames right away; otherwise the system may
196 * buffer them for us.
198 { unsigned int on
= 1;
199 if (ioctl(pcap_fileno(l2
->pcap
), BIOCIMMEDIATE
, &on
) < 0) {
200 fprintf(stderr
, "%s: cannot enable immediate mode on "
201 "interface %s: %s\n",
202 __func__
, l2
->ifname
, strerror(errno
));
203 /* XXX should we fail? */
207 eloop_register_read_sock(pcap_get_selectable_fd(l2
->pcap
),
208 l2_packet_receive
, l2
, l2
->pcap
);
214 l2_packet_deinit_libpcap(struct l2_packet_data
*l2
)
216 if (l2
->pcap
!= NULL
) {
217 eloop_unregister_read_sock(pcap_get_selectable_fd(l2
->pcap
));
218 pcap_close(l2
->pcap
);
224 eth_get(const char *device
, u8 ea
[ETH_ALEN
])
226 struct if_msghdr
*ifm
;
227 struct sockaddr_dl
*sdl
;
230 int mib
[] = { CTL_NET
, AF_ROUTE
, 0, AF_LINK
, NET_RT_IFLIST
, 0 };
232 if (sysctl(mib
, 6, NULL
, &len
, NULL
, 0) < 0)
234 if ((buf
= malloc(len
)) == NULL
)
236 if (sysctl(mib
, 6, buf
, &len
, NULL
, 0) < 0) {
240 for (p
= buf
; p
< buf
+ len
; p
+= ifm
->ifm_msglen
) {
241 ifm
= (struct if_msghdr
*)p
;
242 sdl
= (struct sockaddr_dl
*)(ifm
+ 1);
243 if (ifm
->ifm_type
!= RTM_IFINFO
||
244 (ifm
->ifm_addrs
& RTA_IFP
) == 0)
246 if (sdl
->sdl_family
!= AF_LINK
|| sdl
->sdl_nlen
== 0 ||
247 memcmp(sdl
->sdl_data
, device
, sdl
->sdl_nlen
) != 0)
249 memcpy(ea
, LLADDR(sdl
), sdl
->sdl_alen
);
254 if (p
>= buf
+ len
) {
261 struct l2_packet_data
*
262 l2_packet_init(const char *ifname
, const u8
*own_addr
, unsigned short protocol
,
263 void (*rx_callback
)(void *ctx
, const u8
*src_addr
,
264 const u8
*buf
, size_t len
),
265 void *rx_callback_ctx
, int l2_hdr
)
267 struct l2_packet_data
*l2
;
269 l2
= malloc(sizeof(struct l2_packet_data
));
272 memset(l2
, 0, sizeof(*l2
));
273 strncpy(l2
->ifname
, ifname
, sizeof(l2
->ifname
));
274 l2
->rx_callback
= rx_callback
;
275 l2
->rx_callback_ctx
= rx_callback_ctx
;
278 if (eth_get(l2
->ifname
, l2
->own_addr
) < 0) {
279 fprintf(stderr
, "Failed to get link-level address for "
280 "interface '%s'.\n", l2
->ifname
);
285 if (l2_packet_init_libpcap(l2
, protocol
) != 0) {
293 l2_packet_deinit(struct l2_packet_data
*l2
)
296 l2_packet_deinit_libpcap(l2
);