TDLS: Add initial support for TDLS (IEEE Std 802.11z-2010)

This commit is contained in:
Ganesh Prasadh 2010-10-07 10:26:56 +03:00 committed by Jouni Malinen
parent 23ab8e863f
commit 281ff0aa76
17 changed files with 2036 additions and 5 deletions

View file

@ -101,6 +101,11 @@
/* Status codes (IEEE 802.11-2007, 7.3.1.9, Table 7-23) */
#define WLAN_STATUS_SUCCESS 0
#define WLAN_STATUS_UNSPECIFIED_FAILURE 1
#define WLAN_STATUS_TDLS_WAKEUP_ALTERNATE 2
#define WLAN_STATUS_TDLS_WAKEUP_REJECT 3
#define WLAN_STATUS_SECURITY_DISABLED 5
#define WLAN_STATUS_UNACCEPTABLE_LIFETIME 6
#define WLAN_STATUS_NOT_IN_SAME_BSS 7
#define WLAN_STATUS_CAPS_UNSUPPORTED 10
#define WLAN_STATUS_REASSOC_NO_ASSOC 11
#define WLAN_STATUS_ASSOC_DENIED_UNSPEC 12
@ -148,6 +153,7 @@
#define WLAN_STATUS_INVALID_PMKID 53
#define WLAN_STATUS_INVALID_MDIE 54
#define WLAN_STATUS_INVALID_FTIE 55
#define WLAN_STATUS_INVALID_RSNIE 72
/* Reason codes (IEEE 802.11-2007, 7.3.1.7, Table 7-22) */
#define WLAN_REASON_UNSPECIFIED 1
@ -175,6 +181,8 @@
#define WLAN_REASON_INVALID_RSN_IE_CAPAB 22
#define WLAN_REASON_IEEE_802_1X_AUTH_FAILED 23
#define WLAN_REASON_CIPHER_SUITE_REJECTED 24
#define WLAN_REASON_TDLS_TEARDOWN_UNREACHABLE 25
#define WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED 26
/* IEEE 802.11e */
#define WLAN_REASON_DISASSOC_LOW_ACK 34

View file

@ -56,6 +56,7 @@
#endif /* CONFIG_IEEE80211R */
#define RSN_AUTH_KEY_MGMT_802_1X_SHA256 RSN_SELECTOR(0x00, 0x0f, 0xac, 5)
#define RSN_AUTH_KEY_MGMT_PSK_SHA256 RSN_SELECTOR(0x00, 0x0f, 0xac, 6)
#define RSN_AUTH_KEY_MGMT_TPK_HANDSHAKE RSN_SELECTOR(0x00, 0x0f, 0xac, 7)
#define RSN_CIPHER_SUITE_NONE RSN_SELECTOR(0x00, 0x0f, 0xac, 0)
#define RSN_CIPHER_SUITE_WEP40 RSN_SELECTOR(0x00, 0x0f, 0xac, 1)
@ -68,6 +69,7 @@
#ifdef CONFIG_IEEE80211W
#define RSN_CIPHER_SUITE_AES_128_CMAC RSN_SELECTOR(0x00, 0x0f, 0xac, 6)
#endif /* CONFIG_IEEE80211W */
#define RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED RSN_SELECTOR(0x00, 0x0f, 0xac, 7)
/* EAPOL-Key Key Data Encapsulation
* GroupKey and PeerKey require encryption, otherwise, encryption is optional.

View file

@ -694,6 +694,14 @@ struct p2p_params {
size_t num_sec_dev_types;
};
enum tdls_oper {
TDLS_DISCOVERY_REQ,
TDLS_SETUP,
TDLS_TEARDOWN,
TDLS_ENABLE_LINK,
TDLS_DISABLE_LINK
};
/**
* struct wpa_driver_ops - Driver interface API definition
*
@ -2187,6 +2195,26 @@ struct wpa_driver_ops {
int (*p2p_invite)(void *priv, const u8 *peer, int role,
const u8 *bssid, const u8 *ssid, size_t ssid_len,
const u8 *go_dev_addr, int persistent_group);
/**
* send_tdls_mgmt - for sending TDLS management packets
* @priv: private driver interface data
* @dst: Destination (peer) MAC address
* @action_code: TDLS action code for the mssage
* @dialog_token: Dialog Token to use in the message (if needed)
* @status_code: Status Code or Reason Code to use (if needed)
* @buf: TDLS IEs to add to the message
* @len: Length of buf in octets
* Returns: 0 on success, -1 on failure
*
* This optional function can be used to send packet to driver which is
* responsible for receiving and sending all TDLS packets.
*/
int (*send_tdls_mgmt)(void *priv, const u8 *dst, u8 action_code,
u8 dialog_token, u16 status_code,
const u8 *buf, size_t len);
int (*tdls_oper)(void *priv, enum tdls_oper oper, const u8 *peer);
};
@ -2308,6 +2336,13 @@ enum wpa_event_type {
*/
EVENT_STKSTART,
/**
* EVENT_TDLS - Request TDLS operation
*
* This event can be used to request a TDLS operation to be performed.
*/
EVENT_TDLS,
/**
* EVENT_FT_RESPONSE - Report FT (IEEE 802.11r) response IEs
*
@ -2757,6 +2792,18 @@ union wpa_event_data {
u8 peer[ETH_ALEN];
} stkstart;
/**
* struct tdls - Data for EVENT_TDLS
*/
struct tdls {
u8 peer[ETH_ALEN];
enum {
TDLS_REQUEST_SETUP,
TDLS_REQUEST_TEARDOWN
} oper;
u16 reason_code; /* for teardown */
} tdls;
/**
* struct ft_ies - FT information elements (EVENT_FT_RESPONSE)
*

View file

@ -3324,5 +3324,7 @@ const struct wpa_driver_ops wpa_driver_ndis_ops = {
NULL /* p2p_sd_response */,
NULL /* p2p_service_update */,
NULL /* p2p_reject */,
NULL /* p2p_invite */
NULL /* p2p_invite */,
NULL /* send_tdls_mgmt */,
NULL /* tdls_oper */
};

1700
src/rsn_supp/tdls.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -55,6 +55,12 @@ struct wpa_sm_ctx {
int (*send_ft_action)(void *ctx, u8 action, const u8 *target_ap,
const u8 *ies, size_t ies_len);
int (*mark_authenticated)(void *ctx, const u8 *target_ap);
#ifdef CONFIG_TDLS
int (*send_tdls_mgmt)(void *ctx, const u8 *dst,
u8 action_code, u8 dialog_token,
u16 status_code, const u8 *buf, size_t len);
int (*tdls_oper)(void *ctx, int oper, const u8 *peer);
#endif /* CONFIG_TDLS */
};
@ -330,4 +336,12 @@ wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
#endif /* CONFIG_IEEE80211R */
/* tdls.c */
int wpa_tdls_start(struct wpa_sm *sm, const u8 *addr);
int wpa_tdls_recv_teardown_notify(struct wpa_sm *sm, const u8 *addr,
u16 reason_code);
int wpa_tdls_init(struct wpa_sm *sm);
void wpa_tdls_deinit(struct wpa_sm *sm);
#endif /* WPA_H */

View file

@ -18,6 +18,7 @@
#include "utils/list.h"
struct wpa_peerkey;
struct wpa_tdls_peer;
struct wpa_eapol_key;
/**
@ -43,6 +44,7 @@ struct wpa_sm {
struct l2_packet_data *l2_preauth;
struct l2_packet_data *l2_preauth_br;
struct l2_packet_data *l2_tdls;
u8 preauth_bssid[ETH_ALEN]; /* current RSN pre-auth peer or
* 00:00:00:00:00:00 if no pre-auth is
* in progress */
@ -92,6 +94,9 @@ struct wpa_sm {
#ifdef CONFIG_PEERKEY
struct wpa_peerkey *peerkey;
#endif /* CONFIG_PEERKEY */
#ifdef CONFIG_TDLS
struct wpa_tdls_peer *tdls;
#endif /* CONFIG_TDLS */
#ifdef CONFIG_IEEE80211R
u8 xxkey[PMK_LEN]; /* PSK or the second 256 bits of MSK */
@ -237,6 +242,27 @@ static inline int wpa_sm_mark_authenticated(struct wpa_sm *sm,
return -1;
}
#ifdef CONFIG_TDLS
static inline int wpa_sm_send_tdls_mgmt(struct wpa_sm *sm, const u8 *dst,
u8 action_code, u8 dialog_token,
u16 status_code, const u8 *buf,
size_t len)
{
if (sm->ctx->send_tdls_mgmt)
return sm->ctx->send_tdls_mgmt(sm->ctx->ctx, dst, action_code,
dialog_token, status_code,
buf, len);
return -1;
}
static inline int wpa_sm_tdls_oper(struct wpa_sm *sm, int oper,
const u8 *peer)
{
if (sm->ctx->tdls_oper)
return sm->ctx->tdls_oper(sm->ctx->ctx, oper, peer);
return -1;
}
#endif /* CONFIG_TDLS */
void wpa_eapol_key_send(struct wpa_sm *sm, const u8 *kck,
int ver, const u8 *dest, u16 proto,

View file

@ -397,7 +397,6 @@ int wpa_supplicant_parse_ies(const u8 *buf, size_t len,
ie->rsn_ie_len = pos[1] + 2;
wpa_hexdump(MSG_DEBUG, "WPA: RSN IE in EAPOL-Key",
ie->rsn_ie, ie->rsn_ie_len);
#ifdef CONFIG_IEEE80211R
} else if (*pos == WLAN_EID_MOBILITY_DOMAIN) {
ie->mdie = pos;
ie->mdie_len = pos[1] + 2;
@ -424,7 +423,9 @@ int wpa_supplicant_parse_ies(const u8 *buf, size_t len,
"EAPOL-Key Key Data IE",
pos, 2 + pos[1]);
}
#endif /* CONFIG_IEEE80211R */
} else if (*pos == WLAN_EID_LINK_ID) {
ie->lnkid = pos;
ie->lnkid_len = pos[1] + 2;
} else if (*pos == WLAN_EID_VENDOR_SPECIFIC) {
ret = wpa_parse_generic(pos, end, ie);
if (ret < 0)

View file

@ -41,14 +41,14 @@ struct wpa_eapol_ie_parse {
const u8 *igtk;
size_t igtk_len;
#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_IEEE80211R
const u8 *mdie;
size_t mdie_len;
const u8 *ftie;
size_t ftie_len;
const u8 *reassoc_deadline;
const u8 *key_lifetime;
#endif /* CONFIG_IEEE80211R */
const u8 *lnkid;
size_t lnkid_len;
};
int wpa_supplicant_parse_ies(const u8 *buf, size_t len,

View file

@ -320,6 +320,9 @@ static inline unsigned int wpa_swap_32(unsigned int v)
#ifndef ETH_P_ALL
#define ETH_P_ALL 0x0003
#endif
#ifndef ETH_P_80211_ENCAP
#define ETH_P_80211_ENCAP 0x890d /* TDLS comes under this category */
#endif
#ifndef ETH_P_PAE
#define ETH_P_PAE 0x888E /* Port Access Entity (IEEE 802.1X) */
#endif /* ETH_P_PAE */

View file

@ -142,6 +142,13 @@ NEED_SHA256=y
NEED_AES_OMAC1=y
endif
ifdef CONFIG_TDLS
CFLAGS += -DCONFIG_TDLS
OBJS += ../src/rsn_supp/tdls.o
NEED_SHA256=y
NEED_AES_OMAC1=y
endif
ifdef CONFIG_PEERKEY
CFLAGS += -DCONFIG_PEERKEY
endif

View file

@ -181,6 +181,64 @@ static int wpa_supplicant_ctrl_iface_stkstart(
#endif /* CONFIG_PEERKEY */
#ifdef CONFIG_TDLS
static int wpa_supplicant_ctrl_iface_tdls_discover(
struct wpa_supplicant *wpa_s, char *addr)
{
u8 peer[ETH_ALEN];
if (hwaddr_aton(addr, peer)) {
wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_DISCOVER: invalid "
"address '%s'", addr);
return -1;
}
wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_DISCOVER " MACSTR,
MAC2STR(peer));
return wpa_drv_tdls_oper(wpa_s, TDLS_DISCOVERY_REQ, peer);
}
static int wpa_supplicant_ctrl_iface_tdls_setup(
struct wpa_supplicant *wpa_s, char *addr)
{
u8 peer[ETH_ALEN];
if (hwaddr_aton(addr, peer)) {
wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_SETUP: invalid "
"address '%s'", addr);
return -1;
}
wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_SETUP " MACSTR,
MAC2STR(peer));
return wpa_drv_tdls_oper(wpa_s, TDLS_SETUP, peer);
}
static int wpa_supplicant_ctrl_iface_tdls_teardown(
struct wpa_supplicant *wpa_s, char *addr)
{
u8 peer[ETH_ALEN];
if (hwaddr_aton(addr, peer)) {
wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_TEARDOWN: invalid "
"address '%s'", addr);
return -1;
}
wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_TEARDOWN " MACSTR,
MAC2STR(peer));
return wpa_drv_tdls_oper(wpa_s, TDLS_TEARDOWN, peer);
}
#endif /* CONFIG_TDLS */
#ifdef CONFIG_IEEE80211R
static int wpa_supplicant_ctrl_iface_ft_ds(
struct wpa_supplicant *wpa_s, char *addr)
@ -3118,6 +3176,17 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
} else if (os_strncmp(buf, "STA_AUTOCONNECT ", 16) == 0) {
if (wpa_supplicant_ctrl_iface_sta_autoconnect(wpa_s, buf + 16))
reply_len = -1;
#ifdef CONFIG_TDLS
} else if (os_strncmp(buf, "TDLS_DISCOVER ", 14) == 0) {
if (wpa_supplicant_ctrl_iface_tdls_discover(wpa_s, buf + 14))
reply_len = -1;
} else if (os_strncmp(buf, "TDLS_SETUP ", 11) == 0) {
if (wpa_supplicant_ctrl_iface_tdls_setup(wpa_s, buf + 11))
reply_len = -1;
} else if (os_strncmp(buf, "TDLS_TEARDOWN ", 14) == 0) {
if (wpa_supplicant_ctrl_iface_tdls_teardown(wpa_s, buf + 14))
reply_len = -1;
#endif /* CONFIG_TDLS */
} else {
os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
reply_len = 16;

View file

@ -675,5 +675,25 @@ static inline int wpa_drv_p2p_invite(struct wpa_supplicant *wpa_s,
persistent_group);
}
static inline int wpa_drv_send_tdls_mgmt(struct wpa_supplicant *wpa_s,
const u8 *dst, u8 action_code,
u8 dialog_token, u16 status_code,
const u8 *buf, size_t len)
{
if (wpa_s->driver->send_tdls_mgmt) {
return wpa_s->driver->send_tdls_mgmt(wpa_s->drv_priv, dst,
action_code, dialog_token,
status_code, buf, len);
}
return -1;
}
static inline int wpa_drv_tdls_oper(struct wpa_supplicant *wpa_s,
enum tdls_oper oper, const u8 *peer)
{
if (!wpa_s->driver->tdls_oper)
return -1;
return wpa_s->driver->tdls_oper(wpa_s->drv_priv, oper, peer);
}
#endif /* DRIVER_I_H */

View file

@ -1587,6 +1587,26 @@ wpa_supplicant_event_stkstart(struct wpa_supplicant *wpa_s,
#endif /* CONFIG_PEERKEY */
#ifdef CONFIG_TDLS
static void wpa_supplicant_event_tdls(struct wpa_supplicant *wpa_s,
union wpa_event_data *data)
{
if (data == NULL)
return;
switch (data->tdls.oper) {
case TDLS_REQUEST_SETUP:
wpa_tdls_start(wpa_s->wpa, data->tdls.peer);
break;
case TDLS_REQUEST_TEARDOWN:
/* request from driver to add FTIE */
wpa_tdls_recv_teardown_notify(wpa_s->wpa, data->tdls.peer,
data->tdls.reason_code);
break;
}
}
#endif /* CONFIG_TDLS */
#ifdef CONFIG_IEEE80211R
static void
wpa_supplicant_event_ft_response(struct wpa_supplicant *wpa_s,
@ -1818,6 +1838,11 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
wpa_supplicant_event_stkstart(wpa_s, data);
break;
#endif /* CONFIG_PEERKEY */
#ifdef CONFIG_TDLS
case EVENT_TDLS:
wpa_supplicant_event_tdls(wpa_s, data);
break;
#endif /* CONFIG_TDLS */
#ifdef CONFIG_IEEE80211R
case EVENT_FT_RESPONSE:
wpa_supplicant_event_ft_response(wpa_s, data);

View file

@ -2153,6 +2153,69 @@ static int wpa_cli_cmd_sta_autoconnect(struct wpa_ctrl *ctrl, int argc,
}
static int wpa_cli_cmd_tdls_discover(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
char cmd[256];
int res;
if (argc != 1) {
printf("Invalid TDLS_DISCOVER command: needs one argument "
"(Peer STA MAC address)\n");
return -1;
}
res = os_snprintf(cmd, sizeof(cmd), "TDLS_DISCOVER %s", argv[0]);
if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
printf("Too long TDLS_DISCOVER command.\n");
return -1;
}
return wpa_ctrl_command(ctrl, cmd);
}
static int wpa_cli_cmd_tdls_setup(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
char cmd[256];
int res;
if (argc != 1) {
printf("Invalid TDLS_SETUP command: needs one argument "
"(Peer STA MAC address)\n");
return -1;
}
res = os_snprintf(cmd, sizeof(cmd), "TDLS_SETUP %s", argv[0]);
if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
printf("Too long TDLS_SETUP command.\n");
return -1;
}
return wpa_ctrl_command(ctrl, cmd);
}
static int wpa_cli_cmd_tdls_teardown(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
char cmd[256];
int res;
if (argc != 1) {
printf("Invalid TDLS_TEARDOWN command: needs one argument "
"(Peer STA MAC address)\n");
return -1;
}
res = os_snprintf(cmd, sizeof(cmd), "TDLS_TEARDOWN %s", argv[0]);
if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
printf("Too long TDLS_TEARDOWN command.\n");
return -1;
}
return wpa_ctrl_command(ctrl, cmd);
}
enum wpa_cli_cmd_flags {
cli_cmd_flag_none = 0x00,
cli_cmd_flag_sensitive = 0x01
@ -2450,6 +2513,15 @@ static struct wpa_cli_cmd wpa_cli_commands[] = {
#endif /* CONFIG_P2P */
{ "sta_autoconnect", wpa_cli_cmd_sta_autoconnect, cli_cmd_flag_none,
"<0/1> = disable/enable automatic reconnection" },
{ "tdls_discover", wpa_cli_cmd_tdls_discover,
cli_cmd_flag_none,
"<addr> = request TDLS discovery with <addr>" },
{ "tdls_setup", wpa_cli_cmd_tdls_setup,
cli_cmd_flag_none,
"<addr> = request TDLS setup with <addr>" },
{ "tdls_teardown", wpa_cli_cmd_tdls_teardown,
cli_cmd_flag_none,
"<addr> = tear down TDLS with <addr>" },
{ NULL, NULL, cli_cmd_flag_none, NULL }
};

View file

@ -402,6 +402,10 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
rsn_preauth_deinit(wpa_s->wpa);
#ifdef CONFIG_TDLS
wpa_tdls_deinit(wpa_s->wpa);
#endif /* CONFIG_TDLS */
pmksa_candidate_free(wpa_s->wpa);
wpa_sm_deinit(wpa_s->wpa);
wpa_s->wpa = NULL;
@ -2136,6 +2140,11 @@ next_driver:
if (wpa_supplicant_driver_init(wpa_s) < 0)
return -1;
#ifdef CONFIG_TDLS
if (wpa_tdls_init(wpa_s->wpa))
return -1;
#endif /* CONFIG_TDLS */
if (wpa_s->conf->country[0] && wpa_s->conf->country[1] &&
wpa_drv_set_country(wpa_s, wpa_s->conf->country)) {
wpa_dbg(wpa_s, MSG_DEBUG, "Failed to set country");

View file

@ -535,6 +535,28 @@ static int wpa_supplicant_mark_authenticated(void *ctx, const u8 *target_ap)
#endif /* CONFIG_NO_WPA */
#ifdef CONFIG_TDLS
static int wpa_supplicant_send_tdls_mgmt(void *ctx, const u8 *dst,
u8 action_code, u8 dialog_token,
u16 status_code, const u8 *buf,
size_t len)
{
struct wpa_supplicant *wpa_s = ctx;
return wpa_drv_send_tdls_mgmt(wpa_s, dst, action_code, dialog_token,
status_code, buf, len);
}
static int wpa_supplicant_tdls_oper(void *ctx, int oper, const u8 *peer)
{
struct wpa_supplicant *wpa_s = ctx;
return wpa_drv_tdls_oper(wpa_s, oper, peer);
}
#endif /* CONFIG_TDLS */
#ifdef IEEE8021X_EAPOL
#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
static void wpa_supplicant_eap_param_needed(void *ctx, const char *field,
@ -668,6 +690,10 @@ int wpa_supplicant_init_wpa(struct wpa_supplicant *wpa_s)
ctx->send_ft_action = wpa_supplicant_send_ft_action;
ctx->mark_authenticated = wpa_supplicant_mark_authenticated;
#endif /* CONFIG_IEEE80211R */
#ifdef CONFIG_TDLS
ctx->send_tdls_mgmt = wpa_supplicant_send_tdls_mgmt;
ctx->tdls_oper = wpa_supplicant_tdls_oper;
#endif /* CONFIG_TDLS */
wpa_s->wpa = wpa_sm_init(ctx);
if (wpa_s->wpa == NULL) {