wpa_printf(MSG_DEBUG, "Wireless event: new AP: "
MACSTR,
MAC2STR((u8 *) iwe->u.ap_addr.sa_data));
- if (os_memcmp(iwe->u.ap_addr.sa_data,
- "\x00\x00\x00\x00\x00\x00", ETH_ALEN) ==
- 0 ||
+ if (is_zero_ether_addr(
+ (const u8 *) iwe->u.ap_addr.sa_data) ||
os_memcmp(iwe->u.ap_addr.sa_data,
"\x44\x44\x44\x44\x44\x44", ETH_ALEN) ==
0) {
(ifi->ifi_flags & IFF_UP) ? "[UP]" : "",
(ifi->ifi_flags & IFF_RUNNING) ? "[RUNNING]" : "",
(ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "",
- (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT" : "");
+ (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : "");
/*
* Some drivers send the association event before the operup event--in
* this case, lifting operstate in wpa_driver_wext_set_operstate()
/*
* Some drivers do not report frequency, but a channel.
* Try to map this to frequency by assuming they are using
- * IEEE 802.11b/g.
+ * IEEE 802.11b/g. But don't overwrite a previously parsed
+ * frequency if the driver sends both frequency and channel,
+ * since the driver may be sending an A-band channel that we
+ * don't handle here.
*/
+
+ if (res->res.freq)
+ return;
+
if (iwe->u.freq.m >= 1 && iwe->u.freq.m <= 13) {
res->res.freq = 2407 + 5 * iwe->u.freq.m;
return;
{
struct wpa_driver_wext_data *drv = priv;
struct iwreq iwr;
- int ret = 0;
+ int ret = -1, flags;
+ unsigned int new_mode = mode ? IW_MODE_ADHOC : IW_MODE_INFRA;
os_memset(&iwr, 0, sizeof(iwr));
os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
- iwr.u.mode = mode ? IW_MODE_ADHOC : IW_MODE_INFRA;
+ iwr.u.mode = new_mode;
+ if (ioctl(drv->ioctl_sock, SIOCSIWMODE, &iwr) == 0) {
+ ret = 0;
+ goto done;
+ }
- if (ioctl(drv->ioctl_sock, SIOCSIWMODE, &iwr) < 0) {
+ if (errno != EBUSY) {
perror("ioctl[SIOCSIWMODE]");
- ret = -1;
+ goto done;
+ }
+
+ /* mac80211 doesn't allow mode changes while the device is up, so if
+ * the device isn't in the mode we're about to change to, take device
+ * down, try to set the mode again, and bring it back up.
+ */
+ if (ioctl(drv->ioctl_sock, SIOCGIWMODE, &iwr) < 0) {
+ perror("ioctl[SIOCGIWMODE]");
+ goto done;
+ }
+
+ if (iwr.u.mode == new_mode) {
+ ret = 0;
+ goto done;
+ }
+
+ if (wpa_driver_wext_get_ifflags(drv, &flags) == 0) {
+ (void) wpa_driver_wext_set_ifflags(drv, flags & ~IFF_UP);
+
+ /* Try to set the mode again while the interface is down */
+ iwr.u.mode = new_mode;
+ if (ioctl(drv->ioctl_sock, SIOCSIWMODE, &iwr) < 0)
+ perror("ioctl[SIOCSIWMODE]");
+ else
+ ret = 0;
+
+ /* Ignore return value of get_ifflags to ensure that the device
+ * is always up like it was before this function was called.
+ */
+ (void) wpa_driver_wext_get_ifflags(drv, &flags);
+ (void) wpa_driver_wext_set_ifflags(drv, flags | IFF_UP);
}
+done:
return ret;
}