Move more multi-BSSID processing into drv_callbacks.c

This simplifies driver wrapper operations and removes last direct
struct hostapd_data dereferences from driver_nl80211.c. In addition,
some of the TX callbacks are now fixed for secondary BSSes.
master
Jouni Malinen 15 years ago committed by Jouni Malinen
parent 412036f5f0
commit 4b9841d34c

@ -120,24 +120,104 @@ void hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr,
const u8 *buf, size_t len, int ack) const u8 *buf, size_t len, int ack)
{ {
struct sta_info *sta; struct sta_info *sta;
struct hostapd_iface *iface = hapd->iface;
sta = ap_get_sta(hapd, addr); sta = ap_get_sta(hapd, addr);
if (sta && sta->flags & WLAN_STA_PENDING_POLL) { if (sta == NULL && iface->num_bss > 1) {
size_t j;
for (j = 0; j < iface->num_bss; j++) {
hapd = iface->bss[j];
sta = ap_get_sta(hapd, addr);
if (sta)
break;
}
}
if (sta == NULL)
return;
if (sta->flags & WLAN_STA_PENDING_POLL) {
wpa_printf(MSG_DEBUG, "STA " MACSTR " %s pending " wpa_printf(MSG_DEBUG, "STA " MACSTR " %s pending "
"activity poll", MAC2STR(sta->addr), "activity poll", MAC2STR(sta->addr),
ack ? "ACKed" : "did not ACK"); ack ? "ACKed" : "did not ACK");
if (ack) if (ack)
sta->flags &= ~WLAN_STA_PENDING_POLL; sta->flags &= ~WLAN_STA_PENDING_POLL;
} }
if (sta)
ieee802_1x_tx_status(hapd, sta, buf, len, ack); ieee802_1x_tx_status(hapd, sta, buf, len, ack);
}
static const u8 * get_hdr_bssid(const struct ieee80211_hdr *hdr, size_t len)
{
u16 fc, type, stype;
/*
* PS-Poll frames are 16 bytes. All other frames are
* 24 bytes or longer.
*/
if (len < 16)
return NULL;
fc = le_to_host16(hdr->frame_control);
type = WLAN_FC_GET_TYPE(fc);
stype = WLAN_FC_GET_STYPE(fc);
switch (type) {
case WLAN_FC_TYPE_DATA:
if (len < 24)
return NULL;
switch (fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) {
case WLAN_FC_TODS:
return hdr->addr1;
case WLAN_FC_FROMDS:
return hdr->addr2;
default:
return NULL;
}
case WLAN_FC_TYPE_CTRL:
if (stype != WLAN_FC_STYPE_PSPOLL)
return NULL;
return hdr->addr1;
case WLAN_FC_TYPE_MGMT:
return hdr->addr3;
default:
return NULL;
}
}
#define HAPD_BROADCAST ((struct hostapd_data *) -1)
static struct hostapd_data * get_hapd_bssid(struct hostapd_iface *iface,
const u8 *bssid)
{
size_t i;
if (bssid == NULL)
return NULL;
if (bssid[0] == 0xff && bssid[1] == 0xff && bssid[2] == 0xff &&
bssid[3] == 0xff && bssid[4] == 0xff && bssid[5] == 0xff)
return HAPD_BROADCAST;
for (i = 0; i < iface->num_bss; i++) {
if (os_memcmp(bssid, iface->bss[i]->own_addr, ETH_ALEN) == 0)
return iface->bss[i];
}
return NULL;
} }
void hostapd_rx_from_unknown_sta(struct hostapd_data *hapd, const u8 *addr) void hostapd_rx_from_unknown_sta(struct hostapd_data *hapd,
const struct ieee80211_hdr *hdr, size_t len)
{ {
struct sta_info *sta; struct sta_info *sta;
const u8 *addr;
hapd = get_hapd_bssid(hapd->iface, get_hdr_bssid(hdr, len));
if (hapd == NULL || hapd == HAPD_BROADCAST)
return;
addr = hdr->addr2;
sta = ap_get_sta(hapd, addr); sta = ap_get_sta(hapd, addr);
if (!sta || !(sta->flags & WLAN_STA_ASSOC)) { if (!sta || !(sta->flags & WLAN_STA_ASSOC)) {
wpa_printf(MSG_DEBUG, "Data/PS-poll frame from not associated " wpa_printf(MSG_DEBUG, "Data/PS-poll frame from not associated "
@ -262,13 +342,48 @@ void hostapd_eapol_receive(struct hostapd_data *hapd, const u8 *sa,
void hostapd_mgmt_rx(struct hostapd_data *hapd, u8 *buf, size_t len, void hostapd_mgmt_rx(struct hostapd_data *hapd, u8 *buf, size_t len,
u16 stype, struct hostapd_frame_info *fi) u16 stype, struct hostapd_frame_info *fi)
{ {
ieee802_11_mgmt(hapd, buf, len, stype, fi); struct hostapd_iface *iface = hapd->iface;
struct ieee80211_hdr *hdr;
const u8 *bssid;
hdr = (struct ieee80211_hdr *) buf;
bssid = get_hdr_bssid(hdr, len);
if (bssid == NULL)
return;
hapd = get_hapd_bssid(iface, bssid);
if (hapd == NULL) {
u16 fc;
fc = le_to_host16(hdr->frame_control);
/*
* Drop frames to unknown BSSIDs except for Beacon frames which
* could be used to update neighbor information.
*/
if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_BEACON)
hapd = iface->bss[0];
else
return;
}
if (hapd == HAPD_BROADCAST) {
size_t i;
for (i = 0; i < iface->num_bss; i++)
ieee802_11_mgmt(iface->bss[i], buf, len, stype, fi);
} else
ieee802_11_mgmt(hapd, buf, len, stype, fi);
} }
void hostapd_mgmt_tx_cb(struct hostapd_data *hapd, u8 *buf, size_t len, void hostapd_mgmt_tx_cb(struct hostapd_data *hapd, u8 *buf, size_t len,
u16 stype, int ok) u16 stype, int ok)
{ {
struct ieee80211_hdr *hdr;
hdr = (struct ieee80211_hdr *) buf;
hapd = get_hapd_bssid(hapd->iface, get_hdr_bssid(hdr, len));
if (hapd == NULL || hapd == HAPD_BROADCAST)
return;
ieee802_11_mgmt_cb(hapd, buf, len, stype, ok); ieee802_11_mgmt_cb(hapd, buf, len, stype, ok);
} }
#endif /* NEED_MLME */ #endif /* NEED_MLME */

@ -1728,12 +1728,14 @@ void wpa_scan_sort_results(struct wpa_scan_results *res);
/* hostapd functions for driver wrappers */ /* hostapd functions for driver wrappers */
struct sta_info; struct sta_info;
struct ieee80211_hdr;
void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta, void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta,
int reassoc); int reassoc);
void hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr, void hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr,
const u8 *buf, size_t len, int ack); const u8 *buf, size_t len, int ack);
void hostapd_rx_from_unknown_sta(struct hostapd_data *hapd, const u8 *addr); void hostapd_rx_from_unknown_sta(struct hostapd_data *hapd,
const struct ieee80211_hdr *hdr, size_t len);
int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr, int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
const u8 *ie, size_t ielen); const u8 *ie, size_t ielen);
void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr); void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr);

@ -78,7 +78,7 @@ static void handle_data(struct hostap_driver_data *drv, u8 *buf, size_t len,
} }
sa = hdr->addr2; sa = hdr->addr2;
hostapd_rx_from_unknown_sta(drv->hapd, sa); hostapd_rx_from_unknown_sta(drv->hapd, hdr, len);
pos = (u8 *) (hdr + 1); pos = (u8 *) (hdr + 1);
left = len - sizeof(*hdr); left = len - sizeof(*hdr);

@ -38,20 +38,11 @@
#include <linux/filter.h> #include <linux/filter.h>
#include "radiotap.h" #include "radiotap.h"
#include "radiotap_iter.h" #include "radiotap_iter.h"
#endif /* CONFIG_AP || HOSTAPD */
#ifdef CONFIG_AP
#include "../hostapd/hostapd_defs.h" #include "../../hostapd/hostapd_defs.h"
#endif /* CONFIG_AP || HOSTAPD */
#ifndef ETH_P_ALL
#define ETH_P_ALL 0x0003
#endif
#endif /* CONFIG_AP */
#ifdef HOSTAPD #ifdef HOSTAPD
#include "../../hostapd/hostapd.h"
#include "../../hostapd/sta_flags.h" #include "../../hostapd/sta_flags.h"
#include "ieee802_11_common.h" #include "ieee802_11_common.h"
@ -78,12 +69,6 @@
#define IF_OPER_UP 6 #define IF_OPER_UP 6
#endif #endif
enum ieee80211_msg_type {
ieee80211_msg_normal = 0,
ieee80211_msg_tx_callback_ack = 1,
ieee80211_msg_tx_callback_fail = 2,
};
struct i802_bss { struct i802_bss {
struct i802_bss *next; struct i802_bss *next;
int ifindex; int ifindex;
@ -125,8 +110,6 @@ struct wpa_driver_nl80211_data {
#endif /* CONFIG_AP */ #endif /* CONFIG_AP */
#ifdef HOSTAPD #ifdef HOSTAPD
struct hostapd_data *hapd;
int eapol_sock; /* socket for EAPOL frames */ int eapol_sock; /* socket for EAPOL frames */
int default_if_indices[16]; int default_if_indices[16];
@ -2472,139 +2455,46 @@ static void handle_tx_callback(void *ctx, u8 *buf, size_t len, int ok)
} }
static void handle_frame(struct wpa_driver_nl80211_data *drv, static void from_unknown_sta(struct wpa_driver_nl80211_data *drv,
u8 *buf, size_t len, struct ieee80211_hdr *hdr, size_t len)
struct hostapd_frame_info *hfi,
enum ieee80211_msg_type msg_type)
{ {
struct ieee80211_hdr *hdr;
u16 fc, type, stype;
size_t data_len = len;
u8 *bssid;
void *ctx = drv->ctx;
#ifdef HOSTAPD #ifdef HOSTAPD
struct hostapd_iface *iface = drv->hapd->iface; hostapd_rx_from_unknown_sta(drv->ctx, hdr, len);
struct hostapd_data *hapd = NULL; #else /* HOSTAPD */
int broadcast_bssid = 0; ap_rx_from_unknown_sta(drv->ctx, hdr->addr2);
size_t i;
#endif /* HOSTAPD */ #endif /* HOSTAPD */
}
/*
* PS-Poll frames are 16 bytes. All other frames are static void handle_frame(struct wpa_driver_nl80211_data *drv,
* 24 bytes or longer. u8 *buf, size_t len,
*/ struct hostapd_frame_info *hfi)
if (len < 16) {
return; struct ieee80211_hdr *hdr;
u16 fc, stype;
hdr = (struct ieee80211_hdr *) buf; hdr = (struct ieee80211_hdr *) buf;
fc = le_to_host16(hdr->frame_control); fc = le_to_host16(hdr->frame_control);
type = WLAN_FC_GET_TYPE(fc);
stype = WLAN_FC_GET_STYPE(fc); stype = WLAN_FC_GET_STYPE(fc);
switch (type) { switch (WLAN_FC_GET_TYPE(fc)) {
case WLAN_FC_TYPE_DATA:
if (len < 24)
return;
switch (fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) {
case WLAN_FC_TODS:
bssid = hdr->addr1;
break;
case WLAN_FC_FROMDS:
bssid = hdr->addr2;
break;
default:
/* discard */
return;
}
break;
case WLAN_FC_TYPE_CTRL:
/* discard non-ps-poll frames */
if (stype != WLAN_FC_STYPE_PSPOLL)
return;
bssid = hdr->addr1;
break;
case WLAN_FC_TYPE_MGMT:
bssid = hdr->addr3;
break;
default:
/* discard */
return;
}
#ifdef HOSTAPD
/* find interface frame belongs to */
for (i = 0; i < iface->num_bss; i++) {
if (memcmp(bssid, iface->bss[i]->own_addr, ETH_ALEN) == 0) {
hapd = iface->bss[i];
break;
}
}
if (hapd == NULL) {
hapd = iface->bss[0];
if (bssid[0] != 0xff || bssid[1] != 0xff ||
bssid[2] != 0xff || bssid[3] != 0xff ||
bssid[4] != 0xff || bssid[5] != 0xff) {
/*
* Unknown BSSID - drop frame if this is not from
* passive scanning or a beacon (at least ProbeReq
* frames to other APs may be allowed through RX
* filtering in the wlan hw/driver)
*/
if ((type != WLAN_FC_TYPE_MGMT ||
stype != WLAN_FC_STYPE_BEACON))
return;
} else
broadcast_bssid = 1;
}
ctx = hapd;
#endif /* HOSTAPD */
switch (msg_type) {
case ieee80211_msg_normal:
/* continue processing */
break;
case ieee80211_msg_tx_callback_ack:
handle_tx_callback(ctx, buf, data_len, 1);
return;
case ieee80211_msg_tx_callback_fail:
handle_tx_callback(ctx, buf, data_len, 0);
return;
}
switch (type) {
case WLAN_FC_TYPE_MGMT: case WLAN_FC_TYPE_MGMT:
if (stype != WLAN_FC_STYPE_BEACON && if (stype != WLAN_FC_STYPE_BEACON &&
stype != WLAN_FC_STYPE_PROBE_REQ) stype != WLAN_FC_STYPE_PROBE_REQ)
wpa_printf(MSG_MSGDUMP, "MGMT"); wpa_printf(MSG_MSGDUMP, "MGMT");
#ifdef HOSTAPD #ifdef HOSTAPD
if (broadcast_bssid) { hostapd_mgmt_rx(drv->ctx, buf, len, stype, hfi);
for (i = 0; i < iface->num_bss; i++)
hostapd_mgmt_rx(iface->bss[i], buf, data_len,
stype, hfi);
} else
hostapd_mgmt_rx(hapd, buf, data_len, stype, hfi);
#else /* HOSTAPD */ #else /* HOSTAPD */
ap_mgmt_rx(drv->ctx, buf, data_len, stype, hfi); ap_mgmt_rx(drv->ctx, buf, len, stype, hfi);
#endif /* HOSTAPD */ #endif /* HOSTAPD */
break; break;
case WLAN_FC_TYPE_CTRL: case WLAN_FC_TYPE_CTRL:
/* can only get here with PS-Poll frames */ /* can only get here with PS-Poll frames */
wpa_printf(MSG_DEBUG, "CTRL"); wpa_printf(MSG_DEBUG, "CTRL");
#ifdef HOSTAPD from_unknown_sta(drv, hdr, len);
hostapd_rx_from_unknown_sta(drv->hapd, hdr->addr2);
#else /* HOSTAPD */
ap_rx_from_unknown_sta(drv->ctx, hdr->addr2);
#endif /* HOSTAPD */
break; break;
case WLAN_FC_TYPE_DATA: case WLAN_FC_TYPE_DATA:
#ifdef HOSTAPD from_unknown_sta(drv, hdr, len);
hostapd_rx_from_unknown_sta(drv->hapd, hdr->addr2);
#else /* HOSTAPD */
ap_rx_from_unknown_sta(drv->ctx, hdr->addr2);
#endif /* HOSTAPD */
break; break;
} }
} }
@ -2618,7 +2508,7 @@ static void handle_monitor_read(int sock, void *eloop_ctx, void *sock_ctx)
struct ieee80211_radiotap_iterator iter; struct ieee80211_radiotap_iterator iter;
int ret; int ret;
struct hostapd_frame_info hfi; struct hostapd_frame_info hfi;
int injected = 0, failed = 0, msg_type, rxflags = 0; int injected = 0, failed = 0, rxflags = 0;
len = recv(sock, buf, sizeof(buf), 0); len = recv(sock, buf, sizeof(buf), 0);
if (len < 0) { if (len < 0) {
@ -2675,14 +2565,11 @@ static void handle_monitor_read(int sock, void *eloop_ctx, void *sock_ctx)
return; return;
if (!injected) if (!injected)
msg_type = ieee80211_msg_normal; handle_frame(drv, buf + iter.max_length,
else if (failed) len - iter.max_length, &hfi);
msg_type = ieee80211_msg_tx_callback_fail;
else else
msg_type = ieee80211_msg_tx_callback_ack; handle_tx_callback(drv->ctx, buf + iter.max_length,
len - iter.max_length, !failed);
handle_frame(drv, buf + iter.max_length,
len - iter.max_length, &hfi, msg_type);
} }
@ -3864,11 +3751,11 @@ static void handle_eapol(int sock, void *eloop_ctx, void *sock_ctx)
} }
if (have_ifidx(drv, lladdr.sll_ifindex)) { if (have_ifidx(drv, lladdr.sll_ifindex)) {
struct hostapd_data *hapd; void *ctx;
hapd = hostapd_sta_get_bss(drv->hapd, lladdr.sll_addr); ctx = hostapd_sta_get_bss(drv->ctx, lladdr.sll_addr);
if (!hapd) if (!ctx)
return; return;
hostapd_eapol_receive(hapd, lladdr.sll_addr, buf, len); hostapd_eapol_receive(ctx, lladdr.sll_addr, buf, len);
} }
} }
@ -3943,7 +3830,6 @@ static void *i802_init(struct hostapd_data *hapd,
if (drv == NULL) if (drv == NULL)
return NULL; return NULL;
drv->hapd = hapd;
drv->bss.ifindex = drv->ifindex; drv->bss.ifindex = drv->ifindex;
drv->num_if_indices = sizeof(drv->default_if_indices) / sizeof(int); drv->num_if_indices = sizeof(drv->default_if_indices) / sizeof(int);

Loading…
Cancel
Save