394 lines
12 KiB
C
394 lines
12 KiB
C
#include "capwap.h"
|
|
#include "ieee80211.h"
|
|
|
|
/* */
|
|
static int ieee80211_ie_set_ssid(char* buffer, const char* ssid, int hidessid) {
|
|
struct ieee80211_ie_ssid* iessid = (struct ieee80211_ie_ssid*)buffer;
|
|
|
|
ASSERT(buffer != NULL);
|
|
ASSERT(ssid != NULL);
|
|
|
|
iessid->id = IEEE80211_IE_SSID;
|
|
if (hidessid) {
|
|
iessid->len = 0;
|
|
} else {
|
|
iessid->len = strlen(ssid);
|
|
if (iessid->len > IEEE80211_IE_SSID_MAX_LENGTH) {
|
|
return -1;
|
|
}
|
|
|
|
strncpy((char*)iessid->ssid, ssid, iessid->len);
|
|
}
|
|
|
|
return sizeof(struct ieee80211_ie_ssid) + iessid->len;
|
|
}
|
|
|
|
/* */
|
|
static int ieee80211_ie_set_supportedrates(char* buffer, uint8_t* supportedrates, int supportedratescount) {
|
|
int i;
|
|
int count;
|
|
struct ieee80211_ie_supported_rates* iesupportedrates = (struct ieee80211_ie_supported_rates*)buffer;
|
|
|
|
ASSERT(buffer != NULL);
|
|
ASSERT(supportedrates != NULL);
|
|
ASSERT(supportedratescount > 0);
|
|
|
|
/* IE accept max only 8 rate */
|
|
count = supportedratescount;
|
|
if (count > 8) {
|
|
count = 8;
|
|
}
|
|
|
|
/* */
|
|
iesupportedrates->id = IEEE80211_IE_SUPPORTED_RATES;
|
|
iesupportedrates->len = count;
|
|
|
|
for (i = 0; i < count; i++) {
|
|
iesupportedrates->rates[i] = supportedrates[i];
|
|
}
|
|
|
|
return sizeof(struct ieee80211_ie_supported_rates) + iesupportedrates->len;
|
|
}
|
|
|
|
/* */
|
|
static int ieee80211_ie_set_extendedsupportedrates(char* buffer, uint8_t* supportedrates, int supportedratescount) {
|
|
int i, j;
|
|
struct ieee80211_ie_extended_supported_rates* ieextendedsupportedrates = (struct ieee80211_ie_extended_supported_rates*)buffer;
|
|
|
|
ASSERT(buffer != NULL);
|
|
ASSERT(supportedrates != NULL);
|
|
|
|
/* IE accept only > 8 rate */
|
|
if (supportedratescount <= IEEE80211_IE_SUPPORTED_RATES_MAX_LENGTH) {
|
|
return 0;
|
|
}
|
|
|
|
/* */
|
|
ieextendedsupportedrates->id = IEEE80211_IE_EXTENDED_SUPPORTED_RATES;
|
|
ieextendedsupportedrates->len = supportedratescount - IEEE80211_IE_SUPPORTED_RATES_MAX_LENGTH;
|
|
|
|
for (i = IEEE80211_IE_SUPPORTED_RATES_MAX_LENGTH, j = 0; i < supportedratescount; i++, j++) {
|
|
ieextendedsupportedrates->rates[j] = supportedrates[i];
|
|
}
|
|
|
|
return sizeof(struct ieee80211_ie_extended_supported_rates) + ieextendedsupportedrates->len;
|
|
}
|
|
|
|
/* */
|
|
static int ieee80211_ie_set_dsss(char* buffer, uint8_t channel) {
|
|
struct ieee80211_ie_dsss* iedsss = (struct ieee80211_ie_dsss*)buffer;
|
|
|
|
ASSERT(buffer != NULL);
|
|
|
|
iedsss->id = IEEE80211_IE_DSSS;
|
|
iedsss->len = IEEE80211_IE_DSSS_LENGTH;
|
|
iedsss->channel = channel;
|
|
|
|
return sizeof(struct ieee80211_ie_dsss);
|
|
}
|
|
|
|
/* */
|
|
static int ieee80211_ie_set_erp(char* buffer, uint32_t mode, uint8_t erpinfo) {
|
|
struct ieee80211_ie_erp* ieerp = (struct ieee80211_ie_erp*)buffer;
|
|
|
|
ASSERT(buffer != NULL);
|
|
|
|
if (!(mode & IEEE80211_RADIO_TYPE_80211G)) {
|
|
return 0;
|
|
}
|
|
|
|
ieerp->id = IEEE80211_IE_ERP;
|
|
ieerp->len = IEEE80211_IE_ERP_LENGTH;
|
|
ieerp->params = erpinfo;
|
|
|
|
return sizeof(struct ieee80211_ie_erp);
|
|
}
|
|
|
|
/* */
|
|
uint8_t ieee80211_get_erpinfo(uint32_t mode, int olbc, unsigned long stationnonerpcount, unsigned long stationnoshortpreamblecount, int shortpreamble) {
|
|
uint8_t result = 0;
|
|
|
|
/* Erp mode is valid only in IEEE 802.11 g*/
|
|
if (mode & IEEE80211_RADIO_TYPE_80211G) {
|
|
if (olbc) {
|
|
result |= IEEE80211_ERP_INFO_USE_PROTECTION;
|
|
}
|
|
|
|
if (stationnonerpcount > 0) {
|
|
result |= (IEEE80211_ERP_INFO_NON_ERP_PRESENT | IEEE80211_ERP_INFO_USE_PROTECTION);
|
|
}
|
|
|
|
if (!shortpreamble || (stationnoshortpreamblecount > 0)) {
|
|
result |= IEEE80211_ERP_INFO_BARKER_PREAMBLE_MODE;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
/* */
|
|
int ieee80211_create_beacon(char* buffer, int length, struct ieee80211_beacon_params* params) {
|
|
int result;
|
|
char* pos;
|
|
struct ieee80211_header_mgmt* header;
|
|
|
|
ASSERT(buffer != NULL);
|
|
ASSERT(length == IEEE80211_MTU);
|
|
|
|
/* */
|
|
header = (struct ieee80211_header_mgmt*)buffer;
|
|
params->headbeacon = buffer;
|
|
|
|
/* Management header frame */
|
|
header->framecontrol = IEEE80211_FRAME_CONTROL(IEEE80211_FRAMECONTROL_TYPE_MGMT, IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_BEACON);
|
|
header->durationid = __cpu_to_le16(0);
|
|
memset(header->da, 0xff, ETH_ALEN);
|
|
memcpy(header->sa, params->bssid, ETH_ALEN);
|
|
memcpy(header->bssid, params->bssid, ETH_ALEN);
|
|
header->sequencecontrol = __cpu_to_le16(0);
|
|
memset(header->beacon.timestamp, 0, sizeof(header->beacon.timestamp));
|
|
header->beacon.beaconinterval = __cpu_to_le16(params->beaconperiod);
|
|
header->beacon.capability = __cpu_to_le16(params->capability);
|
|
|
|
/* Header frame size */
|
|
params->headbeaconlength = (int)((uint8_t*)&header->beacon.ie[0] - (uint8_t*)header);
|
|
pos = buffer + params->headbeaconlength;
|
|
|
|
/* Information Element: SSID */
|
|
result = ieee80211_ie_set_ssid(pos, params->ssid, (params->ssid_hidden ? 1 : 0));
|
|
if (result < 0) {
|
|
return -1;
|
|
}
|
|
|
|
pos += result;
|
|
params->headbeaconlength += result;
|
|
|
|
/* Information Element: Supported Rates */
|
|
result = ieee80211_ie_set_supportedrates(pos, params->supportedrates, params->supportedratescount);
|
|
if (result < 0) {
|
|
return -1;
|
|
}
|
|
|
|
pos += result;
|
|
params->headbeaconlength += result;
|
|
|
|
/* Information Element: DSSS */
|
|
result = ieee80211_ie_set_dsss(pos, params->channel);
|
|
if (result < 0) {
|
|
return -1;
|
|
}
|
|
|
|
pos += result;
|
|
params->headbeaconlength += result;
|
|
|
|
/* Separate Information Elements into two block between IE TIM */
|
|
params->tailbeacon = pos;
|
|
params->tailbeaconlength = 0;
|
|
|
|
/* Information Element: Country */
|
|
/* TODO */
|
|
|
|
/* Information Element: ERP */
|
|
result = ieee80211_ie_set_erp(pos, params->mode, params->erpinfo);
|
|
if (result < 0) {
|
|
return -1;
|
|
}
|
|
|
|
pos += result;
|
|
params->tailbeaconlength += result;
|
|
|
|
/* Information Element: Extended Supported Rates */
|
|
result = ieee80211_ie_set_extendedsupportedrates(pos, params->supportedrates, params->supportedratescount);
|
|
if (result < 0) {
|
|
return -1;
|
|
}
|
|
|
|
pos += result;
|
|
params->tailbeaconlength += result;
|
|
|
|
return (params->headbeaconlength + params->tailbeaconlength);
|
|
}
|
|
|
|
/* */
|
|
int ieee80211_create_probe_response(char* buffer, int length, struct ieee80211_probe_response_params* params) {
|
|
int result;
|
|
char* pos;
|
|
int responselength;
|
|
struct ieee80211_header_mgmt* header;
|
|
|
|
ASSERT(buffer != NULL);
|
|
ASSERT(length == IEEE80211_MTU);
|
|
|
|
/* */
|
|
header = (struct ieee80211_header_mgmt*)buffer;
|
|
|
|
/* Management header frame */
|
|
header->framecontrol = IEEE80211_FRAME_CONTROL(IEEE80211_FRAMECONTROL_TYPE_MGMT, IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_PROBE_RESPONSE);
|
|
header->durationid = __cpu_to_le16(0);
|
|
memcpy(header->da, params->station, ETH_ALEN);
|
|
memcpy(header->sa, params->bssid, ETH_ALEN);
|
|
memcpy(header->bssid, params->bssid, ETH_ALEN);
|
|
header->sequencecontrol = __cpu_to_le16(0);
|
|
memset(header->proberesponse.timestamp, 0, sizeof(header->proberesponse.timestamp));
|
|
header->proberesponse.beaconinterval = __cpu_to_le16(params->beaconperiod);
|
|
header->proberesponse.capability = __cpu_to_le16(params->capability);
|
|
|
|
/* Header frame size */
|
|
responselength = (int)((uint8_t*)&header->proberesponse.ie[0] - (uint8_t*)header);
|
|
pos = buffer + responselength;
|
|
|
|
/* Information Element: SSID */
|
|
result = ieee80211_ie_set_ssid(pos, params->ssid, 0);
|
|
if (result < 0) {
|
|
return -1;
|
|
}
|
|
|
|
pos += result;
|
|
responselength += result;
|
|
|
|
/* Information Element: Supported Rates */
|
|
result = ieee80211_ie_set_supportedrates(pos, params->supportedrates, params->supportedratescount);
|
|
if (result < 0) {
|
|
return -1;
|
|
}
|
|
|
|
pos += result;
|
|
responselength += result;
|
|
|
|
/* Information Element: DSSS */
|
|
result = ieee80211_ie_set_dsss(pos, params->channel);
|
|
if (result < 0) {
|
|
return -1;
|
|
}
|
|
|
|
pos += result;
|
|
responselength += result;
|
|
|
|
/* Information Element: Country */
|
|
/* TODO */
|
|
|
|
/* Information Element: ERP */
|
|
result = ieee80211_ie_set_erp(pos, params->mode, params->erpinfo);
|
|
if (result < 0) {
|
|
return -1;
|
|
}
|
|
|
|
pos += result;
|
|
responselength += result;
|
|
|
|
/* Information Element: Extended Supported Rates */
|
|
result = ieee80211_ie_set_extendedsupportedrates(pos, params->supportedrates, params->supportedratescount);
|
|
if (result < 0) {
|
|
return -1;
|
|
}
|
|
|
|
pos += result;
|
|
responselength += result;
|
|
|
|
return responselength;
|
|
}
|
|
|
|
/* */
|
|
int ieee80211_create_authentication_response(char* buffer, int length, struct ieee80211_authentication_params* params) {
|
|
char* pos;
|
|
int responselength;
|
|
struct ieee80211_header_mgmt* header;
|
|
|
|
ASSERT(buffer != NULL);
|
|
ASSERT(length == IEEE80211_MTU);
|
|
|
|
/* */
|
|
header = (struct ieee80211_header_mgmt*)buffer;
|
|
|
|
/* Management header frame */
|
|
header->framecontrol = IEEE80211_FRAME_CONTROL(IEEE80211_FRAMECONTROL_TYPE_MGMT, IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_AUTHENTICATION);
|
|
header->durationid = __cpu_to_le16(0);
|
|
memcpy(header->da, params->station, ETH_ALEN);
|
|
memcpy(header->sa, params->bssid, ETH_ALEN);
|
|
memcpy(header->bssid, params->bssid, ETH_ALEN);
|
|
header->sequencecontrol = __cpu_to_le16(0);
|
|
header->authetication.algorithm = __cpu_to_le16(params->algorithm);
|
|
header->authetication.transactionseqnumber = __cpu_to_le16(params->transactionseqnumber);
|
|
header->authetication.statuscode = __cpu_to_le16(params->statuscode);
|
|
|
|
/* Header frame size */
|
|
responselength = (int)((uint8_t*)&header->authetication.ie[0] - (uint8_t*)header);
|
|
pos = buffer + responselength;
|
|
|
|
/* TODO: add custon IE */
|
|
|
|
return responselength;
|
|
}
|
|
|
|
/* */
|
|
int ieee80211_create_associationresponse_response(char* buffer, int length, struct ieee80211_associationresponse_params* params) {
|
|
char* pos;
|
|
int result;
|
|
int responselength;
|
|
struct ieee80211_header_mgmt* header;
|
|
|
|
ASSERT(buffer != NULL);
|
|
ASSERT(length == IEEE80211_MTU);
|
|
|
|
/* */
|
|
header = (struct ieee80211_header_mgmt*)buffer;
|
|
|
|
/* Management header frame */
|
|
header->framecontrol = IEEE80211_FRAME_CONTROL(IEEE80211_FRAMECONTROL_TYPE_MGMT, IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_ASSOCIATION_RESPONSE);
|
|
header->durationid = __cpu_to_le16(0);
|
|
memcpy(header->da, params->station, ETH_ALEN);
|
|
memcpy(header->sa, params->bssid, ETH_ALEN);
|
|
memcpy(header->bssid, params->bssid, ETH_ALEN);
|
|
header->sequencecontrol = __cpu_to_le16(0);
|
|
header->associationresponse.capability = __cpu_to_le16(params->capability);
|
|
header->associationresponse.statuscode = __cpu_to_le16(params->statuscode);
|
|
header->associationresponse.aid = __cpu_to_le16(params->aid);
|
|
|
|
/* Header frame size */
|
|
responselength = (int)((uint8_t*)&header->associationresponse.ie[0] - (uint8_t*)header);
|
|
pos = buffer + responselength;
|
|
|
|
/* Information Element: Supported Rates */
|
|
result = ieee80211_ie_set_supportedrates(pos, params->supportedrates, params->supportedratescount);
|
|
if (result < 0) {
|
|
return -1;
|
|
}
|
|
|
|
pos += result;
|
|
responselength += result;
|
|
|
|
/* Information Element: Extended Supported Rates */
|
|
result = ieee80211_ie_set_extendedsupportedrates(pos, params->supportedrates, params->supportedratescount);
|
|
if (result < 0) {
|
|
return -1;
|
|
}
|
|
|
|
pos += result;
|
|
responselength += result;
|
|
|
|
return responselength;
|
|
}
|
|
|
|
/* */
|
|
int ieee80211_create_deauthentication(char* buffer, int length, struct ieee80211_deauthentication_params* params) {
|
|
struct ieee80211_header_mgmt* header;
|
|
|
|
ASSERT(buffer != NULL);
|
|
ASSERT(length == IEEE80211_MTU);
|
|
|
|
/* */
|
|
header = (struct ieee80211_header_mgmt*)buffer;
|
|
|
|
/* Management header frame */
|
|
header->framecontrol = IEEE80211_FRAME_CONTROL(IEEE80211_FRAMECONTROL_TYPE_MGMT, IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_DEAUTHENTICATION);
|
|
header->durationid = __cpu_to_le16(0);
|
|
memcpy(header->da, params->station, ETH_ALEN);
|
|
memcpy(header->sa, params->bssid, ETH_ALEN);
|
|
memcpy(header->bssid, params->bssid, ETH_ALEN);
|
|
header->sequencecontrol = __cpu_to_le16(0);
|
|
header->deauthetication.reasoncode = __cpu_to_le16(params->reasoncode);
|
|
|
|
return (int)((uint8_t*)&header->deauthetication.ie[0] - (uint8_t*)header);
|
|
}
|