2 * Wired Ethernet driver interface
3 * Copyright (c) 2005-2009, Jouni Malinen <j@w1.fi>
4 * Copyright (c) 2004, Gunter Burchardt <tira@isx.de>
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.
17 #include <sys/ioctl.h>
20 #include <netpacket/packet.h>
21 #include <net/if_arp.h>
23 #endif /* __linux__ */
24 #if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
25 #include <net/if_dl.h>
26 #endif /* defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__) */
46 static const u8 pae_group_addr
[ETH_ALEN
] =
47 { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 };
50 struct wpa_driver_wired_data
{
51 char ifname
[IFNAMSIZ
+ 1];
54 int sock
; /* raw packet socket for driver access */
55 int dhcp_sock
; /* socket for dhcp packets */
56 int use_pae_group_addr
;
59 int membership
, multi
, iff_allmulti
, iff_up
;
63 /* TODO: detecting new devices should eventually be changed from using DHCP
64 * snooping to trigger on any packet from a new layer 2 MAC address, e.g.,
65 * based on ebtables, etc. */
83 u_int8_t options
[308]; /* 312 - cookie */
87 static int wired_multicast_membership(int sock
, int ifindex
,
88 const u8
*addr
, int add
)
91 struct packet_mreq mreq
;
96 os_memset(&mreq
, 0, sizeof(mreq
));
97 mreq
.mr_ifindex
= ifindex
;
98 mreq
.mr_type
= PACKET_MR_MULTICAST
;
99 mreq
.mr_alen
= ETH_ALEN
;
100 os_memcpy(mreq
.mr_address
, addr
, ETH_ALEN
);
102 if (setsockopt(sock
, SOL_PACKET
,
103 add
? PACKET_ADD_MEMBERSHIP
: PACKET_DROP_MEMBERSHIP
,
104 &mreq
, sizeof(mreq
)) < 0) {
105 perror("setsockopt");
109 #else /* __linux__ */
111 #endif /* __linux__ */
116 static void handle_data(void *ctx
, unsigned char *buf
, size_t len
)
119 struct ieee8023_hdr
*hdr
;
122 union wpa_event_data event
;
124 /* must contain at least ieee8023_hdr 6 byte source, 6 byte dest,
125 * 2 byte ethertype */
127 wpa_printf(MSG_MSGDUMP
, "handle_data: too short (%lu)",
128 (unsigned long) len
);
132 hdr
= (struct ieee8023_hdr
*) buf
;
134 switch (ntohs(hdr
->ethertype
)) {
136 wpa_printf(MSG_MSGDUMP
, "Received EAPOL packet");
138 os_memset(&event
, 0, sizeof(event
));
139 event
.new_sta
.addr
= sa
;
140 wpa_supplicant_event(ctx
, EVENT_NEW_STA
, &event
);
142 pos
= (u8
*) (hdr
+ 1);
143 left
= len
- sizeof(*hdr
);
144 drv_event_eapol_rx(ctx
, sa
, pos
, left
);
148 wpa_printf(MSG_DEBUG
, "Unknown ethertype 0x%04x in data frame",
149 ntohs(hdr
->ethertype
));
156 static void handle_read(int sock
, void *eloop_ctx
, void *sock_ctx
)
159 unsigned char buf
[3000];
161 len
= recv(sock
, buf
, sizeof(buf
), 0);
167 handle_data(eloop_ctx
, buf
, len
);
171 static void handle_dhcp(int sock
, void *eloop_ctx
, void *sock_ctx
)
174 unsigned char buf
[3000];
175 struct dhcp_message
*msg
;
177 union wpa_event_data event
;
179 len
= recv(sock
, buf
, sizeof(buf
), 0);
185 /* must contain at least dhcp_message->chaddr */
187 wpa_printf(MSG_MSGDUMP
, "handle_dhcp: too short (%d)", len
);
191 msg
= (struct dhcp_message
*) buf
;
192 mac_address
= (u8
*) &(msg
->chaddr
);
194 wpa_printf(MSG_MSGDUMP
, "Got DHCP broadcast packet from " MACSTR
,
195 MAC2STR(mac_address
));
197 os_memset(&event
, 0, sizeof(event
));
198 event
.new_sta
.addr
= mac_address
;
199 wpa_supplicant_event(eloop_ctx
, EVENT_NEW_STA
, &event
);
201 #endif /* __linux__ */
204 static int wired_init_sockets(struct wpa_driver_wired_data
*drv
, u8
*own_addr
)
208 struct sockaddr_ll addr
;
209 struct sockaddr_in addr2
;
212 drv
->sock
= socket(PF_PACKET
, SOCK_RAW
, htons(ETH_P_PAE
));
214 perror("socket[PF_PACKET,SOCK_RAW]");
218 if (eloop_register_read_sock(drv
->sock
, handle_read
, drv
->ctx
, NULL
)) {
219 printf("Could not register read socket\n");
223 os_memset(&ifr
, 0, sizeof(ifr
));
224 os_strlcpy(ifr
.ifr_name
, drv
->ifname
, sizeof(ifr
.ifr_name
));
225 if (ioctl(drv
->sock
, SIOCGIFINDEX
, &ifr
) != 0) {
226 perror("ioctl(SIOCGIFINDEX)");
230 os_memset(&addr
, 0, sizeof(addr
));
231 addr
.sll_family
= AF_PACKET
;
232 addr
.sll_ifindex
= ifr
.ifr_ifindex
;
233 wpa_printf(MSG_DEBUG
, "Opening raw packet socket for ifindex %d",
236 if (bind(drv
->sock
, (struct sockaddr
*) &addr
, sizeof(addr
)) < 0) {
241 /* filter multicast address */
242 if (wired_multicast_membership(drv
->sock
, ifr
.ifr_ifindex
,
243 pae_group_addr
, 1) < 0) {
244 wpa_printf(MSG_ERROR
, "wired: Failed to add multicast group "
249 os_memset(&ifr
, 0, sizeof(ifr
));
250 os_strlcpy(ifr
.ifr_name
, drv
->ifname
, sizeof(ifr
.ifr_name
));
251 if (ioctl(drv
->sock
, SIOCGIFHWADDR
, &ifr
) != 0) {
252 perror("ioctl(SIOCGIFHWADDR)");
256 if (ifr
.ifr_hwaddr
.sa_family
!= ARPHRD_ETHER
) {
257 printf("Invalid HW-addr family 0x%04x\n",
258 ifr
.ifr_hwaddr
.sa_family
);
261 os_memcpy(own_addr
, ifr
.ifr_hwaddr
.sa_data
, ETH_ALEN
);
263 /* setup dhcp listen socket for sta detection */
264 if ((drv
->dhcp_sock
= socket(PF_INET
, SOCK_DGRAM
, IPPROTO_UDP
)) < 0) {
265 perror("socket call failed for dhcp");
269 if (eloop_register_read_sock(drv
->dhcp_sock
, handle_dhcp
, drv
->ctx
,
271 printf("Could not register read socket\n");
275 os_memset(&addr2
, 0, sizeof(addr2
));
276 addr2
.sin_family
= AF_INET
;
277 addr2
.sin_port
= htons(67);
278 addr2
.sin_addr
.s_addr
= INADDR_ANY
;
280 if (setsockopt(drv
->dhcp_sock
, SOL_SOCKET
, SO_REUSEADDR
, (char *) &n
,
282 perror("setsockopt[SOL_SOCKET,SO_REUSEADDR]");
285 if (setsockopt(drv
->dhcp_sock
, SOL_SOCKET
, SO_BROADCAST
, (char *) &n
,
287 perror("setsockopt[SOL_SOCKET,SO_BROADCAST]");
291 os_memset(&ifr
, 0, sizeof(ifr
));
292 os_strlcpy(ifr
.ifr_ifrn
.ifrn_name
, drv
->ifname
, IFNAMSIZ
);
293 if (setsockopt(drv
->dhcp_sock
, SOL_SOCKET
, SO_BINDTODEVICE
,
294 (char *) &ifr
, sizeof(ifr
)) < 0) {
295 perror("setsockopt[SOL_SOCKET,SO_BINDTODEVICE]");
299 if (bind(drv
->dhcp_sock
, (struct sockaddr
*) &addr2
,
300 sizeof(struct sockaddr
)) == -1) {
306 #else /* __linux__ */
308 #endif /* __linux__ */
312 static int wired_send_eapol(void *priv
, const u8
*addr
,
313 const u8
*data
, size_t data_len
, int encrypt
,
316 struct wpa_driver_wired_data
*drv
= priv
;
317 struct ieee8023_hdr
*hdr
;
322 len
= sizeof(*hdr
) + data_len
;
323 hdr
= os_zalloc(len
);
325 printf("malloc() failed for wired_send_eapol(len=%lu)\n",
326 (unsigned long) len
);
330 os_memcpy(hdr
->dest
, drv
->use_pae_group_addr
? pae_group_addr
: addr
,
332 os_memcpy(hdr
->src
, own_addr
, ETH_ALEN
);
333 hdr
->ethertype
= htons(ETH_P_PAE
);
335 pos
= (u8
*) (hdr
+ 1);
336 os_memcpy(pos
, data
, data_len
);
338 res
= send(drv
->sock
, (u8
*) hdr
, len
, 0);
342 perror("wired_send_eapol: send");
343 printf("wired_send_eapol - packet len: %lu - failed\n",
344 (unsigned long) len
);
351 static void * wired_driver_hapd_init(struct hostapd_data
*hapd
,
352 struct wpa_init_params
*params
)
354 struct wpa_driver_wired_data
*drv
;
356 drv
= os_zalloc(sizeof(struct wpa_driver_wired_data
));
358 printf("Could not allocate memory for wired driver data\n");
363 os_strlcpy(drv
->ifname
, params
->ifname
, sizeof(drv
->ifname
));
364 drv
->use_pae_group_addr
= params
->use_pae_group_addr
;
366 if (wired_init_sockets(drv
, params
->own_addr
)) {
375 static void wired_driver_hapd_deinit(void *priv
)
377 struct wpa_driver_wired_data
*drv
= priv
;
382 if (drv
->dhcp_sock
>= 0)
383 close(drv
->dhcp_sock
);
389 static int wpa_driver_wired_get_ssid(void *priv
, u8
*ssid
)
396 static int wpa_driver_wired_get_bssid(void *priv
, u8
*bssid
)
398 /* Report PAE group address as the "BSSID" for wired connection. */
399 os_memcpy(bssid
, pae_group_addr
, ETH_ALEN
);
404 static int wpa_driver_wired_get_capa(void *priv
, struct wpa_driver_capa
*capa
)
406 os_memset(capa
, 0, sizeof(*capa
));
407 capa
->flags
= WPA_DRIVER_FLAGS_WIRED
;
412 static int wpa_driver_wired_get_ifflags(const char *ifname
, int *flags
)
417 s
= socket(PF_INET
, SOCK_DGRAM
, 0);
423 os_memset(&ifr
, 0, sizeof(ifr
));
424 os_strlcpy(ifr
.ifr_name
, ifname
, IFNAMSIZ
);
425 if (ioctl(s
, SIOCGIFFLAGS
, (caddr_t
) &ifr
) < 0) {
426 perror("ioctl[SIOCGIFFLAGS]");
431 *flags
= ifr
.ifr_flags
& 0xffff;
436 static int wpa_driver_wired_set_ifflags(const char *ifname
, int flags
)
441 s
= socket(PF_INET
, SOCK_DGRAM
, 0);
447 os_memset(&ifr
, 0, sizeof(ifr
));
448 os_strlcpy(ifr
.ifr_name
, ifname
, IFNAMSIZ
);
449 ifr
.ifr_flags
= flags
& 0xffff;
450 if (ioctl(s
, SIOCSIFFLAGS
, (caddr_t
) &ifr
) < 0) {
451 perror("ioctl[SIOCSIFFLAGS]");
460 static int wpa_driver_wired_multi(const char *ifname
, const u8
*addr
, int add
)
465 s
= socket(PF_INET
, SOCK_DGRAM
, 0);
471 os_memset(&ifr
, 0, sizeof(ifr
));
472 os_strlcpy(ifr
.ifr_name
, ifname
, IFNAMSIZ
);
474 ifr
.ifr_hwaddr
.sa_family
= AF_UNSPEC
;
475 os_memcpy(ifr
.ifr_hwaddr
.sa_data
, addr
, ETH_ALEN
);
476 #endif /* __linux__ */
477 #if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
479 struct sockaddr_dl
*dlp
;
480 dlp
= (struct sockaddr_dl
*) &ifr
.ifr_addr
;
481 dlp
->sdl_len
= sizeof(struct sockaddr_dl
);
482 dlp
->sdl_family
= AF_LINK
;
485 dlp
->sdl_alen
= ETH_ALEN
;
487 os_memcpy(LLADDR(dlp
), addr
, ETH_ALEN
);
489 #endif /* defined(__FreeBSD__) || defined(__DragonFly__) || defined(FreeBSD_kernel__) */
490 #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
492 struct sockaddr
*sap
;
493 sap
= (struct sockaddr
*) &ifr
.ifr_addr
;
494 sap
->sa_len
= sizeof(struct sockaddr
);
495 sap
->sa_family
= AF_UNSPEC
;
496 os_memcpy(sap
->sa_data
, addr
, ETH_ALEN
);
498 #endif /* defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__) */
500 if (ioctl(s
, add
? SIOCADDMULTI
: SIOCDELMULTI
, (caddr_t
) &ifr
) < 0) {
501 perror("ioctl[SIOC{ADD/DEL}MULTI]");
510 static void * wpa_driver_wired_init(void *ctx
, const char *ifname
)
512 struct wpa_driver_wired_data
*drv
;
515 drv
= os_zalloc(sizeof(*drv
));
518 os_strlcpy(drv
->ifname
, ifname
, sizeof(drv
->ifname
));
522 drv
->pf_sock
= socket(PF_PACKET
, SOCK_DGRAM
, 0);
523 if (drv
->pf_sock
< 0)
524 perror("socket(PF_PACKET)");
525 #else /* __linux__ */
527 #endif /* __linux__ */
529 if (wpa_driver_wired_get_ifflags(ifname
, &flags
) == 0 &&
531 wpa_driver_wired_set_ifflags(ifname
, flags
| IFF_UP
) == 0) {
535 if (wired_multicast_membership(drv
->pf_sock
,
536 if_nametoindex(drv
->ifname
),
537 pae_group_addr
, 1) == 0) {
538 wpa_printf(MSG_DEBUG
, "%s: Added multicast membership with "
539 "packet socket", __func__
);
541 } else if (wpa_driver_wired_multi(ifname
, pae_group_addr
, 1) == 0) {
542 wpa_printf(MSG_DEBUG
, "%s: Added multicast membership with "
543 "SIOCADDMULTI", __func__
);
545 } else if (wpa_driver_wired_get_ifflags(ifname
, &flags
) < 0) {
546 wpa_printf(MSG_INFO
, "%s: Could not get interface "
550 } else if (flags
& IFF_ALLMULTI
) {
551 wpa_printf(MSG_DEBUG
, "%s: Interface is already configured "
552 "for multicast", __func__
);
553 } else if (wpa_driver_wired_set_ifflags(ifname
,
554 flags
| IFF_ALLMULTI
) < 0) {
555 wpa_printf(MSG_INFO
, "%s: Failed to enable allmulti",
560 wpa_printf(MSG_DEBUG
, "%s: Enabled allmulti mode",
562 drv
->iff_allmulti
= 1;
569 static void wpa_driver_wired_deinit(void *priv
)
571 struct wpa_driver_wired_data
*drv
= priv
;
574 if (drv
->membership
&&
575 wired_multicast_membership(drv
->pf_sock
,
576 if_nametoindex(drv
->ifname
),
577 pae_group_addr
, 0) < 0) {
578 wpa_printf(MSG_DEBUG
, "%s: Failed to remove PAE multicast "
579 "group (PACKET)", __func__
);
583 wpa_driver_wired_multi(drv
->ifname
, pae_group_addr
, 0) < 0) {
584 wpa_printf(MSG_DEBUG
, "%s: Failed to remove PAE multicast "
585 "group (SIOCDELMULTI)", __func__
);
588 if (drv
->iff_allmulti
&&
589 (wpa_driver_wired_get_ifflags(drv
->ifname
, &flags
) < 0 ||
590 wpa_driver_wired_set_ifflags(drv
->ifname
,
591 flags
& ~IFF_ALLMULTI
) < 0)) {
592 wpa_printf(MSG_DEBUG
, "%s: Failed to disable allmulti mode",
597 wpa_driver_wired_get_ifflags(drv
->ifname
, &flags
) == 0 &&
599 wpa_driver_wired_set_ifflags(drv
->ifname
, flags
& ~IFF_UP
) < 0) {
600 wpa_printf(MSG_DEBUG
, "%s: Failed to set the interface down",
604 if (drv
->pf_sock
!= -1)
611 const struct wpa_driver_ops wpa_driver_wired_ops
= {
613 .desc
= "Wired Ethernet driver",
614 .hapd_init
= wired_driver_hapd_init
,
615 .hapd_deinit
= wired_driver_hapd_deinit
,
616 .hapd_send_eapol
= wired_send_eapol
,
617 .get_ssid
= wpa_driver_wired_get_ssid
,
618 .get_bssid
= wpa_driver_wired_get_bssid
,
619 .get_capa
= wpa_driver_wired_get_capa
,
620 .init
= wpa_driver_wired_init
,
621 .deinit
= wpa_driver_wired_deinit
,