2 * WPA Supplicant - Layer2 packet handling with DragonFlyBSD
3 * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
4 * Copyright (c) 2005, Sam Leffler <sam@errno.com>
6 * This software may be distributed under the terms of the BSD license.
7 * See README for more details.
14 #include <sys/ioctl.h>
18 #include <sys/sysctl.h>
22 #include <net/if_dl.h>
23 #include <net/route.h>
24 #include <netinet/in.h>
28 #include "l2_packet.h"
31 static const u8 pae_group_addr
[ETH_ALEN
] =
32 { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 };
34 struct l2_packet_data
{
37 u8 own_addr
[ETH_ALEN
];
38 void (*rx_callback
)(void *ctx
, const u8
*src_addr
,
39 const u8
*buf
, size_t len
);
40 void *rx_callback_ctx
;
41 int l2_hdr
; /* whether to include layer 2 (Ethernet) header data
46 int l2_packet_get_own_addr(struct l2_packet_data
*l2
, u8
*addr
)
48 os_memcpy(addr
, l2
->own_addr
, ETH_ALEN
);
53 int l2_packet_send(struct l2_packet_data
*l2
, const u8
*dst_addr
, u16 proto
,
54 const u8
*buf
, size_t len
)
58 struct l2_ethhdr
*eth
= os_malloc(sizeof(*eth
) + len
);
61 os_memcpy(eth
->h_dest
, dst_addr
, ETH_ALEN
);
62 os_memcpy(eth
->h_source
, l2
->own_addr
, ETH_ALEN
);
63 eth
->h_proto
= htons(proto
);
64 os_memcpy(eth
+ 1, buf
, len
);
65 ret
= pcap_inject(l2
->pcap
, (u8
*) eth
, len
+ sizeof(*eth
));
69 return pcap_inject(l2
->pcap
, buf
, len
);
73 static void l2_packet_receive(int sock
, void *eloop_ctx
, void *sock_ctx
)
75 struct l2_packet_data
*l2
= eloop_ctx
;
76 pcap_t
*pcap
= sock_ctx
;
77 struct pcap_pkthdr hdr
;
79 struct l2_ethhdr
*ethhdr
;
83 packet
= pcap_next(pcap
, &hdr
);
85 if (packet
== NULL
|| hdr
.caplen
< sizeof(*ethhdr
))
88 ethhdr
= (struct l2_ethhdr
*) packet
;
90 buf
= (unsigned char *) ethhdr
;
93 buf
= (unsigned char *) (ethhdr
+ 1);
94 len
= hdr
.caplen
- sizeof(*ethhdr
);
96 l2
->rx_callback(l2
->rx_callback_ctx
, ethhdr
->h_source
, buf
, len
);
100 static int l2_packet_init_libpcap(struct l2_packet_data
*l2
,
101 unsigned short protocol
)
103 bpf_u_int32 pcap_maskp
, pcap_netp
;
104 char pcap_filter
[200], pcap_err
[PCAP_ERRBUF_SIZE
];
105 struct bpf_program pcap_fp
;
107 pcap_lookupnet(l2
->ifname
, &pcap_netp
, &pcap_maskp
, pcap_err
);
108 l2
->pcap
= pcap_open_live(l2
->ifname
, 2500, 0, 10, pcap_err
);
109 if (l2
->pcap
== NULL
) {
110 fprintf(stderr
, "pcap_open_live: %s\n", pcap_err
);
111 fprintf(stderr
, "ifname='%s'\n", l2
->ifname
);
114 if (pcap_datalink(l2
->pcap
) != DLT_EN10MB
&&
115 pcap_set_datalink(l2
->pcap
, DLT_EN10MB
) < 0) {
116 fprintf(stderr
, "pcap_set_datalink(DLT_EN10MB): %s\n",
117 pcap_geterr(l2
->pcap
));
120 os_snprintf(pcap_filter
, sizeof(pcap_filter
),
121 "not ether src " MACSTR
" and "
122 "( ether dst " MACSTR
" or ether dst " MACSTR
" ) and "
124 MAC2STR(l2
->own_addr
), /* do not receive own packets */
125 MAC2STR(l2
->own_addr
), MAC2STR(pae_group_addr
),
127 if (pcap_compile(l2
->pcap
, &pcap_fp
, pcap_filter
, 1, pcap_netp
) < 0) {
128 fprintf(stderr
, "pcap_compile: %s\n", pcap_geterr(l2
->pcap
));
132 if (pcap_setfilter(l2
->pcap
, &pcap_fp
) < 0) {
133 fprintf(stderr
, "pcap_setfilter: %s\n", pcap_geterr(l2
->pcap
));
137 pcap_freecode(&pcap_fp
);
140 * When libpcap uses BPF we must enable "immediate mode" to
141 * receive frames right away; otherwise the system may
142 * buffer them for us.
146 if (ioctl(pcap_fileno(l2
->pcap
), BIOCIMMEDIATE
, &on
) < 0) {
147 fprintf(stderr
, "%s: cannot enable immediate mode on "
148 "interface %s: %s\n",
149 __func__
, l2
->ifname
, strerror(errno
));
150 /* XXX should we fail? */
155 eloop_register_read_sock(pcap_get_selectable_fd(l2
->pcap
),
156 l2_packet_receive
, l2
, l2
->pcap
);
162 static int eth_get(const char *device
, u8 ea
[ETH_ALEN
])
166 u32 physaddrlen
= DLPI_PHYSADDR_MAX
;
167 u8 physaddr
[DLPI_PHYSADDR_MAX
];
170 retval
= dlpi_open(device
, &dh
, 0);
171 if (retval
!= DLPI_SUCCESS
) {
172 wpa_printf(MSG_ERROR
, "dlpi_open error: %s",
173 dlpi_strerror(retval
));
177 retval
= dlpi_get_physaddr(dh
, DL_CURR_PHYS_ADDR
, physaddr
,
179 if (retval
!= DLPI_SUCCESS
) {
180 wpa_printf(MSG_ERROR
, "dlpi_get_physaddr error: %s",
181 dlpi_strerror(retval
));
185 os_memcpy(ea
, physaddr
, ETH_ALEN
);
188 struct if_msghdr
*ifm
;
189 struct sockaddr_dl
*sdl
;
192 int mib
[] = { CTL_NET
, AF_ROUTE
, 0, AF_LINK
, NET_RT_IFLIST
, 0 };
194 if (sysctl(mib
, 6, NULL
, &len
, NULL
, 0) < 0)
196 if ((buf
= os_malloc(len
)) == NULL
)
198 if (sysctl(mib
, 6, buf
, &len
, NULL
, 0) < 0) {
202 for (p
= buf
; p
< buf
+ len
; p
+= ifm
->ifm_msglen
) {
203 ifm
= (struct if_msghdr
*)p
;
204 sdl
= (struct sockaddr_dl
*)(ifm
+ 1);
205 if (ifm
->ifm_type
!= RTM_IFINFO
||
206 (ifm
->ifm_addrs
& RTA_IFP
) == 0)
208 if (sdl
->sdl_family
!= AF_LINK
|| sdl
->sdl_nlen
== 0 ||
209 os_memcmp(sdl
->sdl_data
, device
, sdl
->sdl_nlen
) != 0)
211 os_memcpy(ea
, LLADDR(sdl
), sdl
->sdl_alen
);
216 if (p
>= buf
+ len
) {
225 struct l2_packet_data
* l2_packet_init(
226 const char *ifname
, const u8
*own_addr
, unsigned short protocol
,
227 void (*rx_callback
)(void *ctx
, const u8
*src_addr
,
228 const u8
*buf
, size_t len
),
229 void *rx_callback_ctx
, int l2_hdr
)
231 struct l2_packet_data
*l2
;
233 l2
= os_zalloc(sizeof(struct l2_packet_data
));
236 os_strlcpy(l2
->ifname
, ifname
, sizeof(l2
->ifname
));
237 l2
->rx_callback
= rx_callback
;
238 l2
->rx_callback_ctx
= rx_callback_ctx
;
241 if (eth_get(l2
->ifname
, l2
->own_addr
) < 0) {
242 fprintf(stderr
, "Failed to get link-level address for "
243 "interface '%s'.\n", l2
->ifname
);
248 if (l2_packet_init_libpcap(l2
, protocol
)) {
257 void l2_packet_deinit(struct l2_packet_data
*l2
)
261 eloop_unregister_read_sock(
262 pcap_get_selectable_fd(l2
->pcap
));
263 pcap_close(l2
->pcap
);
270 int l2_packet_get_ip_addr(struct l2_packet_data
*l2
, char *buf
, size_t len
)
272 pcap_if_t
*devs
, *dev
;
273 struct pcap_addr
*addr
;
274 struct sockaddr_in
*saddr
;
276 char err
[PCAP_ERRBUF_SIZE
+ 1];
278 if (pcap_findalldevs(&devs
, err
) < 0) {
279 wpa_printf(MSG_DEBUG
, "pcap_findalldevs: %s\n", err
);
283 for (dev
= devs
; dev
&& !found
; dev
= dev
->next
) {
284 if (os_strcmp(dev
->name
, l2
->ifname
) != 0)
287 addr
= dev
->addresses
;
289 saddr
= (struct sockaddr_in
*) addr
->addr
;
290 if (saddr
&& saddr
->sin_family
== AF_INET
) {
291 os_strlcpy(buf
, inet_ntoa(saddr
->sin_addr
),
300 pcap_freealldevs(devs
);
302 return found
? 0 : -1;
306 void l2_packet_notify_auth_start(struct l2_packet_data
*l2
)