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__)
25 #include <net/if_dl.h>
26 #endif /* defined(__FreeBSD__) || defined(__DragonFly__) */
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__ */
115 static void handle_data(void *ctx
, unsigned char *buf
, size_t len
)
118 struct ieee8023_hdr
*hdr
;
121 union wpa_event_data event
;
123 /* must contain at least ieee8023_hdr 6 byte source, 6 byte dest,
124 * 2 byte ethertype */
126 wpa_printf(MSG_MSGDUMP
, "handle_data: too short (%lu)",
127 (unsigned long) len
);
131 hdr
= (struct ieee8023_hdr
*) buf
;
133 switch (ntohs(hdr
->ethertype
)) {
135 wpa_printf(MSG_MSGDUMP
, "Received EAPOL packet");
137 os_memset(&event
, 0, sizeof(event
));
138 event
.new_sta
.addr
= sa
;
139 wpa_supplicant_event(ctx
, EVENT_NEW_STA
, &event
);
141 pos
= (u8
*) (hdr
+ 1);
142 left
= len
- sizeof(*hdr
);
143 drv_event_eapol_rx(ctx
, sa
, pos
, left
);
147 wpa_printf(MSG_DEBUG
, "Unknown ethertype 0x%04x in data frame",
148 ntohs(hdr
->ethertype
));
155 static void handle_read(int sock
, void *eloop_ctx
, void *sock_ctx
)
158 unsigned char buf
[3000];
160 len
= recv(sock
, buf
, sizeof(buf
), 0);
166 handle_data(eloop_ctx
, buf
, len
);
170 static void handle_dhcp(int sock
, void *eloop_ctx
, void *sock_ctx
)
173 unsigned char buf
[3000];
174 struct dhcp_message
*msg
;
176 union wpa_event_data event
;
178 len
= recv(sock
, buf
, sizeof(buf
), 0);
184 /* must contain at least dhcp_message->chaddr */
186 wpa_printf(MSG_MSGDUMP
, "handle_dhcp: too short (%d)", len
);
190 msg
= (struct dhcp_message
*) buf
;
191 mac_address
= (u8
*) &(msg
->chaddr
);
193 wpa_printf(MSG_MSGDUMP
, "Got DHCP broadcast packet from " MACSTR
,
194 MAC2STR(mac_address
));
196 os_memset(&event
, 0, sizeof(event
));
197 event
.new_sta
.addr
= mac_address
;
198 wpa_supplicant_event(eloop_ctx
, EVENT_NEW_STA
, &event
);
202 static int wired_init_sockets(struct wpa_driver_wired_data
*drv
, u8
*own_addr
)
205 struct sockaddr_ll addr
;
206 struct sockaddr_in addr2
;
209 drv
->sock
= socket(PF_PACKET
, SOCK_RAW
, htons(ETH_P_PAE
));
211 perror("socket[PF_PACKET,SOCK_RAW]");
215 if (eloop_register_read_sock(drv
->sock
, handle_read
, drv
->ctx
, NULL
)) {
216 printf("Could not register read socket\n");
220 os_memset(&ifr
, 0, sizeof(ifr
));
221 os_strlcpy(ifr
.ifr_name
, drv
->ifname
, sizeof(ifr
.ifr_name
));
222 if (ioctl(drv
->sock
, SIOCGIFINDEX
, &ifr
) != 0) {
223 perror("ioctl(SIOCGIFINDEX)");
227 os_memset(&addr
, 0, sizeof(addr
));
228 addr
.sll_family
= AF_PACKET
;
229 addr
.sll_ifindex
= ifr
.ifr_ifindex
;
230 wpa_printf(MSG_DEBUG
, "Opening raw packet socket for ifindex %d",
233 if (bind(drv
->sock
, (struct sockaddr
*) &addr
, sizeof(addr
)) < 0) {
238 /* filter multicast address */
239 if (wired_multicast_membership(drv
->sock
, ifr
.ifr_ifindex
,
240 pae_group_addr
, 1) < 0) {
241 wpa_printf(MSG_ERROR
, "wired: Failed to add multicast group "
246 os_memset(&ifr
, 0, sizeof(ifr
));
247 os_strlcpy(ifr
.ifr_name
, drv
->ifname
, sizeof(ifr
.ifr_name
));
248 if (ioctl(drv
->sock
, SIOCGIFHWADDR
, &ifr
) != 0) {
249 perror("ioctl(SIOCGIFHWADDR)");
253 if (ifr
.ifr_hwaddr
.sa_family
!= ARPHRD_ETHER
) {
254 printf("Invalid HW-addr family 0x%04x\n",
255 ifr
.ifr_hwaddr
.sa_family
);
258 os_memcpy(own_addr
, ifr
.ifr_hwaddr
.sa_data
, ETH_ALEN
);
260 /* setup dhcp listen socket for sta detection */
261 if ((drv
->dhcp_sock
= socket(PF_INET
, SOCK_DGRAM
, IPPROTO_UDP
)) < 0) {
262 perror("socket call failed for dhcp");
266 if (eloop_register_read_sock(drv
->dhcp_sock
, handle_dhcp
, drv
->ctx
,
268 printf("Could not register read socket\n");
272 os_memset(&addr2
, 0, sizeof(addr2
));
273 addr2
.sin_family
= AF_INET
;
274 addr2
.sin_port
= htons(67);
275 addr2
.sin_addr
.s_addr
= INADDR_ANY
;
277 if (setsockopt(drv
->dhcp_sock
, SOL_SOCKET
, SO_REUSEADDR
, (char *) &n
,
279 perror("setsockopt[SOL_SOCKET,SO_REUSEADDR]");
282 if (setsockopt(drv
->dhcp_sock
, SOL_SOCKET
, SO_BROADCAST
, (char *) &n
,
284 perror("setsockopt[SOL_SOCKET,SO_BROADCAST]");
288 os_memset(&ifr
, 0, sizeof(ifr
));
289 os_strlcpy(ifr
.ifr_ifrn
.ifrn_name
, drv
->ifname
, IFNAMSIZ
);
290 if (setsockopt(drv
->dhcp_sock
, SOL_SOCKET
, SO_BINDTODEVICE
,
291 (char *) &ifr
, sizeof(ifr
)) < 0) {
292 perror("setsockopt[SOL_SOCKET,SO_BINDTODEVICE]");
296 if (bind(drv
->dhcp_sock
, (struct sockaddr
*) &addr2
,
297 sizeof(struct sockaddr
)) == -1) {
306 static int wired_send_eapol(void *priv
, const u8
*addr
,
307 const u8
*data
, size_t data_len
, int encrypt
,
310 struct wpa_driver_wired_data
*drv
= priv
;
311 struct ieee8023_hdr
*hdr
;
316 len
= sizeof(*hdr
) + data_len
;
317 hdr
= os_zalloc(len
);
319 printf("malloc() failed for wired_send_eapol(len=%lu)\n",
320 (unsigned long) len
);
324 os_memcpy(hdr
->dest
, drv
->use_pae_group_addr
? pae_group_addr
: addr
,
326 os_memcpy(hdr
->src
, own_addr
, ETH_ALEN
);
327 hdr
->ethertype
= htons(ETH_P_PAE
);
329 pos
= (u8
*) (hdr
+ 1);
330 os_memcpy(pos
, data
, data_len
);
332 res
= send(drv
->sock
, (u8
*) hdr
, len
, 0);
336 perror("wired_send_eapol: send");
337 printf("wired_send_eapol - packet len: %lu - failed\n",
338 (unsigned long) len
);
345 static void * wired_driver_hapd_init(struct hostapd_data
*hapd
,
346 struct wpa_init_params
*params
)
348 struct wpa_driver_wired_data
*drv
;
350 drv
= os_zalloc(sizeof(struct wpa_driver_wired_data
));
352 printf("Could not allocate memory for wired driver data\n");
357 os_strlcpy(drv
->ifname
, params
->ifname
, sizeof(drv
->ifname
));
358 drv
->use_pae_group_addr
= params
->use_pae_group_addr
;
360 if (wired_init_sockets(drv
, params
->own_addr
)) {
369 static void wired_driver_hapd_deinit(void *priv
)
371 struct wpa_driver_wired_data
*drv
= priv
;
376 if (drv
->dhcp_sock
>= 0)
377 close(drv
->dhcp_sock
);
383 static int wpa_driver_wired_get_ssid(void *priv
, u8
*ssid
)
390 static int wpa_driver_wired_get_bssid(void *priv
, u8
*bssid
)
392 /* Report PAE group address as the "BSSID" for wired connection. */
393 os_memcpy(bssid
, pae_group_addr
, ETH_ALEN
);
398 static int wpa_driver_wired_get_capa(void *priv
, struct wpa_driver_capa
*capa
)
400 os_memset(capa
, 0, sizeof(*capa
));
401 capa
->flags
= WPA_DRIVER_FLAGS_WIRED
;
406 static int wpa_driver_wired_get_ifflags(const char *ifname
, int *flags
)
411 s
= socket(PF_INET
, SOCK_DGRAM
, 0);
417 os_memset(&ifr
, 0, sizeof(ifr
));
418 os_strlcpy(ifr
.ifr_name
, ifname
, IFNAMSIZ
);
419 if (ioctl(s
, SIOCGIFFLAGS
, (caddr_t
) &ifr
) < 0) {
420 perror("ioctl[SIOCGIFFLAGS]");
425 *flags
= ifr
.ifr_flags
& 0xffff;
430 static int wpa_driver_wired_set_ifflags(const char *ifname
, int flags
)
435 s
= socket(PF_INET
, SOCK_DGRAM
, 0);
441 os_memset(&ifr
, 0, sizeof(ifr
));
442 os_strlcpy(ifr
.ifr_name
, ifname
, IFNAMSIZ
);
443 ifr
.ifr_flags
= flags
& 0xffff;
444 if (ioctl(s
, SIOCSIFFLAGS
, (caddr_t
) &ifr
) < 0) {
445 perror("ioctl[SIOCSIFFLAGS]");
454 static int wpa_driver_wired_multi(const char *ifname
, const u8
*addr
, int add
)
459 s
= socket(PF_INET
, SOCK_DGRAM
, 0);
465 os_memset(&ifr
, 0, sizeof(ifr
));
466 os_strlcpy(ifr
.ifr_name
, ifname
, IFNAMSIZ
);
468 ifr
.ifr_hwaddr
.sa_family
= AF_UNSPEC
;
469 os_memcpy(ifr
.ifr_hwaddr
.sa_data
, addr
, ETH_ALEN
);
470 #endif /* __linux__ */
471 #if defined(__FreeBSD__) || defined(__DragonFly__)
473 struct sockaddr_dl
*dlp
;
474 dlp
= (struct sockaddr_dl
*) &ifr
.ifr_addr
;
475 dlp
->sdl_len
= sizeof(struct sockaddr_dl
);
476 dlp
->sdl_family
= AF_LINK
;
479 dlp
->sdl_alen
= ETH_ALEN
;
481 os_memcpy(LLADDR(dlp
), addr
, ETH_ALEN
);
483 #endif /* defined(__FreeBSD__) || defined(__DragonFly__) */
484 #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
486 struct sockaddr
*sap
;
487 sap
= (struct sockaddr
*) &ifr
.ifr_addr
;
488 sap
->sa_len
= sizeof(struct sockaddr
);
489 sap
->sa_family
= AF_UNSPEC
;
490 os_memcpy(sap
->sa_data
, addr
, ETH_ALEN
);
492 #endif /* defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__) */
494 if (ioctl(s
, add
? SIOCADDMULTI
: SIOCDELMULTI
, (caddr_t
) &ifr
) < 0) {
495 perror("ioctl[SIOC{ADD/DEL}MULTI]");
504 static void * wpa_driver_wired_init(void *ctx
, const char *ifname
)
506 struct wpa_driver_wired_data
*drv
;
509 drv
= os_zalloc(sizeof(*drv
));
512 os_strlcpy(drv
->ifname
, ifname
, sizeof(drv
->ifname
));
516 drv
->pf_sock
= socket(PF_PACKET
, SOCK_DGRAM
, 0);
517 if (drv
->pf_sock
< 0)
518 perror("socket(PF_PACKET)");
519 #else /* __linux__ */
521 #endif /* __linux__ */
523 if (wpa_driver_wired_get_ifflags(ifname
, &flags
) == 0 &&
525 wpa_driver_wired_set_ifflags(ifname
, flags
| IFF_UP
) == 0) {
529 if (wired_multicast_membership(drv
->pf_sock
,
530 if_nametoindex(drv
->ifname
),
531 pae_group_addr
, 1) == 0) {
532 wpa_printf(MSG_DEBUG
, "%s: Added multicast membership with "
533 "packet socket", __func__
);
535 } else if (wpa_driver_wired_multi(ifname
, pae_group_addr
, 1) == 0) {
536 wpa_printf(MSG_DEBUG
, "%s: Added multicast membership with "
537 "SIOCADDMULTI", __func__
);
539 } else if (wpa_driver_wired_get_ifflags(ifname
, &flags
) < 0) {
540 wpa_printf(MSG_INFO
, "%s: Could not get interface "
544 } else if (flags
& IFF_ALLMULTI
) {
545 wpa_printf(MSG_DEBUG
, "%s: Interface is already configured "
546 "for multicast", __func__
);
547 } else if (wpa_driver_wired_set_ifflags(ifname
,
548 flags
| IFF_ALLMULTI
) < 0) {
549 wpa_printf(MSG_INFO
, "%s: Failed to enable allmulti",
554 wpa_printf(MSG_DEBUG
, "%s: Enabled allmulti mode",
556 drv
->iff_allmulti
= 1;
563 static void wpa_driver_wired_deinit(void *priv
)
565 struct wpa_driver_wired_data
*drv
= priv
;
568 if (drv
->membership
&&
569 wired_multicast_membership(drv
->pf_sock
,
570 if_nametoindex(drv
->ifname
),
571 pae_group_addr
, 0) < 0) {
572 wpa_printf(MSG_DEBUG
, "%s: Failed to remove PAE multicast "
573 "group (PACKET)", __func__
);
577 wpa_driver_wired_multi(drv
->ifname
, pae_group_addr
, 0) < 0) {
578 wpa_printf(MSG_DEBUG
, "%s: Failed to remove PAE multicast "
579 "group (SIOCDELMULTI)", __func__
);
582 if (drv
->iff_allmulti
&&
583 (wpa_driver_wired_get_ifflags(drv
->ifname
, &flags
) < 0 ||
584 wpa_driver_wired_set_ifflags(drv
->ifname
,
585 flags
& ~IFF_ALLMULTI
) < 0)) {
586 wpa_printf(MSG_DEBUG
, "%s: Failed to disable allmulti mode",
591 wpa_driver_wired_get_ifflags(drv
->ifname
, &flags
) == 0 &&
593 wpa_driver_wired_set_ifflags(drv
->ifname
, flags
& ~IFF_UP
) < 0) {
594 wpa_printf(MSG_DEBUG
, "%s: Failed to set the interface down",
598 if (drv
->pf_sock
!= -1)
605 const struct wpa_driver_ops wpa_driver_wired_ops
= {
607 .desc
= "Wired Ethernet driver",
608 .hapd_init
= wired_driver_hapd_init
,
609 .hapd_deinit
= wired_driver_hapd_deinit
,
610 .hapd_send_eapol
= wired_send_eapol
,
611 .get_ssid
= wpa_driver_wired_get_ssid
,
612 .get_bssid
= wpa_driver_wired_get_bssid
,
613 .get_capa
= wpa_driver_wired_get_capa
,
614 .init
= wpa_driver_wired_init
,
615 .deinit
= wpa_driver_wired_deinit
,