diff --git a/src/drivers/driver_bsd.c b/src/drivers/driver_bsd.c index 84be779c3..dc8a2e4b8 100644 --- a/src/drivers/driver_bsd.c +++ b/src/drivers/driver_bsd.c @@ -22,6 +22,7 @@ #include "common/ieee802_11_defs.h" #include +#include #ifdef __NetBSD__ #include @@ -142,6 +143,55 @@ bsd_set_ssid(int s, const char *ifname, const u8 *ssid, size_t ssid_len) #endif } +static int +bsd_get_if_media(int s, const char *ifname) +{ + struct ifmediareq ifmr; + + os_memset(&ifmr, 0, sizeof(ifmr)); + os_strlcpy(ifmr.ifm_name, ifname, sizeof(ifmr.ifm_name)); + + if (ioctl(s, SIOCGIFMEDIA, &ifmr) < 0) { + wpa_printf(MSG_ERROR, "%s: SIOCGIFMEDIA %s", __func__, + strerror(errno)); + return -1; + } + + return ifmr.ifm_current; +} + +static int +bsd_set_if_media(int s, const char *ifname, int media) +{ + struct ifreq ifr; + + os_memset(&ifr, 0, sizeof(ifr)); + os_strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); + ifr.ifr_media = media; + + if (ioctl(s, SIOCSIFMEDIA, &ifr) < 0) { + wpa_printf(MSG_ERROR, "%s: SIOCSIFMEDIA %s", __func__, + strerror(errno)); + return -1; + } + + return 0; +} + +static int +bsd_set_mediaopt(int s, const char *ifname, uint32_t mask, uint32_t mode) +{ + int media = bsd_get_if_media(s, ifname); + + if (media < 0) + return -1; + media &= ~mask; + media |= mode; + if (bsd_set_if_media(s, ifname, media) < 0) + return -1; + return 0; +} + #ifdef HOSTAPD @@ -758,6 +808,32 @@ hostapd_bsd_set_ssid(const char *ifname, void *priv, const u8 *buf, int len) return bsd_set_ssid(drv->ioctl_sock, drv->iface, buf, len); } +static int +bsd_set_freq(void *priv, struct hostapd_freq_params *freq) +{ + struct bsd_driver_data *drv = priv; + struct ieee80211chanreq creq; + uint32_t mode; + + if (freq->channel < 14) + mode = IFM_IEEE80211_11G; + else if (freq->channel == 14) + mode = IFM_IEEE80211_11B; + else + mode = IFM_IEEE80211_11A; + if (bsd_set_mediaopt(drv->ioctl_sock, drv->iface, IFM_MMASK, + mode) < 0) { + wpa_printf(MSG_ERROR, "%s: failed to set modulation mode", + __func__); + return -1; + } + + os_memset(&creq, 0, sizeof(creq)); + os_strlcpy(creq.i_name, drv->iface, sizeof(creq.i_name)); + creq.i_channel = freq->channel; + return ioctl(drv->ioctl_sock, SIOCS80211CHANNEL, &creq); +} + static void * bsd_init(struct hostapd_data *hapd, struct wpa_init_params *params) { @@ -788,6 +864,13 @@ bsd_init(struct hostapd_data *hapd, struct wpa_init_params *params) if (bsd_wireless_event_init(drv)) goto bad; + if (bsd_set_mediaopt(drv->ioctl_sock, drv->iface, IFM_OMASK, + IFM_IEEE80211_HOSTAP) < 0) { + wpa_printf(MSG_ERROR, "%s: failed to set operation mode", + __func__); + goto bad; + } + return drv; bad: if (drv->sock_xmit != NULL) @@ -831,6 +914,7 @@ const struct wpa_driver_ops wpa_driver_bsd_ops = { .sta_deauth = bsd_sta_deauth, .hapd_set_ssid = hostapd_bsd_set_ssid, .hapd_get_ssid = hostapd_bsd_get_ssid, + .set_freq = bsd_set_freq, }; #else /* HOSTAPD */ @@ -1465,6 +1549,13 @@ wpa_driver_bsd_init(void *ctx, const char *ifname) __func__, strerror(errno)); goto fail; } + + if (bsd_set_mediaopt(drv->sock, drv->ifname, IFM_OMASK, + 0 /* STA */) < 0) { + wpa_printf(MSG_ERROR, "%s: failed to set operation mode", + __func__); + goto fail; + } if (set80211param(drv, IEEE80211_IOC_ROAMING, IEEE80211_ROAMING_MANUAL) < 0) { wpa_printf(MSG_DEBUG, "%s: failed to set wpa_supplicant-based " "roaming: %s", __func__, strerror(errno));