Files
刘可亮 803cac77d5 V1.0.6
2024-09-03 11:16:08 +08:00

582 lines
16 KiB
C

/*********************************************************************
*
* @file uwifi_kernel.h
*
* @brief Kernel API definitions.
*
* Copyright (C) ASR 2017
*
**********************************************************************
*/
#ifndef __UWIFI_KERNEL_H__
#define __UWIFI_KERNEL_H__
#include <stdint.h>
#include <stdbool.h>
#include "errno.h"
#include "uwifi_types.h"
#include "asr_rtos.h"
#include "uwifi_ieee80211.h"
#include "uwifi_wlan_list.h"
#include "asr_types.h"
/// Flag bits
#ifndef SCAN_PASSIVE_BIT
#define SCAN_PASSIVE_BIT BIT(0)
#define SCAN_DISABLED_BIT BIT(1)
#endif
/* when open RX BA, RX consumes 3(IPC_RXBUF_CNT)+4(WINDOW_SIZE) buffers, so 8 buffers at least needed */
#define STATIC_SKB_TX_NUM 3
#define DYNAMIC_SKB_TX_NUM 15
#define TOTAL_SKB_NUM (IPC_RXBUF_CNT+CFG_REORD_BUF+STATIC_SKB_TX_NUM) //5 //10
#define MAX_SKB_BUF_SIZE IPC_RXBUF_SIZE
#define min_t(type, x, y) ((x) < (y) ? (x) : (y))
#define max_t(type, x, y) ((x) > (y) ? (x) : (y))
#define __round_mask(x, y) ((__typeof__(x))((y)-1))
#define round_up(x, y) ((((x)-1) | __round_mask(x, y))+1)
#ifndef ARRAY_SIZE
#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x)))
#endif
enum ieee80211_channel_flags {
IEEE80211_CHAN_DISABLED = 1<<0,
IEEE80211_CHAN_NO_IR = 1<<1,
/* hole at 1<<2 */
IEEE80211_CHAN_RADAR = 1<<3,
IEEE80211_CHAN_NO_HT40PLUS = 1<<4,
IEEE80211_CHAN_NO_HT40MINUS = 1<<5,
IEEE80211_CHAN_NO_OFDM = 1<<6,
IEEE80211_CHAN_NO_80MHZ = 1<<7,
IEEE80211_CHAN_NO_160MHZ = 1<<8,
IEEE80211_CHAN_INDOOR_ONLY = 1<<9,
IEEE80211_CHAN_GO_CONCURRENT = 1<<10,
IEEE80211_CHAN_NO_20MHZ = 1<<11,
IEEE80211_CHAN_NO_10MHZ = 1<<12,
};
//add
typedef struct list_head _list;
typedef struct __queue {
struct list_head queue;
asr_mutex_t lock;
} _queue;
/*
* This is an Ethernet frame header.
*/
struct ethhdr {
unsigned char h_dest[ETH_ALEN]; /* destination eth addr */
unsigned char h_source[ETH_ALEN]; /* source ether addr */
uint16_t h_proto; /* packet type ID field */
} __attribute__((packed));
struct iphdrs {
uint8_t ihl:4;
uint8_t version:4;
uint8_t tos;
uint16_t tot_len;
uint16_t id;
uint16_t frag_off;
uint8_t ttl;
uint8_t protocol;
uint16_t check;
uint32_t saddr;
uint32_t daddr;
/*The options start here. */
};
struct asr_pbuf {
struct asr_pbuf* next;
void *payload;
uint16_t tot_len;
uint16_t len;
};
struct sk_buff {
/* These two members must be first. */
struct sk_buff *next;
struct sk_buff *prev;
struct list_head list;
uint32_t len;
uint8_t *end;//fixed can not change after alloc
uint8_t *head;//fixed can not change after alloc
uint8_t *data;//data start
uint8_t *tail; //data tail
uint32_t priority;
/*
* This is the control buffer. It is free to use for every
* layer. Please put your private variables there. If you
* want to keep them across layers you have to do a skb_clone()
* first. This is owned by whoever has the skb queued ATM.
*/
uint32_t private[3];
char cb[48] __attribute__((aligned(8)));
};
#define SK_BUFF_T_SIZE (sizeof(struct sk_buff))
struct sk_buff_head {
/* These two members must be first. */
struct sk_buff *next;
struct sk_buff *prev;
uint32_t qlen;
asr_mutex_t lock;
};
struct skb_priv {
uint32_t free_skb_cnt;
_queue free_skb_queue;
uint8_t * allocated_skb_addr;
uint8_t * skb_addr;
uint8_t tx_skb_cnt;
uint8_t tx_skb_static_cnt;
};
uint8_t *skb_pull(struct sk_buff *skb, uint32_t len);
unsigned char *skb_put(struct sk_buff *skb, unsigned int len);
uint8_t *skb_push(struct sk_buff *skb, uint32_t len);
void skb_queue_tail(struct sk_buff_head *list, struct sk_buff *newsk);
void skb_append(struct sk_buff *old, struct sk_buff *newsk, struct sk_buff_head *list);
void skb_queue_head(struct sk_buff_head *list, struct sk_buff *newsk);
uint8_t *skb_reinit(struct sk_buff *skb);
int32_t wifi_free_pktbuf(struct sk_buff *skb, uint8_t is_tx);
struct sk_buff *wifi_alloc_pktbuf(uint32_t size, uint8_t is_tx);
int32_t wlan_init_skb_priv(void);
void wlan_free_skb_priv(void);
#define dev_alloc_skb_tx(a) wifi_alloc_pktbuf(a, 1)
#define dev_alloc_skb_rx(a) wifi_alloc_pktbuf(a, 0)
#define dev_kfree_skb_tx(a) wifi_free_pktbuf(a, 1)
#define dev_kfree_skb_rx(a) wifi_free_pktbuf(a, 0)
#define skb_queue_walk_safe(queue, skb, tmp) \
for (skb = (queue)->next, tmp = skb->next; \
skb != (struct sk_buff *)(queue); \
skb = tmp, tmp = skb->next)
inline static _list *os_list_get_next(_list *list)
{
return list->next;
}
inline static _list *os_get_queue_head(_queue *queue)
{
return (&(queue->queue));
}
/**
* skb_queue_len - get queue length
* @list_: list to measure
*
* Return the length of an &sk_buff queue.
*/
static inline uint32_t skb_queue_len(const struct sk_buff_head *list_)
{
return list_->qlen;
}
/**
* __skb_queue_head_init - initialize non-spinlock portions of sk_buff_head
* @list: queue to initialize
*
* This initializes only the list and queue length aspects of
* an sk_buff_head object. This allows to initialize the list
* aspects of an sk_buff_head without reinitializing things like
* the spinlock. It can also be used for on-stack sk_buff_head
* objects where the spinlock is known to not be used.
*/
static inline void __skb_queue_head_init(struct sk_buff_head *list)
{
list->prev = list->next = (struct sk_buff *)list;
list->qlen = 0;
}
/*
* This function creates a split out lock class for each invocation;
* this is needed for now since a whole lot of users of the skb-queue
* infrastructure in drivers have different locking usage (in hardirq)
* than the networking core (in softirq only). In the long run either the
* network layer or drivers should need annotation to consolidate the
* main types of usage into 3 classes.
*/
static inline void skb_queue_head_init(struct sk_buff_head *list)
{
asr_rtos_init_mutex(&list->lock); //ldw init spinloc, will adapt to semp or mutex
__skb_queue_head_init(list);
}
/**
* skb_queue_empty - check if a queue is empty
* @list: queue head
*
* Returns true if the queue is empty, false otherwise.
*/
static inline int skb_queue_empty(const struct sk_buff_head *list)
{
return list->next == (const struct sk_buff *) list;
}
/*
* Insert an sk_buff on a list.
*
* The "__skb_xxxx()" functions are the non-atomic ones that
* can only be called with interrupts disabled.
*/
static inline void __skb_insert(struct sk_buff *newsk,
struct sk_buff *prev, struct sk_buff *next,
struct sk_buff_head *list)
{
newsk->next = next;
newsk->prev = prev;
next->prev = prev->next = newsk;
list->qlen++;
}
static inline void __skb_queue_splice(const struct sk_buff_head *list,
struct sk_buff *prev,
struct sk_buff *next)
{
struct sk_buff *first = list->next;
struct sk_buff *last = list->prev;
first->prev = prev;
prev->next = first;
last->next = next;
next->prev = last;
}
/**
* skb_queue_splice - join two skb lists, this is designed for stacks
* @list: the new list to add
* @head: the place to add it in the first list
*/
static inline void skb_queue_splice(const struct sk_buff_head *list,
struct sk_buff_head *head)
{
if (!skb_queue_empty(list)) {
__skb_queue_splice(list, (struct sk_buff *) head, head->next);
head->qlen += list->qlen;
}
}
/**
* skb_queue_splice_init - join two skb lists and reinitialise the emptied list
* @list: the new list to add
* @head: the place to add it in the first list
*
* The list at @list is reinitialised
*/
static inline void skb_queue_splice_init(struct sk_buff_head *list,
struct sk_buff_head *head)
{
if (!skb_queue_empty(list)) {
__skb_queue_splice(list, (struct sk_buff *) head, head->next);
head->qlen += list->qlen;
__skb_queue_head_init(list);
}
}
/**
* skb_queue_splice_tail - join two skb lists, each list being a queue
* @list: the new list to add
* @head: the place to add it in the first list
*/
static inline void skb_queue_splice_tail(const struct sk_buff_head *list,
struct sk_buff_head *head)
{
if (!skb_queue_empty(list)) {
__skb_queue_splice(list, head->prev, (struct sk_buff *) head);
head->qlen += list->qlen;
}
}
/**
* skb_queue_splice_tail_init - join two skb lists and reinitialise the emptied list
* @list: the new list to add
* @head: the place to add it in the first list
*
* Each of the lists is a queue.
* The list at @list is reinitialised
*/
static inline void skb_queue_splice_tail_init(struct sk_buff_head *list,
struct sk_buff_head *head)
{
if (!skb_queue_empty(list)) {
__skb_queue_splice(list, head->prev, (struct sk_buff *) head);
head->qlen += list->qlen;
__skb_queue_head_init(list);
}
}
/**
* skb_peek - peek at the head of an &sk_buff_head
* @list_: list to peek at
*
* Peek an &sk_buff. Unlike most other operations you _MUST_
* be careful with this one. A peek leaves the buffer on the
* list and someone else may run off with it. You must hold
* the appropriate locks or have a private queue to do this.
*
* Returns %NULL for an empty list or a pointer to the head element.
* The reference count is not incremented and the reference is therefore
* volatile. Use with caution.
*/
static inline struct sk_buff *skb_peek(const struct sk_buff_head *list_)
{
struct sk_buff *skb = list_->next;
if (skb == (struct sk_buff *)list_)
skb = NULL;
return skb;
}
static inline void __skb_queue_before(struct sk_buff_head *list,
struct sk_buff *next,
struct sk_buff *newsk)
{
__skb_insert(newsk, next->prev, next, list);
}
static inline void __skb_queue_tail(struct sk_buff_head *list,
struct sk_buff *newsk)
{
__skb_queue_before(list, (struct sk_buff *)list, newsk);
}
/*
* remove sk_buff from list. _Must_ be called atomically, and with
* the list known..
*/
void skb_unlink(struct sk_buff *skb, struct sk_buff_head *list);
static inline void __skb_unlink(struct sk_buff *skb, struct sk_buff_head *list)
{
struct sk_buff *next, *prev;
list->qlen--;
next = skb->next;
prev = skb->prev;
skb->next = skb->prev = NULL;
next->prev = prev;
prev->next = next;
}
/**
* __skb_dequeue - remove from the head of the queue
* @list: list to dequeue from
*
* Remove the head of the list. This function does not take any locks
* so must be used with appropriate locks held only. The head item is
* returned or %NULL if the list is empty.
*/
static inline struct sk_buff *__skb_dequeue(struct sk_buff_head *list)
{
struct sk_buff *skb = skb_peek(list);
if (skb)
__skb_unlink(skb, list);
return skb;
}
/**
* __skb_queue_after - queue a buffer at the list head
* @list: list to use
* @prev: place after this buffer
* @newsk: buffer to queue
*
* Queue a buffer int the middle of a list. This function takes no locks
* and you must therefore hold required locks before calling it.
*
* A buffer cannot be placed on two lists at the same time.
*/
static inline void __skb_queue_after(struct sk_buff_head *list,
struct sk_buff *prev,
struct sk_buff *newsk)
{
__skb_insert(newsk, prev, prev->next, list);
}
/**
* __skb_queue_head - queue a buffer at the list head
* @list: list to use
* @newsk: buffer to queue
*
* Queue a buffer at the start of a list. This function takes no locks
* and you must therefore hold required locks before calling it.
*
* A buffer cannot be placed on two lists at the same time.
*/
static inline void __skb_queue_head(struct sk_buff_head *list,
struct sk_buff *newsk)
{
__skb_queue_after(list, (struct sk_buff *)list, newsk);
}
static inline void __skb_queue_purge(struct sk_buff_head *list)
{
struct sk_buff *skb;
while ((skb = __skb_dequeue(list)) != NULL)
dev_kfree_skb_rx(skb);
}
static inline struct ethhdr *eth_hdr(const struct sk_buff *skb)
{
return (struct ethhdr *)(skb->data);
}
static inline uint8_t ipv4_get_dsfield(const struct iphdrs *iph)
{
return iph->tos;
}
/**
* the dsfield is bit4-bit12 start from the ipv6 header
*/
static inline uint8_t ipv6_get_dsfield(const uint16_t *ipv6h)
{
//return ntohs(*ipv6h) >> 4;
return __be16_to_cpu(*ipv6h) >> 4;
}
/**
* is_multicast_ether_addr - Determine if the Ethernet address is a multicast.
* @addr: Pointer to a six-byte array containing the Ethernet address
*
* Return true if the address is a multicast address.
* By definition the broadcast address is also a multicast address.
*/
static inline bool is_multicast_ether_addr(const uint8_t *addr)
{
return 0x01 & addr[0];
}
/**
* is_broadcast_ether_addr - Determine if the Ethernet address is broadcast
* @addr: Pointer to a six-byte array containing the Ethernet address
*
* Return true if the address is the broadcast address.
*
* Please note: addr must be aligned to u16.
*/
static inline bool is_broadcast_ether_addr(const uint8_t *addr)
{
return (*(const uint16_t *)(addr + 0) &
*(const uint16_t *)(addr + 2) &
*(const uint16_t *)(addr + 4)) == 0xffff;
}
/**
* ether_addr_equal - Compare two Ethernet addresses
* @addr1: Pointer to a six-byte array containing the Ethernet address
* @addr2: Pointer other six-byte array containing the Ethernet address
*
* Compare two Ethernet addresses, returns true if equal
*
* Please note: addr1 & addr2 must both be aligned to u16.
*/
static inline bool ether_addr_equal(const uint8_t *addr1, const uint8_t *addr2)
{
const uint16_t *a = (const uint16_t *)addr1;
const uint16_t *b = (const uint16_t *)addr2;
return ((a[0] ^ b[0]) | (a[1] ^ b[1]) | (a[2] ^ b[2])) == 0;
}
static inline uint8_t passive_scan_flag(uint32_t flags) {
if (flags & (IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_RADAR))
return SCAN_PASSIVE_BIT;
return 0;
}
#if !defined(ALIOS_SUPPORT) && !defined(AWORKS) && !defined(STM32H743xx)
/**
* fls - find last (most-significant) bit set
* @x: the word to search
*
* This is defined the same way as ffs.
* Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32.
*/
static inline int fls(int x)
{
int r = 32;
if (!x)
return 0;
if (!(x & 0xffff0000u)) {
x <<= 16;
r -= 16;
}
if (!(x & 0xff000000u)) {
x <<= 8;
r -= 8;
}
if (!(x & 0xf0000000u)) {
x <<= 4;
r -= 4;
}
if (!(x & 0xc0000000u)) {
x <<= 2;
r -= 2;
}
if (!(x & 0x80000000u)) {
x <<= 1;
r -= 1;
}
return r;
}
#endif
/**
* skb_reserve - adjust headroom
* @skb: buffer to alter
* @len: bytes to move
*
* Increase the headroom of an empty &sk_buff by reducing the tail
* room. This is only allowed for an empty buffer.
*/
static inline void skb_reserve(struct sk_buff *skb, int len)
{
skb->data += len;
skb->tail += len;
}
static inline bool skb_is_nonlinear(const struct sk_buff *skb)
{
return skb->len;
}
/**
* skb_headroom - bytes at buffer head
* @skb: buffer to check
*
* Return the number of bytes of free space at the head of an &sk_buff.
*/
static inline unsigned int skb_headroom(const struct sk_buff *skb)
{
return skb->data - skb->head;
}
/**
* skb_tailroom - bytes at buffer end
* @skb: buffer to check
*
* Return the number of bytes of free space at the tail of an sk_buff
*/
static inline int skb_tailroom(const struct sk_buff *skb)
{
//return skb_is_nonlinear(skb) ? 0 : skb->end - skb->tail;
return skb->end - skb->tail;
}
#endif //__UWIFI_KERNEL_H__