| @@ -6,27 +6,29 @@ | | | @@ -6,27 +6,29 @@ |
6 | * This software may be distributed under the terms of the BSD license. | | 6 | * This software may be distributed under the terms of the BSD license. |
7 | * See README for more details. | | 7 | * See README for more details. |
8 | */ | | 8 | */ |
9 | | | 9 | |
10 | #include "includes.h" | | 10 | #include "includes.h" |
11 | #include <sys/ioctl.h> | | 11 | #include <sys/ioctl.h> |
12 | | | 12 | |
13 | #include "common.h" | | 13 | #include "common.h" |
14 | #include "driver.h" | | 14 | #include "driver.h" |
15 | #include "eloop.h" | | 15 | #include "eloop.h" |
16 | #include "common/ieee802_11_defs.h" | | 16 | #include "common/ieee802_11_defs.h" |
17 | #include "common/wpa_common.h" | | 17 | #include "common/wpa_common.h" |
18 | | | 18 | |
| | | 19 | #include <ifaddrs.h> |
19 | #include <net/if.h> | | 20 | #include <net/if.h> |
| | | 21 | #include <net/if_dl.h> |
20 | #include <net/if_media.h> | | 22 | #include <net/if_media.h> |
21 | | | 23 | |
22 | #ifdef __NetBSD__ | | 24 | #ifdef __NetBSD__ |
23 | #include <net/if_ether.h> | | 25 | #include <net/if_ether.h> |
24 | #else | | 26 | #else |
25 | #include <net/ethernet.h> | | 27 | #include <net/ethernet.h> |
26 | #endif | | 28 | #endif |
27 | #include <net/route.h> | | 29 | #include <net/route.h> |
28 | | | 30 | |
29 | #ifdef __DragonFly__ | | 31 | #ifdef __DragonFly__ |
30 | #include <netproto/802_11/ieee80211_ioctl.h> | | 32 | #include <netproto/802_11/ieee80211_ioctl.h> |
31 | #include <netproto/802_11/ieee80211_dragonfly.h> | | 33 | #include <netproto/802_11/ieee80211_dragonfly.h> |
32 | #else /* __DragonFly__ */ | | 34 | #else /* __DragonFly__ */ |
| @@ -605,46 +607,152 @@ bsd_set_freq(void *priv, struct hostapd_ | | | @@ -605,46 +607,152 @@ bsd_set_freq(void *priv, struct hostapd_ |
605 | | | 607 | |
606 | static int | | 608 | static int |
607 | bsd_set_opt_ie(void *priv, const u8 *ie, size_t ie_len) | | 609 | bsd_set_opt_ie(void *priv, const u8 *ie, size_t ie_len) |
608 | { | | 610 | { |
609 | #ifdef IEEE80211_IOC_APPIE | | 611 | #ifdef IEEE80211_IOC_APPIE |
610 | wpa_printf(MSG_DEBUG, "%s: set WPA+RSN ie (len %lu)", __func__, | | 612 | wpa_printf(MSG_DEBUG, "%s: set WPA+RSN ie (len %lu)", __func__, |
611 | (unsigned long)ie_len); | | 613 | (unsigned long)ie_len); |
612 | return bsd_set80211(priv, IEEE80211_IOC_APPIE, IEEE80211_APPIE_WPA, | | 614 | return bsd_set80211(priv, IEEE80211_IOC_APPIE, IEEE80211_APPIE_WPA, |
613 | ie, ie_len); | | 615 | ie, ie_len); |
614 | #endif /* IEEE80211_IOC_APPIE */ | | 616 | #endif /* IEEE80211_IOC_APPIE */ |
615 | return 0; | | 617 | return 0; |
616 | } | | 618 | } |
617 | | | 619 | |
| | | 620 | #ifdef SO_RERROR |
| | | 621 | static void |
| | | 622 | bsd_route_overflow(int sock, void *ctx, struct bsd_driver_global *global) |
| | | 623 | { |
| | | 624 | char event_buf[2048]; /* max size of a single route(4) msg */ |
| | | 625 | int n; |
| | | 626 | struct ifaddrs *ifaddrs, *ifa; |
| | | 627 | struct bsd_driver_data *drv; |
| | | 628 | struct sockaddr_dl *sdl; |
| | | 629 | union wpa_event_data event; |
| | | 630 | |
| | | 631 | /* We need to match the system state, so drain the route |
| | | 632 | * socket to avoid stale messages. */ |
| | | 633 | do { |
| | | 634 | n = read(sock, event_buf, sizeof(event_buf)); |
| | | 635 | } while (n != -1 || errno == ENOBUFS); |
| | | 636 | |
| | | 637 | if (getifaddrs(&ifaddrs) == -1) { |
| | | 638 | wpa_printf(MSG_ERROR, "%s getifaddrs() failed: %s", |
| | | 639 | __func__, strerror(errno)); |
| | | 640 | return; |
| | | 641 | } |
| | | 642 | |
| | | 643 | /* add or update existing interfaces */ |
| | | 644 | for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) { |
| | | 645 | if (ifa->ifa_addr == NULL || |
| | | 646 | ifa->ifa_addr->sa_family != AF_LINK) |
| | | 647 | continue; |
| | | 648 | sdl = (struct sockaddr_dl *)(void *)ifa->ifa_addr; |
| | | 649 | drv = bsd_get_drvname(global, ifa->ifa_name); |
| | | 650 | if (drv != NULL && |
| | | 651 | (drv->ifindex != sdl->sdl_index || drv->if_removed)) { |
| | | 652 | wpa_printf(MSG_DEBUG, |
| | | 653 | "RTM_IFANNOUNCE: Interface '%s' added", |
| | | 654 | drv->ifname); |
| | | 655 | drv->ifindex = sdl->sdl_index; |
| | | 656 | drv->if_removed = 0; |
| | | 657 | event.interface_status.ievent = EVENT_INTERFACE_ADDED; |
| | | 658 | os_strlcpy(event.interface_status.ifname, ifa->ifa_name, |
| | | 659 | sizeof(event.interface_status.ifname)); |
| | | 660 | wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, |
| | | 661 | &event); |
| | | 662 | } |
| | | 663 | if (drv == NULL && |
| | | 664 | (drv = bsd_get_drvindex(global, sdl->sdl_index)) != NULL) { |
| | | 665 | /* Driver name is invalid */ |
| | | 666 | wpa_printf(MSG_DEBUG, |
| | | 667 | "RTM_IFANNOUNCE: Interface '%s' removed", |
| | | 668 | drv->ifname); |
| | | 669 | drv->if_removed = 1; |
| | | 670 | event.interface_status.ievent = EVENT_INTERFACE_REMOVED; |
| | | 671 | os_strlcpy(event.interface_status.ifname, drv->ifname, |
| | | 672 | sizeof(event.interface_status.ifname)); |
| | | 673 | wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, |
| | | 674 | &event); |
| | | 675 | } |
| | | 676 | } |
| | | 677 | |
| | | 678 | /* punt missing interfaces and update flags */ |
| | | 679 | dl_list_for_each(drv, &global->ifaces, struct bsd_driver_data, list) { |
| | | 680 | for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) { |
| | | 681 | if (ifa->ifa_addr == NULL || |
| | | 682 | ifa->ifa_addr->sa_family != AF_LINK) |
| | | 683 | continue; |
| | | 684 | sdl = (struct sockaddr_dl *)(void *)ifa->ifa_addr; |
| | | 685 | if (os_strcmp(drv->ifname, ifa->ifa_name) == 0) |
| | | 686 | break; |
| | | 687 | } |
| | | 688 | if (ifa == NULL && !drv->if_removed) { |
| | | 689 | wpa_printf(MSG_DEBUG, |
| | | 690 | "RTM_IFANNOUNCE: Interface '%s' removed", |
| | | 691 | drv->ifname); |
| | | 692 | drv->if_removed = 1; |
| | | 693 | event.interface_status.ievent = EVENT_INTERFACE_REMOVED; |
| | | 694 | os_strlcpy(event.interface_status.ifname, drv->ifname, |
| | | 695 | sizeof(event.interface_status.ifname)); |
| | | 696 | wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, |
| | | 697 | &event); |
| | | 698 | } |
| | | 699 | if (ifa == NULL) |
| | | 700 | continue; |
| | | 701 | |
| | | 702 | if ((ifa->ifa_flags & IFF_UP) == 0 && |
| | | 703 | (drv->flags & IFF_UP) != 0) { |
| | | 704 | wpa_printf(MSG_DEBUG, "RTM_IFINFO: Interface '%s' DOWN", |
| | | 705 | drv->ifname); |
| | | 706 | wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_DISABLED, |
| | | 707 | NULL); |
| | | 708 | } else if ((ifa->ifa_flags & IFF_UP) != 0 && |
| | | 709 | (drv->flags & IFF_UP) == 0) { |
| | | 710 | wpa_printf(MSG_DEBUG, "RTM_IFINFO: Interface '%s' UP", |
| | | 711 | drv->ifname); |
| | | 712 | wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED, |
| | | 713 | NULL); |
| | | 714 | } |
| | | 715 | drv->flags = ifa->ifa_flags; |
| | | 716 | } |
| | | 717 | |
| | | 718 | freeifaddrs(ifaddrs); |
| | | 719 | } |
| | | 720 | #endif |
| | | 721 | |
618 | static void | | 722 | static void |
619 | bsd_wireless_event_receive(int sock, void *ctx, void *sock_ctx) | | 723 | bsd_wireless_event_receive(int sock, void *ctx, void *sock_ctx) |
620 | { | | 724 | { |
621 | char event_buf[2048]; /* max size of a single route(4) msg */ | | 725 | char event_buf[2048]; /* max size of a single route(4) msg */ |
622 | struct bsd_driver_global *global = sock_ctx; | | 726 | struct bsd_driver_global *global = sock_ctx; |
623 | struct bsd_driver_data *drv; | | 727 | struct bsd_driver_data *drv; |
624 | struct if_announcemsghdr *ifan; | | 728 | struct if_announcemsghdr *ifan; |
625 | struct if_msghdr *ifm; | | 729 | struct if_msghdr *ifm; |
626 | struct rt_msghdr *rtm; | | 730 | struct rt_msghdr *rtm; |
627 | union wpa_event_data event; | | 731 | union wpa_event_data event; |
628 | struct ieee80211_michael_event *mic; | | 732 | struct ieee80211_michael_event *mic; |
629 | struct ieee80211_leave_event *leave; | | 733 | struct ieee80211_leave_event *leave; |
630 | struct ieee80211_join_event *join; | | 734 | struct ieee80211_join_event *join; |
631 | int n; | | 735 | int n; |
632 | | | 736 | |
633 | n = read(sock, event_buf, sizeof(event_buf)); | | 737 | n = read(sock, event_buf, sizeof(event_buf)); |
634 | if (n < 0) { | | 738 | if (n < 0) { |
635 | if (errno != EINTR && errno != EAGAIN) | | 739 | if (errno != EINTR && errno != EAGAIN) |
636 | wpa_printf(MSG_ERROR, "%s read() failed: %s", | | 740 | wpa_printf(MSG_ERROR, "%s read() failed: %s", |
637 | __func__, strerror(errno)); | | 741 | __func__, strerror(errno)); |
| | | 742 | #ifdef SO_RERROR |
| | | 743 | if (errno == ENOBUFS) |
| | | 744 | bsd_route_overflow(sock, ctx, sock_ctx); |
| | | 745 | #endif |
638 | return; | | 746 | return; |
639 | } | | 747 | } |
640 | | | 748 | |
641 | rtm = (struct rt_msghdr *) event_buf; | | 749 | rtm = (struct rt_msghdr *) event_buf; |
642 | if (rtm->rtm_version != RTM_VERSION) { | | 750 | if (rtm->rtm_version != RTM_VERSION) { |
643 | wpa_printf(MSG_DEBUG, "Invalid routing message version=%d", | | 751 | wpa_printf(MSG_DEBUG, "Invalid routing message version=%d", |
644 | rtm->rtm_version); | | 752 | rtm->rtm_version); |
645 | return; | | 753 | return; |
646 | } | | 754 | } |
647 | os_memset(&event, 0, sizeof(event)); | | 755 | os_memset(&event, 0, sizeof(event)); |
648 | switch (rtm->rtm_type) { | | 756 | switch (rtm->rtm_type) { |
649 | case RTM_IEEE80211: | | 757 | case RTM_IEEE80211: |
650 | ifan = (struct if_announcemsghdr *) rtm; | | 758 | ifan = (struct if_announcemsghdr *) rtm; |
| @@ -1550,34 +1658,34 @@ bsd_global_init(void *ctx) | | | @@ -1550,34 +1658,34 @@ bsd_global_init(void *ctx) |
1550 | unsigned char msgfilter[] = { | | 1658 | unsigned char msgfilter[] = { |
1551 | RTM_IEEE80211, | | 1659 | RTM_IEEE80211, |
1552 | RTM_IFINFO, RTM_IFANNOUNCE, | | 1660 | RTM_IFINFO, RTM_IFANNOUNCE, |
1553 | }; | | 1661 | }; |
1554 | #endif | | 1662 | #endif |
1555 | | | 1663 | |
1556 | global = os_zalloc(sizeof(*global)); | | 1664 | global = os_zalloc(sizeof(*global)); |
1557 | if (global == NULL) | | 1665 | if (global == NULL) |
1558 | return NULL; | | 1666 | return NULL; |
1559 | | | 1667 | |
1560 | global->ctx = ctx; | | 1668 | global->ctx = ctx; |
1561 | dl_list_init(&global->ifaces); | | 1669 | dl_list_init(&global->ifaces); |
1562 | | | 1670 | |
1563 | global->sock = socket(PF_INET, SOCK_DGRAM, 0); | | 1671 | global->sock = socket(PF_INET, SOCK_DGRAM|SOCK_CLOEXEC, 0); |
1564 | if (global->sock < 0) { | | 1672 | if (global->sock < 0) { |
1565 | wpa_printf(MSG_ERROR, "socket[PF_INET,SOCK_DGRAM]: %s", | | 1673 | wpa_printf(MSG_ERROR, "socket[PF_INET,SOCK_DGRAM]: %s", |
1566 | strerror(errno)); | | 1674 | strerror(errno)); |
1567 | goto fail1; | | 1675 | goto fail1; |
1568 | } | | 1676 | } |
1569 | | | 1677 | |
1570 | global->route = socket(PF_ROUTE, SOCK_RAW, 0); | | 1678 | global->route = socket(PF_ROUTE, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); |
1571 | if (global->route < 0) { | | 1679 | if (global->route < 0) { |
1572 | wpa_printf(MSG_ERROR, "socket[PF_ROUTE,SOCK_RAW]: %s", | | 1680 | wpa_printf(MSG_ERROR, "socket[PF_ROUTE,SOCK_RAW]: %s", |
1573 | strerror(errno)); | | 1681 | strerror(errno)); |
1574 | goto fail; | | 1682 | goto fail; |
1575 | } | | 1683 | } |
1576 | | | 1684 | |
1577 | #ifdef RO_MSGFILTER | | 1685 | #ifdef RO_MSGFILTER |
1578 | if (setsockopt(global->route, PF_ROUTE, RO_MSGFILTER, | | 1686 | if (setsockopt(global->route, PF_ROUTE, RO_MSGFILTER, |
1579 | &msgfilter, sizeof(msgfilter)) < 0) | | 1687 | &msgfilter, sizeof(msgfilter)) < 0) |
1580 | wpa_printf(MSG_ERROR, "socket[PF_ROUTE,RO_MSGFILTER]: %s", | | 1688 | wpa_printf(MSG_ERROR, "socket[PF_ROUTE,RO_MSGFILTER]: %s", |
1581 | strerror(errno)); | | 1689 | strerror(errno)); |
1582 | #endif | | 1690 | #endif |
1583 | | | 1691 | |