mirror of
https://github.com/Mathewnd/Astral.git
synced 2026-10-31 06:28:22 +00:00
net: port over u80211
This commit is contained in:
@@ -0,0 +1,32 @@
|
||||
#ifndef U80211_AP_H
|
||||
#define U80211_AP_H
|
||||
|
||||
#include <u80211/packet.h>
|
||||
#include <u80211/rbtree.h>
|
||||
|
||||
typedef struct {
|
||||
int refcount;
|
||||
u80211_mac_address_t mac_address;
|
||||
uint16_t interval;
|
||||
uint16_t capabilities;
|
||||
uint8_t channel;
|
||||
uint8_t rate_bitmap[16];
|
||||
char ssid[33];
|
||||
uint8_t *rsn;
|
||||
size_t rsn_size;
|
||||
u80211_rbtree_t cache_node;
|
||||
} u80211_ap_t;
|
||||
|
||||
u80211_ap_t *u80211_ap_allocate(const u80211_beacon_data_t *beacon_data);
|
||||
void u80211_ap_inactive(u80211_ap_t *ap);
|
||||
|
||||
static inline void u80211_ap_hold(u80211_ap_t *ap) {
|
||||
__atomic_add_fetch(&ap->refcount, 1, __ATOMIC_RELAXED);
|
||||
}
|
||||
|
||||
static inline void u80211_ap_release(u80211_ap_t *ap) {
|
||||
if (__atomic_sub_fetch(&ap->refcount, 1, __ATOMIC_RELAXED) == 0)
|
||||
u80211_ap_inactive(ap);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,13 @@
|
||||
#ifndef U80211_ASSOCIATION_H
|
||||
#define U80211_ASSOCIATION_H
|
||||
|
||||
#include <u80211/packet.h>
|
||||
#include <u80211/u80211.h>
|
||||
|
||||
void u80211_association_process_authentication(u80211_device_t *device, u80211_auth_data_t *auth_data); // called from interrupt context
|
||||
void u80211_association_process_response(u80211_device_t *device, u80211_association_response_data_t *association_data); // called from interrupt context
|
||||
void u80211_association_process_deauthentication(u80211_device_t *device, u80211_deauthentication_data_t *deauthentication_data); // called from interrupt context
|
||||
void u80211_association_process_disassociation(u80211_device_t *device, u80211_disassociation_data_t *disassociation_data); // called from interrupt context
|
||||
bool u80211_association_is_duplicate(u80211_device_t *device, const u80211_header_description_t *header, int expected_state); // called from interrupt context
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,24 @@
|
||||
#ifndef U80211_BSS_CACHE_H
|
||||
#define U80211_BSS_CACHE_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <u80211/ap.h>
|
||||
|
||||
typedef struct {
|
||||
void *rwlock;
|
||||
u80211_rbtree_t *root;
|
||||
size_t entry_count;
|
||||
} bss_cache_t;
|
||||
|
||||
int u80211_bss_cache_init(bss_cache_t *cache);
|
||||
void u80211_bss_cache_deinit(bss_cache_t *cache);
|
||||
void u80211_bss_cache_purge(bss_cache_t *cache);
|
||||
void u80211_bss_cache_insert(bss_cache_t *cache, u80211_ap_t *ap);
|
||||
void u80211_bss_cache_remove(bss_cache_t *cache, u80211_mac_address_t *mac);
|
||||
u80211_ap_t *u80211_bss_cache_find(bss_cache_t *cache, u80211_mac_address_t *mac);
|
||||
// each AP pointer written to buffer has an acquired reference that the caller must release.
|
||||
size_t u80211_bss_cache_get_aps(bss_cache_t *cache, u80211_ap_t **buffer, size_t capacity);
|
||||
size_t u80211_bss_cache_get_count(bss_cache_t *cache);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,89 @@
|
||||
#ifndef U80211_KERNEL_INTERFACE_H
|
||||
#define U80211_KERNEL_INTERFACE_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <u80211/u80211.h>
|
||||
|
||||
// allocates 'size' bytes of memory
|
||||
// return NULL on allocation failure
|
||||
void *u80211_kernel_allocate(size_t size);
|
||||
|
||||
// frees the kernel memory referenced by 'ptr'
|
||||
// 'ptr' will never be NULL
|
||||
void u80211_kernel_free(void *ptr);
|
||||
|
||||
// allocates an opaque mutex object
|
||||
// return NULL on allocation failure
|
||||
void *u80211_kernel_allocate_mutex(void);
|
||||
|
||||
// frees the mutex object associated with the 'mutex' pointer
|
||||
// 'mutex' will never be NULL
|
||||
void u80211_kernel_free_mutex(void *mutex);
|
||||
|
||||
// basic mutex operations
|
||||
void u80211_kernel_acquire_mutex(void *mutex);
|
||||
void u80211_kernel_release_mutex(void *mutex);
|
||||
|
||||
// allocates an opaque semaphore object
|
||||
// 'initial_count' contains the initial value of the semaphore
|
||||
void *u80211_kernel_allocate_semaphore(unsigned int initial_count);
|
||||
// frees the semaphore object referenced by 'semaphore'
|
||||
// 'semaphore' will never be NULL
|
||||
void u80211_kernel_free_semaphore(void *semaphore);
|
||||
|
||||
// basic semphore operations
|
||||
void u80211_kernel_wait_semaphore(void *semaphore);
|
||||
void u80211_kernel_signal_semaphore(void *semaphore);
|
||||
|
||||
// allocates an opaque spinlock object
|
||||
// return NULL on allocation failure
|
||||
void *u80211_kernel_allocate_spinlock(void);
|
||||
|
||||
// frees the spinlock object referenced by 'spinlock'
|
||||
// 'spinlock' will never be NULL
|
||||
void u80211_kernel_free_spinlock(void *spinlock);
|
||||
|
||||
// basic spinlock operations
|
||||
// in case the kernel implements interrupt priorities, these functions
|
||||
// must raise/lower it from the network interrupt priority.
|
||||
// otherwise, disable interrupts.
|
||||
void u80211_kernel_acquire_spinlock(void *spinlock);
|
||||
void u80211_kernel_release_spinlock(void *spinlock);
|
||||
|
||||
// allocates an opaque rwlock object
|
||||
// return NULL on allocation failure
|
||||
void *u80211_kernel_allocate_rwlock(void);
|
||||
|
||||
// frees the rwlock object referenced by 'rwlock'
|
||||
// 'spinlock' will never be NULL
|
||||
void u80211_kernel_free_rwlock(void *rwlock);
|
||||
|
||||
// basic rwlock operations
|
||||
// an acquire will always be paired with a release of the same type
|
||||
void u80211_kernel_acquire_rwlock_exclusive(void *rwlock);
|
||||
void u80211_kernel_acquire_rwlock_shared(void *rwlock);
|
||||
void u80211_kernel_release_rwlock_exclusive(void *rwlock);
|
||||
void u80211_kernel_release_rwlock_shared(void *rwlock);
|
||||
|
||||
typedef void (*u80211_kernel_work_fn_t)(void *context);
|
||||
|
||||
// allocates an opaque work object
|
||||
// return NULL on allocation failure
|
||||
void *u80211_kernel_allocate_work(void);
|
||||
|
||||
// enqueue threaded work. this might be called from an interrupt context
|
||||
// 'ms' == 0 enqueues the work immediatelly. otherwise,
|
||||
// work is enqueued 'ms' milliseconds in the future
|
||||
// if work is already pending, the new request must be ignored
|
||||
void u80211_kernel_enqueue_work(void *work, u80211_kernel_work_fn_t function, void *context, size_t ms);
|
||||
|
||||
// frees the work object referenced by 'work'
|
||||
// 'work' will never be NULL
|
||||
// may be called by the work's callback
|
||||
void u80211_kernel_free_work(void *work);
|
||||
|
||||
// kernel packet receive callback
|
||||
// buffer has an ethernet header
|
||||
void u80211_kernel_receive_callback(u80211_device_t *device, void *buffer, size_t size);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,55 @@
|
||||
#ifndef U80211_KEY_H
|
||||
#define U80211_KEY_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <u80211/packet.h>
|
||||
|
||||
typedef enum {
|
||||
U80211_CIPHER_CCMP,
|
||||
U80211_CIPHER_TKIP,
|
||||
U80211_CIPHER_WEP40,
|
||||
U80211_CIPHER_WEP104,
|
||||
} u80211_cipher_t;
|
||||
|
||||
typedef enum {
|
||||
U80211_KEY_PAIRWISE = 1 << 0,
|
||||
U80211_KEY_GROUP = 1 << 1,
|
||||
U80211_KEY_RX = 1 << 2,
|
||||
U80211_KEY_TX = 1 << 3,
|
||||
} u80211_key_flags_t;
|
||||
|
||||
typedef struct {
|
||||
u80211_cipher_t cipher;
|
||||
uint8_t index;
|
||||
u80211_mac_address_t peer;
|
||||
const uint8_t *key;
|
||||
size_t key_len;
|
||||
const uint8_t *rx_seq;
|
||||
size_t rx_seq_len;
|
||||
uint32_t flags;
|
||||
} u80211_key_t;
|
||||
|
||||
typedef struct {
|
||||
const u80211_header_description_t *header;
|
||||
uint8_t key_index;
|
||||
const u80211_mac_address_t *destination;
|
||||
const u80211_mac_address_t *source;
|
||||
uint8_t priority;
|
||||
const void *data;
|
||||
size_t data_size;
|
||||
uint8_t sequence[6];
|
||||
uint8_t mic[8];
|
||||
} u80211_tkip_data_t;
|
||||
|
||||
int u80211_set_key(u80211_device_t *device, const u80211_key_t *key);
|
||||
int u80211_del_key(u80211_device_t *device, uint8_t index, const u80211_mac_address_t *peer, uint32_t flags);
|
||||
int u80211_select_key(u80211_device_t *device, const u80211_header_description_t *header);
|
||||
int u80211_select_cipher(u80211_device_t *device, const u80211_header_description_t *header);
|
||||
int u80211_select_cipher_by_index(u80211_device_t *device, const u80211_header_description_t *header, uint8_t index);
|
||||
bool u80211_key_update_rx_sequence(u80211_device_t *device, const u80211_header_description_t *header, uint8_t index, u80211_cipher_t cipher, const uint8_t *sequence, size_t sequence_size);
|
||||
bool u80211_key_validate_tkip_rx(u80211_device_t *device, const u80211_tkip_data_t *data);
|
||||
bool u80211_key_prepare_tkip_tx(u80211_device_t *device, u80211_tkip_data_t *data);
|
||||
bool u80211_key_next_tx_sequence(u80211_device_t *device, const u80211_header_description_t *header, uint8_t index, u80211_cipher_t cipher, uint8_t *sequence, size_t sequence_size);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,84 @@
|
||||
#ifndef U80211_LIST_H
|
||||
#define U80211_LIST_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
typedef struct u80211_list_node {
|
||||
struct u80211_list_node *prev;
|
||||
struct u80211_list_node *next;
|
||||
} u80211_list_node_t;
|
||||
|
||||
typedef struct {
|
||||
u80211_list_node_t *head;
|
||||
u80211_list_node_t *tail;
|
||||
} u80211_list_t;
|
||||
|
||||
#define U80211_LIST_INIT_VALUE ((u80211_list_t) {.head = NULL, .tail = NULL})
|
||||
|
||||
static inline void u80211_list_init(u80211_list_t *list) {
|
||||
list->head = NULL;
|
||||
list->tail = NULL;
|
||||
}
|
||||
|
||||
static inline void u80211_list_push_front(u80211_list_t *list, u80211_list_node_t *node) {
|
||||
node->prev = NULL;
|
||||
node->next = list->head;
|
||||
if (list->head != NULL) {
|
||||
list->head->prev = node;
|
||||
} else {
|
||||
list->tail = node;
|
||||
}
|
||||
list->head = node;
|
||||
}
|
||||
|
||||
static inline void u80211_list_push_back(u80211_list_t *list, u80211_list_node_t *node) {
|
||||
node->next = NULL;
|
||||
node->prev = list->tail;
|
||||
if (list->tail != NULL) {
|
||||
list->tail->next = node;
|
||||
} else {
|
||||
list->head = node;
|
||||
}
|
||||
list->tail = node;
|
||||
}
|
||||
|
||||
static inline void u80211_list_remove(u80211_list_t *list, u80211_list_node_t *node) {
|
||||
if (node->prev != NULL) {
|
||||
node->prev->next = node->next;
|
||||
} else {
|
||||
list->head = node->next;
|
||||
}
|
||||
if (node->next != NULL) {
|
||||
node->next->prev = node->prev;
|
||||
} else {
|
||||
list->tail = node->prev;
|
||||
}
|
||||
node->prev = NULL;
|
||||
node->next = NULL;
|
||||
}
|
||||
|
||||
static inline u80211_list_node_t *u80211_list_pop_front(u80211_list_t *list) {
|
||||
if (list->head == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
u80211_list_node_t *node = list->head;
|
||||
u80211_list_remove(list, node);
|
||||
return node;
|
||||
}
|
||||
|
||||
static inline u80211_list_node_t *u80211_list_pop_back(u80211_list_t *list) {
|
||||
if (list->tail == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
u80211_list_node_t *node = list->tail;
|
||||
u80211_list_remove(list, node);
|
||||
return node;
|
||||
}
|
||||
|
||||
#define u80211_list_for_each(LIST, ITER) \
|
||||
for (u80211_list_node_t *ITER = (LIST)->head; ITER != NULL; ITER = ITER->next)
|
||||
|
||||
#define u80211_list_for_each_safe(LIST, ITER) \
|
||||
for (u80211_list_node_t *ITER = (LIST)->head, *_next = (ITER ? ITER->next : NULL); ITER != NULL; ITER = _next, _next = (ITER ? ITER->next : NULL))
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,9 @@
|
||||
#ifndef U80211_MICHAEL_H
|
||||
#define U80211_MICHAEL_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
void u80211_michael_mic(const uint8_t key[8], const uint8_t da[6], const uint8_t sa[6], uint8_t priority, const void *data, size_t len, uint8_t out[8]);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,112 @@
|
||||
#ifndef U80211_PACKET_H
|
||||
#define U80211_PACKET_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct u80211_device u80211_device_t;
|
||||
|
||||
typedef struct {
|
||||
void *data;
|
||||
size_t size;
|
||||
size_t current_offset;
|
||||
} u80211_tx_buffer_descriptor_t;
|
||||
|
||||
typedef struct {
|
||||
int key;
|
||||
int cipher;
|
||||
} u80211_transmit_options_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t bytes[6];
|
||||
} u80211_mac_address_t;
|
||||
|
||||
static inline bool u80211_mac_address_equal(const u80211_mac_address_t *a, const u80211_mac_address_t *b) {
|
||||
for (size_t i = 0; i < sizeof(a->bytes); ++i) {
|
||||
if (a->bytes[i] != b->bytes[i])
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#define U80211_HEADER_FRAME_CONTROL_GET_VERSION(x) ((x) & 0x3)
|
||||
#define U80211_HEADER_FRAME_CONTROL_GET_TYPE(x) (((x) & 0xc) >> 2)
|
||||
#define U80211_HEADER_FRAME_CONTROL_TYPE_MANAGEMENT 0
|
||||
#define U80211_HEADER_FRAME_CONTROL_TYPE_CONTROL 1
|
||||
#define U80211_HEADER_FRAME_CONTROL_TYPE_DATA 2
|
||||
#define U80211_HEADER_FRAME_CONTROL_GET_SUBTYPE(x) (((x) & 0xf0) >> 4)
|
||||
#define U80211_HEADER_FRAME_CONTROL_SUBTYPE_ASSOCIATION_REQUEST 0
|
||||
#define U80211_HEADER_FRAME_CONTROL_SUBTYPE_ASSOCIATION_RESPONSE 1
|
||||
#define U80211_HEADER_FRAME_CONTROL_SUBTYPE_PROBE_REQUEST 4
|
||||
#define U80211_HEADER_FRAME_CONTROL_SUBTYPE_PROBE_RESPONSE 5
|
||||
#define U80211_HEADER_FRAME_CONTROL_SUBTYPE_DISASSOCIATION 10
|
||||
#define U80211_HEADER_FRAME_CONTROL_SUBTYPE_AUTHENTICATION 11
|
||||
#define U80211_HEADER_FRAME_CONTROL_SUBTYPE_DEAUTHENTICATION 12
|
||||
#define U80211_HEADER_FRAME_CONTROL_SUBTYPE_DATA 0
|
||||
#define U80211_HEADER_FRAME_CONTROL_SUBTYPE_NULL_DATA 4
|
||||
#define U80211_HEADER_FRAME_CONTROL_TO_DS 0x100
|
||||
#define U80211_HEADER_FRAME_CONTROL_FROM_DS 0x200
|
||||
#define U80211_HEADER_FRAME_CONTROL_MORE_FRAGMENTS 0x400
|
||||
#define U80211_HEADER_FRAME_CONTROL_RETRY 0x800
|
||||
#define U80211_HEADER_FRAME_CONTROL_POWER_MANAGEMENT 0x1000
|
||||
#define U80211_HEADER_FRAME_CONTROL_MORE_DATA 0x2000
|
||||
#define U80211_HEADER_FRAME_CONTROL_PROTECTED_FRAME 0x4000
|
||||
#define U80211_HEADER_FRAME_CONTROL_ORDER 0x8000
|
||||
|
||||
typedef struct {
|
||||
uint16_t frame_control;
|
||||
uint16_t duration_id;
|
||||
u80211_mac_address_t addresses[4];
|
||||
uint16_t sequence_control;
|
||||
} u80211_header_description_t;
|
||||
|
||||
typedef struct {
|
||||
u80211_mac_address_t mac_address;
|
||||
uint16_t interval;
|
||||
uint16_t capabilities;
|
||||
uint8_t channel;
|
||||
uint8_t rate_bitmap[16];
|
||||
char ssid[33];
|
||||
const uint8_t *rsn;
|
||||
size_t rsn_size;
|
||||
} u80211_beacon_data_t;
|
||||
|
||||
#define U80211_AUTH_ALGORITHM_OPEN 0
|
||||
typedef struct {
|
||||
u80211_mac_address_t address;
|
||||
uint16_t auth_algorithm;
|
||||
uint16_t auth_transaction;
|
||||
uint16_t status;
|
||||
} u80211_auth_data_t;
|
||||
|
||||
typedef struct {
|
||||
u80211_mac_address_t address;
|
||||
uint16_t capabilities;
|
||||
uint16_t status;
|
||||
uint16_t association_id;
|
||||
uint8_t rate_bitmap[16];
|
||||
} u80211_association_response_data_t;
|
||||
|
||||
typedef struct {
|
||||
u80211_mac_address_t address;
|
||||
uint16_t reason;
|
||||
} u80211_deauthentication_data_t;
|
||||
|
||||
typedef struct {
|
||||
u80211_mac_address_t address;
|
||||
uint16_t reason;
|
||||
} u80211_disassociation_data_t;
|
||||
|
||||
int u80211_deserialize_header(void *source, size_t source_size, u80211_header_description_t *header, void **data_start, size_t *data_size);
|
||||
int u80211_serialize_header(u80211_header_description_t *header, u80211_tx_buffer_descriptor_t *descriptor);
|
||||
void u80211_process_management_packet(u80211_device_t *device, u80211_header_description_t *header, const void *data, size_t data_size); // called from an interrupt context
|
||||
void u80211_process_data_packet(u80211_device_t *device, u80211_header_description_t *header, void *data, size_t data_size); // called from an interrupt context
|
||||
|
||||
int u80211_send_probe_request(u80211_device_t *device);
|
||||
int u80211_send_authentication(u80211_device_t *device, u80211_auth_data_t *auth_data);
|
||||
int u80211_send_deauthentication(u80211_device_t *device, u80211_deauthentication_data_t *deauthentication_data);
|
||||
int u80211_send_association_request(u80211_device_t *device, const void *information_elements, size_t information_elements_size);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,24 @@
|
||||
#ifndef U80211_RBTREE_H
|
||||
#define U80211_RBTREE_H
|
||||
|
||||
typedef struct u80211_rbtree_t {
|
||||
struct u80211_rbtree_t *left, *right, *parent;
|
||||
} u80211_rbtree_t;
|
||||
|
||||
// return -1 when a < b
|
||||
// return 0 when a = b
|
||||
// return 1 when a > b
|
||||
typedef int (*u80211_rbtree_compare_fn_t)(u80211_rbtree_t *a, u80211_rbtree_t *b);
|
||||
typedef int (*u80211_rbtree_value_compare_fn_t)(void *a, u80211_rbtree_t *b);
|
||||
|
||||
u80211_rbtree_t *u80211_rbtree_lookup(u80211_rbtree_t *rbtree, void *key, u80211_rbtree_value_compare_fn_t compare_fn);
|
||||
void u80211_rbtree_insert(u80211_rbtree_t **rbtreep, u80211_rbtree_t *node, u80211_rbtree_compare_fn_t compare_fn);
|
||||
void u80211_rbtree_remove(u80211_rbtree_t **rbtreep, u80211_rbtree_t *node);
|
||||
void u80211_rbtree_check(u80211_rbtree_t *rbtree);
|
||||
u80211_rbtree_t *u80211_rbtree_first(u80211_rbtree_t *rbtree);
|
||||
u80211_rbtree_t *u80211_rbtree_last(u80211_rbtree_t *rbtree);
|
||||
u80211_rbtree_t *u80211_rbtree_successor(u80211_rbtree_t *node);
|
||||
u80211_rbtree_t *u80211_rbtree_predecessor(u80211_rbtree_t *node);
|
||||
u80211_rbtree_t *u80211_rbtree_find_first_larger_equal(u80211_rbtree_t *rbtree, void *key, u80211_rbtree_value_compare_fn_t compare_fn);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,17 @@
|
||||
#ifndef U80211_REGULATORY_DATABASE_H
|
||||
#define U80211_REGULATORY_DATABASE_H
|
||||
|
||||
// TODO: this will have safe defaults for transmission on all countries.
|
||||
// eventually a proper "database" should be implemented to map a 2-character
|
||||
// country code into channel rules.
|
||||
|
||||
#define U80211_CHANNEL_RULES_DISABLED 1 // no receive/transmission.
|
||||
#define U80211_CHANNEL_RULES_PASSIVE 2 // only transmit when a passive scan returns an AP in that channel.
|
||||
typedef struct {
|
||||
int flags;
|
||||
int max_dbm;
|
||||
} u80211_channel_rules_t;
|
||||
|
||||
u80211_channel_rules_t u80211_get_channel_rules(int channel);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,27 @@
|
||||
#ifndef U80211_RINGBUFFER_H
|
||||
#define U80211_RINGBUFFER_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct {
|
||||
size_t size;
|
||||
uintmax_t write;
|
||||
uintmax_t read;
|
||||
void *data;
|
||||
} u80211_ringbuffer_t;
|
||||
|
||||
int u80211_ringbuffer_init(u80211_ringbuffer_t *ringbuffer, size_t size);
|
||||
void u80211_ringbuffer_destroy(u80211_ringbuffer_t *ringbuffer);
|
||||
|
||||
size_t u80211_ringbuffer_read(u80211_ringbuffer_t *ringbuffer, void *buffer, size_t count);
|
||||
size_t u80211_ringbuffer_write(u80211_ringbuffer_t *ringbuffer, const void *buffer, size_t count);
|
||||
size_t u80211_ringbuffer_truncate(u80211_ringbuffer_t *ringbuffer, size_t count);
|
||||
size_t u80211_ringbuffer_peek(const u80211_ringbuffer_t *ringbuffer, void *buffer, uintmax_t offset, size_t count);
|
||||
size_t u80211_ringbuffer_remove(u80211_ringbuffer_t *ringbuffer, size_t count);
|
||||
|
||||
#define U80211_RINGBUFFER_DATA_COUNT(x) ((x)->write - (x)->read)
|
||||
#define U80211_RINGBUFFER_SIZE(x) ((x)->size)
|
||||
#define U80211_RINGBUFFER_FREE_SPACE(x) (U80211_RINGBUFFER_SIZE(x) - U80211_RINGBUFFER_DATA_COUNT(x))
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,8 @@
|
||||
#ifndef U80211_SCAN_H
|
||||
#define U80211_SCAN_H
|
||||
|
||||
#include <u80211/packet.h>
|
||||
|
||||
void u80211_scan_process_response(u80211_device_t *device, u80211_beacon_data_t *beacon_data);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,16 @@
|
||||
#ifndef U80211_STATUS_H
|
||||
#define U80211_STATUS_H
|
||||
|
||||
#define U80211_STATUS_SUCCESS 0
|
||||
#define U80211_STATUS_ENOMEM 1
|
||||
#define U80211_STATUS_UNSUPPORTED 2
|
||||
#define U80211_STATUS_NOT_ENOUGH_SPACE 3
|
||||
#define U80211_STATUS_BUSY 4
|
||||
#define U80211_STATUS_NOT_PERMITTED 5
|
||||
#define U80211_STATUS_RETRY 6
|
||||
#define U80211_STATUS_REJECTED 7
|
||||
#define U80211_STATUS_TIMED_OUT 8
|
||||
#define U80211_STATUS_NOT_ASSOCIATED 9
|
||||
#define U80211_STATUS_UNKNOWN_ERROR 0xffff
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,10 @@
|
||||
#ifndef U80211_STRING_H
|
||||
#define U80211_STRING_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
void *u80211_memcpy(void *destination, const void *source, size_t size);
|
||||
int u80211_memcmp(const void *a, const void *b, size_t size);
|
||||
void *u80211_memset(void *destination, int value, size_t size);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,100 @@
|
||||
#ifndef U80211_U80211_H
|
||||
#define U80211_U80211_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <u80211/bss_cache.h>
|
||||
#include <u80211/list.h>
|
||||
#include <u80211/packet.h>
|
||||
#include <u80211/ap.h>
|
||||
#include <u80211/key.h>
|
||||
#include <u80211/status.h>
|
||||
|
||||
static inline void *u80211_descriptor_allocate_space(u80211_tx_buffer_descriptor_t *descriptor, size_t size) {
|
||||
if (size > descriptor->current_offset)
|
||||
return NULL;
|
||||
|
||||
descriptor->current_offset -= size;
|
||||
return (uint8_t *)descriptor->data + descriptor->current_offset;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
int (*allocate_tx_buffer)(u80211_device_t *device, size_t size, u80211_tx_buffer_descriptor_t *buffer_descriptor);
|
||||
int (*free_tx_buffer)(u80211_device_t *device, u80211_tx_buffer_descriptor_t *buffer_descriptor);
|
||||
int (*transmit)(u80211_device_t *device, u80211_tx_buffer_descriptor_t *buffer_descriptor, const u80211_transmit_options_t *options);
|
||||
int (*set_channel)(u80211_device_t *device, int channel);
|
||||
int (*set_key)(u80211_device_t *device, const u80211_key_t *key);
|
||||
int (*del_key)(u80211_device_t *device, uint8_t index, const u80211_mac_address_t *peer, uint32_t flags);
|
||||
} u80211_device_ops_t;
|
||||
|
||||
typedef struct {
|
||||
u80211_mac_address_t mac_address;
|
||||
uint8_t rate_bitmap[16];
|
||||
} u80211_device_metadata_t;
|
||||
|
||||
#define U80211_DEVICE_STATE_DOWN 0
|
||||
#define U80211_DEVICE_STATE_SCANNING 1
|
||||
#define U80211_DEVICE_STATE_AUTHENTICATING 2
|
||||
#define U80211_DEVICE_STATE_ASSOCIATING 3
|
||||
#define U80211_DEVICE_STATE_ASSOCIATED 4
|
||||
#define U80211_DEVICE_STATE_DEAUTHENTICATING 5
|
||||
struct u80211_device {
|
||||
u80211_device_metadata_t metadata;
|
||||
void *driver_data;
|
||||
const u80211_device_ops_t *ops;
|
||||
|
||||
int state;
|
||||
size_t packet_count;
|
||||
uint16_t tx_sequence_control;
|
||||
uint16_t received_sequence_control;
|
||||
bool received_sequence_control_valid;
|
||||
void *key_spinlock;
|
||||
u80211_list_t keys;
|
||||
|
||||
void *scan_spinlock;
|
||||
void *scan_context;
|
||||
u80211_list_t scan_waiters;
|
||||
|
||||
bss_cache_t bss_cache;
|
||||
|
||||
void *association_spinlock;
|
||||
void *association_context;
|
||||
void *association_cleanup_work;
|
||||
u80211_list_t association_waiters;
|
||||
unsigned int association_generation;
|
||||
int association_result;
|
||||
u80211_ap_t *ap;
|
||||
u80211_ap_t *disconnected_ap;
|
||||
};
|
||||
|
||||
static inline int u80211_get_device_state(u80211_device_t *device) {
|
||||
return __atomic_load_n(&device->state, __ATOMIC_ACQUIRE);
|
||||
}
|
||||
|
||||
static inline bool u80211_set_device_state(u80211_device_t *device, int old_state, int new_state) {
|
||||
return __atomic_compare_exchange_n(&device->state, &old_state, new_state, false, __ATOMIC_ACQ_REL, __ATOMIC_RELAXED);
|
||||
}
|
||||
|
||||
int u80211_scan(u80211_device_t *device);
|
||||
int u80211_wait_for_scan_completion(u80211_device_t *device);
|
||||
|
||||
void u80211_process_packet(u80211_device_t *device, void *packet, size_t packet_size);
|
||||
|
||||
// these are mostly diagnostic and should not be relied upon
|
||||
size_t u80211_get_packet_count(u80211_device_t *device);
|
||||
void u80211_reset_packet_count(u80211_device_t *device);
|
||||
|
||||
int u80211_register_device(const u80211_device_metadata_t *metadata, const u80211_device_ops_t *ops, void *driver_data, u80211_device_t **device_out);
|
||||
void u80211_unregister_device(u80211_device_t *device);
|
||||
|
||||
int u80211_associate(u80211_device_t *device, u80211_ap_t *ap, const void *information_elements, size_t information_elements_size);
|
||||
int u80211_wait_for_association_completion(u80211_device_t *device);
|
||||
int u80211_disassociate(u80211_device_t *device);
|
||||
|
||||
// allocates an ethernet-sized buffer
|
||||
int u80211_allocate_tx_buffer(u80211_device_t *device, u80211_tx_buffer_descriptor_t *descriptor);
|
||||
// expects an ethernet header. descriptor **must** be a buffer returned by u80211_allocate_tx_buffer.
|
||||
// consumes the descriptor regardless of the returned status.
|
||||
int u80211_transmit_buffer(u80211_device_t *device, u80211_tx_buffer_descriptor_t *descriptor);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,85 @@
|
||||
#ifndef U80211_UTIL_H
|
||||
#define U80211_UTIL_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <u80211/string.h>
|
||||
|
||||
static inline uint16_t u80211_host_to_le16(uint16_t value) {
|
||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
return value;
|
||||
#else
|
||||
return __builtin_bswap16(value);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline uint32_t u80211_host_to_le32(uint32_t value) {
|
||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
return value;
|
||||
#else
|
||||
return __builtin_bswap32(value);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline uint64_t u80211_host_to_le64(uint64_t value) {
|
||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
return value;
|
||||
#else
|
||||
return __builtin_bswap64(value);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline uint16_t u80211_le_to_host16(uint16_t value) {
|
||||
return u80211_host_to_le16(value);
|
||||
}
|
||||
|
||||
static inline uint32_t u80211_le_to_host32(uint32_t value) {
|
||||
return u80211_host_to_le32(value);
|
||||
}
|
||||
|
||||
static inline uint64_t u80211_le_to_host64(uint64_t value) {
|
||||
return u80211_host_to_le64(value);
|
||||
}
|
||||
|
||||
#define host_to_le(value) _Generic((value), \
|
||||
uint16_t: u80211_host_to_le16, \
|
||||
uint32_t: u80211_host_to_le32, \
|
||||
uint64_t: u80211_host_to_le64 \
|
||||
)(value)
|
||||
|
||||
#define le_to_host(value) _Generic((value), \
|
||||
uint16_t: u80211_le_to_host16, \
|
||||
uint32_t: u80211_le_to_host32, \
|
||||
uint64_t: u80211_le_to_host64 \
|
||||
)(value)
|
||||
|
||||
static inline uint16_t deserialize_le16(const void *source) {
|
||||
uint16_t value;
|
||||
u80211_memcpy(&value, source, sizeof(value));
|
||||
return le_to_host(value);
|
||||
}
|
||||
|
||||
static inline uint32_t deserialize_le32(const void *source) {
|
||||
uint32_t value;
|
||||
u80211_memcpy(&value, source, sizeof(value));
|
||||
return le_to_host(value);
|
||||
}
|
||||
|
||||
static inline void serialize_le16(uint8_t *destination, uint16_t value) {
|
||||
uint16_t little_endian_value = host_to_le(value);
|
||||
u80211_memcpy(destination, &little_endian_value, sizeof(little_endian_value));
|
||||
}
|
||||
|
||||
static inline void serialize_le32(uint8_t *destination, uint32_t value) {
|
||||
uint32_t little_endian_value = host_to_le(value);
|
||||
u80211_memcpy(destination, &little_endian_value, sizeof(little_endian_value));
|
||||
}
|
||||
|
||||
#define likely(x) __builtin_expect(!!(x), 1)
|
||||
#define unlikely(x) __builtin_expect(!!(x), 0)
|
||||
#define min(a, b) ((a) < (b) ? (a) : (b))
|
||||
|
||||
#define container_of(ptr, type, member) \
|
||||
((type *)((uintptr_t)ptr - offsetof(type, member)))
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user