#endif
#endif /* _BYTE_ORDER */
-#include <net80211/ieee80211.h>
-#include <net80211/_ieee80211.h>
-#include <net80211/ieee80211_crypto.h>
-
/*
* Note, the ATH_WPS_IE setting must match with the driver build.. If the
* driver does not include this, the IEEE80211_IOCTL_GETWPAIE ioctl will fail.
*/
#define ATH_WPS_IE
-#include <net80211/ieee80211_ioctl.h>
+
+#include "os/linux/include/ieee80211_external.h"
+
#ifdef CONFIG_WPS
-#ifdef IEEE80211_IOCTL_FILTERFRAME
#include <netpacket/packet.h>
#ifndef ETH_P_80211_RAW
#define ETH_P_80211_RAW 0x0019
#endif
-#endif /* IEEE80211_IOCTL_FILTERFRAME */
#endif /* CONFIG_WPS */
-/*
- * Avoid conflicts with hostapd definitions by undefining couple of defines
- * from madwifi header files.
- */
-#undef WPA_OUI_TYPE
-#undef WME_OUI_TYPE
-
#include "wireless_copy.h"
#include "driver.h"
#include "priv_netlink.h"
#include "l2_packet/l2_packet.h"
#include "common/ieee802_11_defs.h"
+#include "netlink.h"
+#include "linux_ioctl.h"
struct madwifi_driver_data {
struct l2_packet_data *sock_xmit; /* raw packet xmit socket */
struct l2_packet_data *sock_recv; /* raw packet recv socket */
int ioctl_sock; /* socket for ioctl() use */
- int wext_sock; /* socket for wireless events */
+ struct netlink_data *netlink;
int we_version;
u8 acct_mac[ETH_ALEN];
struct hostap_sta_driver_data acct_data;
static int madwifi_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
int reason_code);
+static int madwifi_set_privacy(void *priv, int enabled);
+
+static const char * athr_get_ioctl_name(int op)
+{
+ switch (op) {
+ case IEEE80211_IOCTL_SETPARAM:
+ return "SETPARAM";
+ case IEEE80211_IOCTL_GETPARAM:
+ return "GETPARAM";
+ case IEEE80211_IOCTL_SETKEY:
+ return "SETKEY";
+ case IEEE80211_IOCTL_SETWMMPARAMS:
+ return "SETWMMPARAMS";
+ case IEEE80211_IOCTL_DELKEY:
+ return "DELKEY";
+ case IEEE80211_IOCTL_GETWMMPARAMS:
+ return "GETWMMPARAMS";
+ case IEEE80211_IOCTL_SETMLME:
+ return "SETMLME";
+ case IEEE80211_IOCTL_GETCHANINFO:
+ return "GETCHANINFO";
+ case IEEE80211_IOCTL_SETOPTIE:
+ return "SETOPTIE";
+ case IEEE80211_IOCTL_GETOPTIE:
+ return "GETOPTIE";
+ case IEEE80211_IOCTL_ADDMAC:
+ return "ADDMAC";
+ case IEEE80211_IOCTL_DELMAC:
+ return "DELMAC";
+ case IEEE80211_IOCTL_GETCHANLIST:
+ return "GETCHANLIST";
+ case IEEE80211_IOCTL_SETCHANLIST:
+ return "SETCHANLIST";
+ case IEEE80211_IOCTL_KICKMAC:
+ return "KICKMAC";
+ case IEEE80211_IOCTL_CHANSWITCH:
+ return "CHANSWITCH";
+ case IEEE80211_IOCTL_GETMODE:
+ return "GETMODE";
+ case IEEE80211_IOCTL_SETMODE:
+ return "SETMODE";
+ case IEEE80211_IOCTL_GET_APPIEBUF:
+ return "GET_APPIEBUF";
+ case IEEE80211_IOCTL_SET_APPIEBUF:
+ return "SET_APPIEBUF";
+ case IEEE80211_IOCTL_SET_ACPARAMS:
+ return "SET_ACPARAMS";
+ case IEEE80211_IOCTL_FILTERFRAME:
+ return "FILTERFRAME";
+ case IEEE80211_IOCTL_SET_RTPARAMS:
+ return "SET_RTPARAMS";
+ case IEEE80211_IOCTL_SENDADDBA:
+ return "SENDADDBA";
+ case IEEE80211_IOCTL_GETADDBASTATUS:
+ return "GETADDBASTATUS";
+ case IEEE80211_IOCTL_SENDDELBA:
+ return "SENDDELBA";
+ case IEEE80211_IOCTL_SET_MEDENYENTRY:
+ return "SET_MEDENYENTRY";
+ case IEEE80211_IOCTL_SET_ADDBARESP:
+ return "SET_ADDBARESP";
+ case IEEE80211_IOCTL_GET_MACADDR:
+ return "GET_MACADDR";
+ case IEEE80211_IOCTL_SET_HBRPARAMS:
+ return "SET_HBRPARAMS";
+ case IEEE80211_IOCTL_SET_RXTIMEOUT:
+ return "SET_RXTIMEOUT";
+ case IEEE80211_IOCTL_STA_STATS:
+ return "STA_STATS";
+ case IEEE80211_IOCTL_GETWPAIE:
+ return "GETWPAIE";
+ default:
+ return "??";
+ }
+}
+
+
+static const char * athr_get_param_name(int op)
+{
+ switch (op) {
+ case IEEE80211_IOC_MCASTCIPHER:
+ return "MCASTCIPHER";
+ case IEEE80211_PARAM_MCASTKEYLEN:
+ return "MCASTKEYLEN";
+ case IEEE80211_PARAM_UCASTCIPHERS:
+ return "UCASTCIPHERS";
+ case IEEE80211_PARAM_KEYMGTALGS:
+ return "KEYMGTALGS";
+ case IEEE80211_PARAM_RSNCAPS:
+ return "RSNCAPS";
+ case IEEE80211_PARAM_WPA:
+ return "WPA";
+ case IEEE80211_PARAM_AUTHMODE:
+ return "AUTHMODE";
+ case IEEE80211_PARAM_PRIVACY:
+ return "PRIVACY";
+ case IEEE80211_PARAM_COUNTERMEASURES:
+ return "COUNTERMEASURES";
+ default:
+ return "??";
+ }
+}
+
static int
set80211priv(struct madwifi_driver_data *drv, int op, void *data, int len)
}
if (ioctl(drv->ioctl_sock, op, &iwr) < 0) {
- int first = IEEE80211_IOCTL_SETPARAM;
- static const char *opnames[] = {
- "ioctl[IEEE80211_IOCTL_SETPARAM]",
- "ioctl[IEEE80211_IOCTL_GETPARAM]",
- "ioctl[IEEE80211_IOCTL_SETKEY]",
- "ioctl[IEEE80211_IOCTL_SETWMMPARAMS]",
- "ioctl[IEEE80211_IOCTL_DELKEY]",
- "ioctl[IEEE80211_IOCTL_GETWMMPARAMS]",
- "ioctl[IEEE80211_IOCTL_SETMLME]",
- "ioctl[IEEE80211_IOCTL_GETCHANINFO]",
- "ioctl[IEEE80211_IOCTL_SETOPTIE]",
- "ioctl[IEEE80211_IOCTL_GETOPTIE]",
- "ioctl[IEEE80211_IOCTL_ADDMAC]",
- "ioctl[IEEE80211_IOCTL_DELMAC]",
- "ioctl[IEEE80211_IOCTL_GETCHANLIST]",
- "ioctl[IEEE80211_IOCTL_SETCHANLIST]",
- "ioctl[IEEE80211_IOCTL_KICKMAC]",
- "ioctl[IEEE80211_IOCTL_CHANSWITCH]",
- "ioctl[IEEE80211_IOCTL_GETMODE]",
- "ioctl[IEEE80211_IOCTL_SETMODE]",
- "ioctl[IEEE80211_IOCTL_GET_APPIEBUF]",
- "ioctl[IEEE80211_IOCTL_SET_APPIEBUF]",
- NULL,
- "ioctl[IEEE80211_IOCTL_FILTERFRAME]",
- };
- int idx = op - first;
- if (first <= op &&
- idx < (int) (sizeof(opnames) / sizeof(opnames[0])) &&
- opnames[idx])
- perror(opnames[idx]);
- else {
- perror("ioctl[unknown???]");
- wpa_printf(MSG_DEBUG, "Failed ioctl: 0x%x", op);
- }
+ wpa_printf(MSG_DEBUG, "atheros: %s: %s: ioctl op=0x%x "
+ "(%s) len=%d failed: %d (%s)",
+ __func__, drv->iface, op,
+ athr_get_ioctl_name(op),
+ len, errno, strerror(errno));
return -1;
}
return 0;
if (ioctl(drv->ioctl_sock, IEEE80211_IOCTL_SETPARAM, &iwr) < 0) {
perror("ioctl[IEEE80211_IOCTL_SETPARAM]");
- wpa_printf(MSG_DEBUG, "%s: Failed to set parameter (op %d "
- "arg %d)", __func__, op, arg);
+ wpa_printf(MSG_DEBUG, "%s: %s: Failed to set parameter (op %d "
+ "(%s) arg %d)", __func__, drv->iface, op,
+ athr_get_param_name(op), arg);
return -1;
}
return 0;
return 0;
}
-
-static int
-madwifi_set_iface_flags(void *priv, int dev_up)
-{
- struct madwifi_driver_data *drv = priv;
- struct ifreq ifr;
-
- wpa_printf(MSG_DEBUG, "%s: dev_up=%d", __func__, dev_up);
-
- if (drv->ioctl_sock < 0)
- return -1;
-
- memset(&ifr, 0, sizeof(ifr));
- os_strlcpy(ifr.ifr_name, drv->iface, IFNAMSIZ);
-
- if (ioctl(drv->ioctl_sock, SIOCGIFFLAGS, &ifr) != 0) {
- perror("ioctl[SIOCGIFFLAGS]");
- return -1;
- }
-
- if (dev_up)
- ifr.ifr_flags |= IFF_UP;
- else
- ifr.ifr_flags &= ~IFF_UP;
-
- if (ioctl(drv->ioctl_sock, SIOCSIFFLAGS, &ifr) != 0) {
- perror("ioctl[SIOCSIFFLAGS]");
- return -1;
- }
-
- return 0;
-}
-
static int
madwifi_set_ieee8021x(void *priv, struct wpa_bss_params *params)
{
if (!params->enabled) {
/* XXX restore state */
- return set80211param(priv, IEEE80211_PARAM_AUTHMODE,
- IEEE80211_AUTH_AUTO);
+ if (set80211param(priv, IEEE80211_PARAM_AUTHMODE,
+ IEEE80211_AUTH_AUTO) < 0)
+ return -1;
+ /* IEEE80211_AUTH_AUTO ends up enabling Privacy; clear that */
+ return madwifi_set_privacy(drv, 0);
}
if (!params->wpa && !params->ieee802_1x) {
hostapd_logger(drv->hapd, NULL, HOSTAPD_MODULE_DRIVER,
}
static int
-madwifi_set_privacy(const char *ifname, void *priv, int enabled)
+madwifi_set_privacy(void *priv, int enabled)
{
struct madwifi_driver_data *drv = priv;
}
static int
-madwifi_sta_set_flags(void *priv, const u8 *addr, int total_flags,
- int flags_or, int flags_and)
+madwifi_sta_set_flags(void *priv, const u8 *addr,
+ int total_flags, int flags_or, int flags_and)
{
/* For now, only support setting Authorized flag */
if (flags_or & WPA_STA_AUTHORIZED)
}
static int
-madwifi_set_key(const char *ifname, void *priv, wpa_alg alg, const u8 *addr,
- int key_idx, int set_tx, const u8 *seq, size_t seq_len,
- const u8 *key, size_t key_len)
+madwifi_set_key(const char *ifname, void *priv, enum wpa_alg alg,
+ const u8 *addr, int key_idx, int set_tx, const u8 *seq,
+ size_t seq_len, const u8 *key, size_t key_len)
{
struct madwifi_driver_data *drv = priv;
struct ieee80211req_key wk;
* swap it to match with the byte order used in WPA.
*/
int i;
+#ifndef WPA_KEY_RSC_LEN
+#define WPA_KEY_RSC_LEN 8
+#endif
u8 tmp[WPA_KEY_RSC_LEN];
memcpy(tmp, &wk.ik_keytsc, sizeof(wk.ik_keytsc));
for (i = 0; i < WPA_KEY_RSC_LEN; i++) {
static int
-madwifi_set_opt_ie(const char *ifname, void *priv, const u8 *ie, size_t ie_len)
+madwifi_set_opt_ie(void *priv, const u8 *ie, size_t ie_len)
{
/*
* Do nothing; we setup parameters at startup that define the
{
struct madwifi_driver_data *drv = ctx;
const struct ieee80211_mgmt *mgmt;
- const u8 *end, *ie;
u16 fc;
- size_t ie_len;
+ union wpa_event_data event;
/* Send Probe Request information to WPS processing */
WLAN_FC_GET_STYPE(fc) != WLAN_FC_STYPE_PROBE_REQ)
return;
- end = buf + len;
- ie = mgmt->u.probe_req.variable;
- ie_len = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req));
-
- hostapd_probe_req_rx(drv->hapd, mgmt->sa, ie, ie_len);
+ os_memset(&event, 0, sizeof(event));
+ event.rx_probe_req.sa = mgmt->sa;
+ event.rx_probe_req.ie = mgmt->u.probe_req.variable;
+ event.rx_probe_req.ie_len =
+ len - (IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req));
+ wpa_supplicant_event(drv->hapd, EVENT_RX_PROBE_REQ, &event);
}
#endif /* CONFIG_WPS */
madwifi_set_wps_ie(void *priv, const u8 *ie, size_t len, u32 frametype)
{
struct madwifi_driver_data *drv = priv;
- u8 buf[256];
+ u8 buf[500];
struct ieee80211req_getset_appiebuf *beac_ie;
wpa_printf(MSG_DEBUG, "%s buflen = %lu", __func__,
}
static int
-madwifi_set_wps_beacon_ie(const char *ifname, void *priv, const u8 *ie,
- size_t len)
-{
- return madwifi_set_wps_ie(priv, ie, len, IEEE80211_APPIE_FRAME_BEACON);
-}
-
-static int
-madwifi_set_wps_probe_resp_ie(const char *ifname, void *priv, const u8 *ie,
- size_t len)
+madwifi_set_ap_wps_ie(void *priv, const struct wpabuf *beacon,
+ const struct wpabuf *proberesp,
+ const struct wpabuf *assocresp)
{
- return madwifi_set_wps_ie(priv, ie, len,
+ madwifi_set_wps_ie(priv, assocresp ? wpabuf_head(assocresp) : NULL,
+ assocresp ? wpabuf_len(assocresp) : 0,
+ IEEE80211_APPIE_FRAME_ASSOC_RESP);
+ if (madwifi_set_wps_ie(priv, beacon ? wpabuf_head(beacon) : NULL,
+ beacon ? wpabuf_len(beacon) : 0,
+ IEEE80211_APPIE_FRAME_BEACON))
+ return -1;
+ return madwifi_set_wps_ie(priv,
+ proberesp ? wpabuf_head(proberesp) : NULL,
+ proberesp ? wpabuf_len(proberesp): 0,
IEEE80211_APPIE_FRAME_PROBE_RESP);
}
#else /* CONFIG_WPS */
-#define madwifi_set_wps_beacon_ie NULL
-#define madwifi_set_wps_probe_resp_ie NULL
+#define madwifi_set_ap_wps_ie NULL
#endif /* CONFIG_WPS */
-static int
+static void
madwifi_new_sta(struct madwifi_driver_data *drv, u8 addr[IEEE80211_ADDR_LEN])
{
struct hostapd_data *hapd = drv->hapd;
struct ieee80211req_wpaie ie;
- int ielen = 0, res;
+ int ielen = 0;
u8 *iebuf = NULL;
/*
ielen += 2;
no_ie:
- res = hostapd_notif_assoc(hapd, addr, iebuf, ielen);
+ drv_event_assoc(hapd, addr, iebuf, ielen);
if (memcmp(addr, drv->acct_mac, ETH_ALEN) == 0) {
/* Cached accounting data is not valid anymore. */
memset(drv->acct_mac, 0, ETH_ALEN);
memset(&drv->acct_data, 0, sizeof(drv->acct_data));
}
-
- return res;
}
static void
switch (iwe->cmd) {
case IWEVEXPIRED:
- hostapd_notif_disassoc(drv->hapd,
- (u8 *) iwe->u.addr.sa_data);
+ drv_event_disassoc(drv->hapd,
+ (u8 *) iwe->u.addr.sa_data);
break;
case IWEVREGISTERED:
madwifi_new_sta(drv, (u8 *) iwe->u.addr.sa_data);
static void
-madwifi_wireless_event_rtm_newlink(struct madwifi_driver_data *drv,
- struct nlmsghdr *h, int len)
+madwifi_wireless_event_rtm_newlink(void *ctx,
+ struct ifinfomsg *ifi, u8 *buf, size_t len)
{
- struct ifinfomsg *ifi;
- int attrlen, nlmsg_len, rta_len;
- struct rtattr * attr;
-
- if (len < (int) sizeof(*ifi))
- return;
-
- ifi = NLMSG_DATA(h);
+ struct madwifi_driver_data *drv = ctx;
+ int attrlen, rta_len;
+ struct rtattr *attr;
if (ifi->ifi_index != drv->ifindex)
return;
- nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
-
- attrlen = NLMSG_PAYLOAD(h, sizeof(struct ifinfomsg));
- if (attrlen < 0)
- return;
-
- attr = (struct rtattr *) (((char *) ifi) + nlmsg_len);
+ attrlen = len;
+ attr = (struct rtattr *) buf;
rta_len = RTA_ALIGN(sizeof(struct rtattr));
while (RTA_OK(attr, attrlen)) {
}
-static void
-madwifi_wireless_event_receive(int sock, void *eloop_ctx, void *sock_ctx)
-{
- char buf[256];
- int left;
- struct sockaddr_nl from;
- socklen_t fromlen;
- struct nlmsghdr *h;
- struct madwifi_driver_data *drv = eloop_ctx;
-
- fromlen = sizeof(from);
- left = recvfrom(sock, buf, sizeof(buf), MSG_DONTWAIT,
- (struct sockaddr *) &from, &fromlen);
- if (left < 0) {
- if (errno != EINTR && errno != EAGAIN)
- perror("recvfrom(netlink)");
- return;
- }
-
- h = (struct nlmsghdr *) buf;
- while (left >= (int) sizeof(*h)) {
- int len, plen;
-
- len = h->nlmsg_len;
- plen = len - sizeof(*h);
- if (len > left || plen < 0) {
- printf("Malformed netlink message: "
- "len=%d left=%d plen=%d\n",
- len, left, plen);
- break;
- }
-
- switch (h->nlmsg_type) {
- case RTM_NEWLINK:
- madwifi_wireless_event_rtm_newlink(drv, h, plen);
- break;
- }
-
- len = NLMSG_ALIGN(len);
- left -= len;
- h = (struct nlmsghdr *) ((char *) h + len);
- }
-
- if (left > 0) {
- printf("%d extra bytes in the end of netlink message\n", left);
- }
-}
-
-
static int
madwifi_get_we_version(struct madwifi_driver_data *drv)
{
static int
madwifi_wireless_event_init(struct madwifi_driver_data *drv)
{
- int s;
- struct sockaddr_nl local;
+ struct netlink_config *cfg;
madwifi_get_we_version(drv);
- drv->wext_sock = -1;
-
- s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
- if (s < 0) {
- perror("socket(PF_NETLINK,SOCK_RAW,NETLINK_ROUTE)");
+ cfg = os_zalloc(sizeof(*cfg));
+ if (cfg == NULL)
return -1;
- }
-
- memset(&local, 0, sizeof(local));
- local.nl_family = AF_NETLINK;
- local.nl_groups = RTMGRP_LINK;
- if (bind(s, (struct sockaddr *) &local, sizeof(local)) < 0) {
- perror("bind(netlink)");
- close(s);
+ cfg->ctx = drv;
+ cfg->newlink_cb = madwifi_wireless_event_rtm_newlink;
+ drv->netlink = netlink_init(cfg);
+ if (drv->netlink == NULL) {
+ os_free(cfg);
return -1;
}
- eloop_register_read_sock(s, madwifi_wireless_event_receive, drv, NULL);
- drv->wext_sock = s;
-
return 0;
}
-static void
-madwifi_wireless_event_deinit(struct madwifi_driver_data *drv)
-{
- if (drv->wext_sock < 0)
- return;
- eloop_unregister_read_sock(drv->wext_sock);
- close(drv->wext_sock);
-}
-
-
static int
madwifi_send_eapol(void *priv, const u8 *addr, const u8 *data, size_t data_len,
int encrypt, const u8 *own_addr)
handle_read(void *ctx, const u8 *src_addr, const u8 *buf, size_t len)
{
struct madwifi_driver_data *drv = ctx;
- hostapd_eapol_receive(drv->hapd, src_addr,
- buf + sizeof(struct l2_ethhdr),
- len - sizeof(struct l2_ethhdr));
+ drv_event_eapol_rx(drv->hapd, src_addr, buf + sizeof(struct l2_ethhdr),
+ len - sizeof(struct l2_ethhdr));
}
static void *
struct madwifi_driver_data *drv;
struct ifreq ifr;
struct iwreq iwr;
+ char brname[IFNAMSIZ];
drv = os_zalloc(sizeof(struct madwifi_driver_data));
if (drv == NULL) {
1);
if (drv->sock_recv == NULL)
goto bad;
+ } else if (linux_br_get(brname, drv->iface) == 0) {
+ wpa_printf(MSG_DEBUG, "Interface in bridge %s; configure for "
+ "EAPOL receive", brname);
+ drv->sock_recv = l2_packet_init(brname, NULL, ETH_P_EAPOL,
+ handle_read, drv, 1);
+ if (drv->sock_recv == NULL)
+ goto bad;
} else
drv->sock_recv = drv->sock_xmit;
goto bad;
}
- madwifi_set_iface_flags(drv, 0); /* mark down during setup */
- madwifi_set_privacy(drv->iface, drv, 0); /* default to no privacy */
+ /* mark down during setup */
+ linux_set_iface_flags(drv->ioctl_sock, drv->iface, 0);
+ madwifi_set_privacy(drv, 0); /* default to no privacy */
madwifi_receive_probe_req(drv);
return drv;
bad:
+ if (drv->sock_recv != NULL && drv->sock_recv != drv->sock_xmit)
+ l2_packet_deinit(drv->sock_recv);
if (drv->sock_xmit != NULL)
l2_packet_deinit(drv->sock_xmit);
if (drv->ioctl_sock >= 0)
{
struct madwifi_driver_data *drv = priv;
- madwifi_wireless_event_deinit(drv);
- (void) madwifi_set_iface_flags(drv, 0);
+ netlink_deinit(drv->netlink);
+ (void) linux_set_iface_flags(drv->ioctl_sock, drv->iface, 0);
if (drv->ioctl_sock >= 0)
close(drv->ioctl_sock);
if (drv->sock_recv != NULL && drv->sock_recv != drv->sock_xmit)
}
static int
-madwifi_set_ssid(const char *ifname, void *priv, const u8 *buf, int len)
+madwifi_set_ssid(void *priv, const u8 *buf, int len)
{
struct madwifi_driver_data *drv = priv;
struct iwreq iwr;
}
static int
-madwifi_get_ssid(const char *ifname, void *priv, u8 *buf, int len)
+madwifi_get_ssid(void *priv, u8 *buf, int len)
{
struct madwifi_driver_data *drv = priv;
struct iwreq iwr;
static int
madwifi_commit(void *priv)
{
- return madwifi_set_iface_flags(priv, 1);
+ struct madwifi_driver_data *drv = priv;
+ return linux_set_iface_flags(drv->ioctl_sock, drv->iface, 1);
}
const struct wpa_driver_ops wpa_driver_atheros_ops = {
.name = "atheros",
.hapd_init = madwifi_init,
- .deinit = madwifi_deinit,
+ .hapd_deinit = madwifi_deinit,
.set_ieee8021x = madwifi_set_ieee8021x,
.set_privacy = madwifi_set_privacy,
.set_key = madwifi_set_key,
.set_countermeasures = madwifi_set_countermeasures,
.sta_clear_stats = madwifi_sta_clear_stats,
.commit = madwifi_commit,
- .set_wps_beacon_ie = madwifi_set_wps_beacon_ie,
- .set_wps_probe_resp_ie = madwifi_set_wps_probe_resp_ie,
+ .set_ap_wps_ie = madwifi_set_ap_wps_ie,
};