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: head/usr.sbin/wpa/l2_packet.c 172682 2007-10-16 02:12:06Z mlaier $
19 * DragonFly-specific implementation.
21 #include <sys/types.h>
22 #include <sys/ioctl.h>
23 #include <sys/socket.h>
24 #include <sys/sysctl.h>
28 #include <net/if_dl.h>
29 #include <net/route.h>
30 #include <netinet/in.h>
31 #include <arpa/inet.h>
41 #include "l2_packet.h"
43 static const u8 pae_group_addr
[ETH_ALEN
] =
44 { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 };
46 struct l2_packet_data
{
49 u8 own_addr
[ETH_ALEN
];
50 void (*rx_callback
)(void *ctx
, const u8
*src_addr
,
51 const u8
*buf
, size_t len
);
52 void *rx_callback_ctx
;
53 int l2_hdr
; /* whether to include layer 2 (Ethernet) header data
58 l2_packet_get_own_addr(struct l2_packet_data
*l2
, u8
*addr
)
60 memcpy(addr
, l2
->own_addr
, ETH_ALEN
);
65 l2_packet_get_ip_addr(struct l2_packet_data
*l2
, char *buf
, size_t len
)
67 pcap_if_t
*devs
, *dev
;
68 struct pcap_addr
*addr
;
69 struct sockaddr_in
*saddr
;
71 char err
[PCAP_ERRBUF_SIZE
+ 1];
73 if (pcap_findalldevs(&devs
, err
) < 0) {
74 wpa_printf(MSG_DEBUG
, "pcap_findalldevs: %s\n", err
);
78 for (dev
= devs
; dev
&& !found
; dev
= dev
->next
) {
79 if (strcmp(dev
->name
, l2
->ifname
) != 0)
82 addr
= dev
->addresses
;
84 saddr
= (struct sockaddr_in
*) addr
->addr
;
85 if (saddr
&& saddr
->sin_family
== AF_INET
) {
86 snprintf(buf
, len
, "%s",
87 inet_ntoa(saddr
->sin_addr
));
95 pcap_freealldevs(devs
);
97 return found
? 0 : -1;
101 l2_packet_notify_auth_start(struct l2_packet_data
*l2
)
106 l2_packet_send(struct l2_packet_data
*l2
,
107 const u8
*dst_addr
, u16 proto
, const u8
*buf
, size_t len
)
111 struct l2_ethhdr
*eth
= malloc(sizeof(*eth
) + len
);
114 memcpy(eth
->h_dest
, dst_addr
, ETH_ALEN
);
115 memcpy(eth
->h_source
, l2
->own_addr
, ETH_ALEN
);
116 eth
->h_proto
= htons(proto
);
117 memcpy(eth
+ 1, buf
, len
);
118 ret
= pcap_inject(l2
->pcap
, (u8
*) eth
, len
+ sizeof(*eth
));
122 return pcap_inject(l2
->pcap
, buf
, len
);
127 l2_packet_receive(int sock
, void *eloop_ctx
, void *sock_ctx
)
129 struct l2_packet_data
*l2
= eloop_ctx
;
130 pcap_t
*pcap
= sock_ctx
;
131 struct pcap_pkthdr hdr
;
132 const u_char
*packet
;
133 struct l2_ethhdr
*ethhdr
;
137 packet
= pcap_next(pcap
, &hdr
);
139 if (packet
== NULL
|| hdr
.caplen
< sizeof(*ethhdr
))
142 ethhdr
= (struct l2_ethhdr
*) packet
;
144 buf
= (unsigned char *) ethhdr
;
147 buf
= (unsigned char *) (ethhdr
+ 1);
148 len
= hdr
.caplen
- sizeof(*ethhdr
);
150 l2
->rx_callback(l2
->rx_callback_ctx
, ethhdr
->h_source
, buf
, len
);
154 l2_packet_init_libpcap(struct l2_packet_data
*l2
, unsigned short protocol
)
156 bpf_u_int32 pcap_maskp
, pcap_netp
;
157 char pcap_filter
[200], pcap_err
[PCAP_ERRBUF_SIZE
];
158 struct bpf_program pcap_fp
;
160 pcap_lookupnet(l2
->ifname
, &pcap_netp
, &pcap_maskp
, pcap_err
);
161 l2
->pcap
= pcap_open_live(l2
->ifname
, 2500, 0, 10, pcap_err
);
162 if (l2
->pcap
== NULL
) {
163 fprintf(stderr
, "pcap_open_live: %s\n", pcap_err
);
164 fprintf(stderr
, "ifname='%s'\n", l2
->ifname
);
167 if (pcap_datalink(l2
->pcap
) != DLT_EN10MB
&&
168 pcap_set_datalink(l2
->pcap
, DLT_EN10MB
) < 0) {
169 fprintf(stderr
, "pcap_set_datalink(DLT_EN10MB): %s\n",
170 pcap_geterr(l2
->pcap
));
173 snprintf(pcap_filter
, sizeof(pcap_filter
),
174 "not ether src " MACSTR
" and "
175 "( ether dst " MACSTR
" or ether dst " MACSTR
" ) and "
177 MAC2STR(l2
->own_addr
), /* do not receive own packets */
178 MAC2STR(l2
->own_addr
), MAC2STR(pae_group_addr
),
180 if (pcap_compile(l2
->pcap
, &pcap_fp
, pcap_filter
, 1, pcap_netp
) < 0) {
181 fprintf(stderr
, "pcap_compile: %s\n", pcap_geterr(l2
->pcap
));
185 if (pcap_setfilter(l2
->pcap
, &pcap_fp
) < 0) {
186 fprintf(stderr
, "pcap_setfilter: %s\n", pcap_geterr(l2
->pcap
));
190 pcap_freecode(&pcap_fp
);
192 * When libpcap uses BPF we must enable "immediate mode" to
193 * receive frames right away; otherwise the system may
194 * buffer them for us.
196 { unsigned int on
= 1;
197 if (ioctl(pcap_fileno(l2
->pcap
), BIOCIMMEDIATE
, &on
) < 0) {
198 fprintf(stderr
, "%s: cannot enable immediate mode on "
199 "interface %s: %s\n",
200 __func__
, l2
->ifname
, strerror(errno
));
201 /* XXX should we fail? */
205 eloop_register_read_sock(pcap_get_selectable_fd(l2
->pcap
),
206 l2_packet_receive
, l2
, l2
->pcap
);
212 l2_packet_deinit_libpcap(struct l2_packet_data
*l2
)
214 if (l2
->pcap
!= NULL
) {
215 eloop_unregister_read_sock(pcap_get_selectable_fd(l2
->pcap
));
216 pcap_close(l2
->pcap
);
222 eth_get(const char *device
, u8 ea
[ETH_ALEN
])
224 struct if_msghdr
*ifm
;
225 struct sockaddr_dl
*sdl
;
228 int mib
[] = { CTL_NET
, AF_ROUTE
, 0, AF_LINK
, NET_RT_IFLIST
, 0 };
230 if (sysctl(mib
, 6, NULL
, &len
, NULL
, 0) < 0)
232 if ((buf
= malloc(len
)) == NULL
)
234 if (sysctl(mib
, 6, buf
, &len
, NULL
, 0) < 0) {
238 for (p
= buf
; p
< buf
+ len
; p
+= ifm
->ifm_msglen
) {
239 ifm
= (struct if_msghdr
*)p
;
240 sdl
= (struct sockaddr_dl
*)(ifm
+ 1);
241 if (ifm
->ifm_type
!= RTM_IFINFO
||
242 (ifm
->ifm_addrs
& RTA_IFP
) == 0)
244 if (sdl
->sdl_family
!= AF_LINK
|| sdl
->sdl_nlen
== 0 ||
245 memcmp(sdl
->sdl_data
, device
, sdl
->sdl_nlen
) != 0)
247 memcpy(ea
, LLADDR(sdl
), sdl
->sdl_alen
);
252 if (p
>= buf
+ len
) {
259 struct l2_packet_data
*
260 l2_packet_init(const char *ifname
, const u8
*own_addr
, unsigned short protocol
,
261 void (*rx_callback
)(void *ctx
, const u8
*src_addr
,
262 const u8
*buf
, size_t len
),
263 void *rx_callback_ctx
, int l2_hdr
)
265 struct l2_packet_data
*l2
;
267 l2
= malloc(sizeof(struct l2_packet_data
));
270 memset(l2
, 0, sizeof(*l2
));
271 strncpy(l2
->ifname
, ifname
, sizeof(l2
->ifname
));
272 l2
->rx_callback
= rx_callback
;
273 l2
->rx_callback_ctx
= rx_callback_ctx
;
276 if (eth_get(l2
->ifname
, l2
->own_addr
) < 0) {
277 fprintf(stderr
, "Failed to get link-level address for "
278 "interface '%s'.\n", l2
->ifname
);
283 if (l2_packet_init_libpcap(l2
, protocol
) != 0) {
291 l2_packet_deinit(struct l2_packet_data
*l2
)
294 l2_packet_deinit_libpcap(l2
);