| /****************************************************************************** |
| * |
| * Copyright (c) 2012 - 2020 Samsung Electronics Co., Ltd. All rights reserved |
| * |
| *****************************************************************************/ |
| |
| #ifndef SLSI_UTILS_H__ |
| #define SLSI_UTILS_H__ |
| |
| #include <linux/version.h> |
| #include <linux/types.h> |
| #include <linux/spinlock.h> |
| #include <linux/workqueue.h> |
| #include <linux/skbuff.h> |
| #include <net/cfg80211.h> |
| #include <netif.h> |
| |
| #include "wakelock.h" |
| #include "fapi.h" |
| |
| static inline u32 slsi_convert_tlv_data_to_value(u8 *data, u16 length) |
| { |
| u32 value = 0; |
| int i; |
| |
| if (length > 4) |
| return 0; |
| for (i = 0; i < length; i++) |
| value |= ((u32)data[i]) << i * 8; |
| |
| return value; |
| } |
| |
| #ifdef __cplusplus |
| extern "C" { |
| #endif |
| |
| #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) |
| #define SLSI_ETHER_COPY(dst, src) ether_addr_copy((dst), (src)) |
| #define SLSI_ETHER_EQUAL(mac1, mac2) ether_addr_equal((mac1), (mac2)) |
| #else |
| #define SLSI_ETHER_COPY(dst, src) memcpy((dst), (src), ETH_ALEN) |
| #define SLSI_ETHER_EQUAL(mac1, mac2) (memcmp((mac1), (mac2), ETH_ALEN) == 0) |
| #endif |
| |
| #ifndef CONFIG_SCSC_SMAPPER |
| struct slsi_skb_cb { |
| u32 sig_length; |
| u32 data_length; |
| u32 frame_format; |
| u32 colour; |
| }; |
| |
| static inline struct slsi_skb_cb *slsi_skb_cb_get(struct sk_buff *skb) |
| { |
| return (struct slsi_skb_cb *)skb->cb; |
| } |
| |
| static inline struct slsi_skb_cb *slsi_skb_cb_init(struct sk_buff *skb) |
| { |
| BUILD_BUG_ON(sizeof(struct slsi_skb_cb) > sizeof(skb->cb)); |
| |
| memset(skb->cb, 0, sizeof(struct slsi_skb_cb)); |
| return slsi_skb_cb_get(skb); |
| } |
| #endif |
| |
| static inline struct sk_buff *fapi_alloc_f(size_t sig_size, size_t data_size, u16 id, u16 vif, const char *file, int line) |
| { |
| struct sk_buff *skb = NULL; |
| struct fapi_vif_signal_header *header; |
| |
| if (WARN_ON(in_interrupt())) |
| return NULL; |
| skb = alloc_skb(sig_size + data_size, GFP_KERNEL); |
| WARN_ON(sig_size < sizeof(struct fapi_signal_header)); |
| if (WARN_ON(!skb)) |
| return NULL; |
| |
| slsi_skb_cb_init(skb)->sig_length = sig_size; |
| slsi_skb_cb_get(skb)->data_length = sig_size; |
| |
| header = (struct fapi_vif_signal_header *)skb_put(skb, sig_size); |
| header->id = cpu_to_le16(id); |
| header->receiver_pid = 0; |
| header->sender_pid = 0; |
| header->fw_reference = 0; |
| header->vif = vif; |
| return skb; |
| } |
| |
| #define fapi_alloc(mp_name, mp_id, mp_vif, mp_datalen) fapi_alloc_f(fapi_sig_size(mp_name), mp_datalen, mp_id, mp_vif, __FILE__, __LINE__) |
| #define fapi_get_buff(mp_skb, mp_name) (((struct fapi_signal *)(mp_skb)->data)->mp_name) |
| #define fapi_get_u16(mp_skb, mp_name) le16_to_cpu(((struct fapi_signal *)(mp_skb)->data)->mp_name) |
| #define fapi_get_u32(mp_skb, mp_name) le32_to_cpu(((struct fapi_signal *)(mp_skb)->data)->mp_name) |
| #define fapi_get_u64(mp_skb, mp_name) le64_to_cpu(((struct fapi_signal *)(mp_skb)->data)->mp_name) |
| #define fapi_set_u16(mp_skb, mp_name, mp_value) (((struct fapi_signal *)(mp_skb)->data)->mp_name = cpu_to_le16(mp_value)) |
| #define fapi_set_u32(mp_skb, mp_name, mp_value) (((struct fapi_signal *)(mp_skb)->data)->mp_name = cpu_to_le32(mp_value)) |
| #define fapi_get_s16(mp_skb, mp_name) ((s16)le16_to_cpu(((struct fapi_signal *)(mp_skb)->data)->mp_name)) |
| #define fapi_get_s32(mp_skb, mp_name) ((s32)le32_to_cpu(((struct fapi_signal *)(mp_skb)->data)->mp_name)) |
| #define fapi_set_s16(mp_skb, mp_name, mp_value) (((struct fapi_signal *)(mp_skb)->data)->mp_name = cpu_to_le16((u16)mp_value)) |
| #define fapi_set_s32(mp_skb, mp_name, mp_value) (((struct fapi_signal *)(mp_skb)->data)->mp_name = cpu_to_le32((u32)mp_value)) |
| #define fapi_set_memcpy(mp_skb, mp_name, mp_value) memcpy(((struct fapi_signal *)(mp_skb)->data)->mp_name, mp_value, sizeof(((struct fapi_signal *)(mp_skb)->data)->mp_name)) |
| #define fapi_set_memset(mp_skb, mp_name, mp_value) memset(((struct fapi_signal *)(mp_skb)->data)->mp_name, mp_value, sizeof(((struct fapi_signal *)(mp_skb)->data)->mp_name)) |
| |
| /* Helper to get and set high/low 16 bits from u32 signals */ |
| #define fapi_get_high16_u32(mp_skb, mp_name) ((fapi_get_u32((mp_skb), mp_name) & 0xffff0000) >> 16) |
| #define fapi_set_high16_u32(mp_skb, mp_name, mp_value) fapi_set_u32((mp_skb), mp_name, (fapi_get_u32((mp_skb), mp_name) & 0xffff) | ((mp_value) << 16)) |
| #define fapi_get_low16_u32(mp_skb, mp_name) (fapi_get_u32((mp_skb), mp_name) & 0xffff) |
| #define fapi_set_low16_u32(mp_skb, mp_name, mp_value) fapi_set_u32((mp_skb), mp_name, (fapi_get_u32((mp_skb), mp_name) & 0xffff0000) | (mp_value)) |
| |
| #define fapi_get_siglen(mp_skb) (slsi_skb_cb_get(mp_skb)->sig_length) |
| #define fapi_get_datalen(mp_skb) (slsi_skb_cb_get(mp_skb)->data_length - slsi_skb_cb_get(mp_skb)->sig_length) |
| #define fapi_get_data(mp_skb) (mp_skb->data + fapi_get_siglen(mp_skb)) |
| #define fapi_get_vif(mp_skb) le16_to_cpu(((struct fapi_vif_signal_header *)(mp_skb)->data)->vif) |
| |
| /* Helper to get the struct ieee80211_mgmt from the data */ |
| #define fapi_get_mgmt(mp_skb) ((struct ieee80211_mgmt *)fapi_get_data(mp_skb)) |
| #define fapi_get_mgmtlen(mp_skb) fapi_get_datalen(mp_skb) |
| |
| |
| static inline u8 *fapi_append_data(struct sk_buff *skb, const u8 *data, size_t data_len) |
| { |
| u8 *p; |
| |
| if (WARN_ON(skb_tailroom(skb) < data_len)) |
| return NULL; |
| |
| p = skb_put(skb, data_len); |
| slsi_skb_cb_get(skb)->data_length += data_len; |
| if (data) |
| memcpy(p, data, data_len); |
| return p; |
| } |
| |
| static inline u8 *fapi_append_data_u32(struct sk_buff *skb, const u32 data) |
| { |
| __le32 val = cpu_to_le32(data); |
| |
| return fapi_append_data(skb, (u8 *)&val, sizeof(val)); |
| } |
| |
| static inline u8 *fapi_append_data_u16(struct sk_buff *skb, const u16 data) |
| { |
| __le16 val = cpu_to_le16(data); |
| |
| return fapi_append_data(skb, (u8 *)&val, sizeof(val)); |
| } |
| |
| static inline u8 *fapi_append_data_u8(struct sk_buff *skb, const u8 data) |
| { |
| u8 val = data; |
| |
| return fapi_append_data(skb, (u8 *)&val, sizeof(val)); |
| } |
| |
| #define fapi_append_data_bool(skb, data) fapi_append_data_u16(skb, data) |
| |
| extern uint slsi_sg_host_align_mask; |
| #define SLSI_HIP_FH_SIG_PREAMBLE_LEN 4 |
| #define SLSI_SKB_GET_ALIGNMENT_OFFSET(skb) (0) |
| |
| /* Get the Compiler to ignore Unused parameters */ |
| #define SLSI_UNUSED_PARAMETER(x) ((void)(x)) |
| #ifdef UFK6_DEBUG |
| #define SLSI_UNUSED_PARAMETER_NOT_DEBUG(x) |
| #else |
| #define SLSI_UNUSED_PARAMETER_NOT_DEBUG(x) ((void)(x)) |
| #endif |
| |
| /* Helper ERROR Macros */ |
| #define SLSI_ECR(func) \ |
| do { \ |
| int _err = (func); \ |
| if (_err != 0) { \ |
| SLSI_ERR_NODEV("e=%d\n", _err); \ |
| return _err; \ |
| } \ |
| } while (0) |
| |
| #define SLSI_EC(func) \ |
| do { \ |
| int _err = (func); \ |
| if (_err != 0) { \ |
| SLSI_ERR_NODEV("e=%d\n", _err); \ |
| return; \ |
| } \ |
| } while (0) |
| |
| #define SLSI_EC_GOTO(func, err, label) \ |
| do { \ |
| (err) = func; \ |
| if ((err) != 0) { \ |
| WARN_ON(1); \ |
| SLSI_ERR(sdev, "fail at line:%d\n", __LINE__); \ |
| goto label; \ |
| } \ |
| } while (0) |
| |
| /*------------------------------------------------------------------*/ |
| /* Endian conversion. */ |
| /*------------------------------------------------------------------*/ |
| #define SLSI_BUFF_LE_TO_U16(ptr) (((u16)((u8 *)(ptr))[0]) | ((u16)((u8 *)(ptr))[1]) << 8) |
| #define SLSI_U16_TO_BUFF_LE(uint, ptr) \ |
| do { \ |
| u32 local_uint_tmp = (uint); \ |
| ((u8 *)(ptr))[0] = ((u8)((local_uint_tmp & 0x00FF))); \ |
| ((u8 *)(ptr))[1] = ((u8)(local_uint_tmp >> 8)); \ |
| } while (0) |
| |
| #define SLSI_U32_TO_BUFF_LE(uint, ptr) ((*(u32 *)ptr) = cpu_to_le32(uint)) |
| |
| #define SLSI_BUFF_LE_TO_U16_P(output, input) \ |
| do { \ |
| (output) = (u16)((((u16)(input)[1]) << 8) | ((u16)(input)[0])); \ |
| (input) += 2; \ |
| } while (0) |
| |
| #define SLSI_BUFF_LE_TO_U32_P(output, input) \ |
| do { \ |
| (output) = le32_to_cpu(*(u32 *)input); \ |
| (input) += 4; \ |
| } while (0) |
| |
| #define SLSI_U16_TO_BUFF_LE_P(output, input) \ |
| do { \ |
| (output)[0] = ((u8)((input) & 0x00FF)); \ |
| (output)[1] = ((u8)((input) >> 8)); \ |
| (output) += 2; \ |
| } while (0) |
| |
| #define SLSI_U32_TO_BUFF_LE_P(output, input) \ |
| do { \ |
| (*(u32 *)output) = cpu_to_le32(input); \ |
| (output) += 4; \ |
| } while (0) |
| |
| #ifdef CONFIG_SCSC_WLAN_SKB_TRACKING |
| void slsi_dbg_track_skb_init(void); |
| void slsi_dbg_track_skb_reset(void); |
| void slsi_dbg_track_skb_f(struct sk_buff *skb, gfp_t flags, const char *file, int line); |
| bool slsi_dbg_untrack_skb_f(struct sk_buff *skb, const char *file, int line); |
| bool slsi_dbg_track_skb_marker_f(struct sk_buff *skb, const char *file, int line); |
| #define slsi_dbg_track_skb(skb_, flags_) slsi_dbg_track_skb_f(skb_, flags_, __FILE__, __LINE__) |
| #define slsi_dbg_untrack_skb(skb_) slsi_dbg_untrack_skb_f(skb_, __FILE__, __LINE__) |
| #define slsi_dbg_track_skb_marker(skb_) slsi_dbg_track_skb_marker_f(skb_, __FILE__, __LINE__) |
| void slsi_dbg_track_skb_report(void); |
| void slsi_dbg_skb_device_add(void); |
| void slsi_dbg_skb_device_remove(void); |
| |
| static inline struct sk_buff *slsi_dev_alloc_skb_f(unsigned int length, const char *file, int line) |
| { |
| struct sk_buff *skb = dev_alloc_skb(SLSI_NETIF_SKB_HEADROOM + SLSI_NETIF_SKB_TAILROOM + length); |
| |
| if (skb) { |
| skb_reserve(skb, SLSI_NETIF_SKB_HEADROOM - SLSI_SKB_GET_ALIGNMENT_OFFSET(skb)); |
| slsi_dbg_track_skb_f(skb, GFP_ATOMIC, file, line); |
| } |
| return skb; |
| } |
| |
| static inline struct sk_buff *slsi_alloc_skb_f(unsigned int size, gfp_t priority, const char *file, int line) |
| { |
| struct sk_buff *skb = alloc_skb(SLSI_NETIF_SKB_HEADROOM + SLSI_NETIF_SKB_TAILROOM + size, priority); |
| |
| if (skb) { |
| skb_reserve(skb, SLSI_NETIF_SKB_HEADROOM - SLSI_SKB_GET_ALIGNMENT_OFFSET(skb)); |
| slsi_dbg_track_skb_f(skb, priority, file, line); |
| } |
| return skb; |
| } |
| |
| static inline void slsi_skb_unlink_f(struct sk_buff *skb, struct sk_buff_head *list, const char *file, int line) |
| { |
| skb_unlink(skb, list); |
| slsi_dbg_track_skb_marker_f(skb, file, line); |
| } |
| |
| static inline void slsi_skb_queue_tail_f(struct sk_buff_head *list, struct sk_buff *skb, const char *file, int line) |
| { |
| skb_queue_tail(list, skb); |
| slsi_dbg_track_skb_marker_f(skb, file, line); |
| } |
| |
| static inline void slsi_skb_queue_head_f(struct sk_buff_head *list, struct sk_buff *skb, const char *file, int line) |
| { |
| skb_queue_head(list, skb); |
| slsi_dbg_track_skb_marker_f(skb, file, line); |
| } |
| |
| static inline struct sk_buff *slsi_skb_dequeue_f(struct sk_buff_head *list, const char *file, int line) |
| { |
| struct sk_buff *skb = skb_dequeue(list); |
| |
| if (skb) |
| slsi_dbg_track_skb_marker_f(skb, file, line); |
| return skb; |
| } |
| |
| static inline struct sk_buff *slsi_skb_realloc_headroom_f(struct sk_buff *skb, unsigned int headroom, const char *file, int line) |
| { |
| skb = skb_realloc_headroom(skb, headroom); |
| if (skb) |
| slsi_dbg_track_skb_f(skb, GFP_ATOMIC, file, line); |
| return skb; |
| } |
| |
| static inline struct sk_buff *slsi_skb_copy_f(struct sk_buff *skb, gfp_t priority, const char *file, int line) |
| { |
| skb = skb_copy(skb, priority); |
| |
| if (skb) |
| slsi_dbg_track_skb_f(skb, priority, file, line); |
| return skb; |
| } |
| |
| static inline struct sk_buff *skb_copy_expand_f(struct sk_buff *skb, int newheadroom, int newtailroom, gfp_t priority, const char *file, int line) |
| { |
| skb = skb_copy_expand(skb, newheadroom, newtailroom, priority); |
| |
| if (skb) |
| slsi_dbg_track_skb_f(skb, priority, file, line); |
| return skb; |
| } |
| |
| static inline struct sk_buff *slsi_skb_clone_f(struct sk_buff *skb, gfp_t priority, const char *file, int line) |
| { |
| skb = skb_clone(skb, priority); |
| |
| if (skb) |
| slsi_dbg_track_skb_f(skb, priority, file, line); |
| return skb; |
| } |
| |
| static inline void slsi_kfree_skb_f(struct sk_buff *skb, const char *file, int line) |
| { |
| /* If untrack fails we do not free the SKB |
| * This helps tracking bad pointers and double frees |
| */ |
| if (skb && slsi_dbg_untrack_skb_f(skb, file, line)) |
| kfree_skb(skb); |
| } |
| |
| #define slsi_dev_alloc_skb(length_) slsi_dev_alloc_skb_f(length_, __FILE__, __LINE__) |
| #define slsi_alloc_skb(size_, priority_) slsi_alloc_skb_f(size_, priority_, __FILE__, __LINE__) |
| #define slsi_skb_realloc_headroom(skb_, headroom_) slsi_skb_realloc_headroom_f(skb_, headroom_, __FILE__, __LINE__) |
| #define slsi_skb_copy(skb_, priority_) slsi_skb_copy_f(skb_, priority_, __FILE__, __LINE__) |
| #define slsi_skb_copy_expand(skb_, newheadroom_, newtailroom_, priority_) skb_copy_expand_f(skb_, newheadroom_, newtailroom_, priority_, __FILE__, __LINE__) |
| #define slsi_skb_clone(skb_, priority_) slsi_skb_clone_f(skb_, priority_, __FILE__, __LINE__) |
| #define slsi_kfree_skb(skb_) slsi_kfree_skb_f(skb_, __FILE__, __LINE__) |
| #define slsi_skb_unlink(skb_, list_) slsi_skb_unlink_f(skb_, list_, __FILE__, __LINE__) |
| #define slsi_skb_queue_tail(list_, skb_) slsi_skb_queue_tail_f(list_, skb_, __FILE__, __LINE__) |
| #define slsi_skb_queue_head(list_, skb_) slsi_skb_queue_head_f(list_, skb_, __FILE__, __LINE__) |
| #define slsi_skb_dequeue(list_) slsi_skb_dequeue_f(list_, __FILE__, __LINE__) |
| |
| static inline void slsi_skb_queue_purge(struct sk_buff_head *list) |
| { |
| struct sk_buff *skb; |
| |
| while ((skb = skb_dequeue(list)) != NULL) |
| slsi_kfree_skb(skb); |
| } |
| |
| #else |
| #define slsi_dbg_track_skb_init() |
| #define slsi_dbg_track_skb_reset() |
| #define slsi_dbg_track_skb(skb_, flags_) |
| #define slsi_dbg_untrack_skb(skb_) |
| #define slsi_dbg_track_skb_marker(skb_) |
| #define slsi_dbg_track_skb_report() |
| #define slsi_dbg_skb_device_add() |
| #define slsi_dbg_skb_device_remove() |
| |
| static inline struct sk_buff *slsi_dev_alloc_skb_f(unsigned int length, const char *file, int line) |
| { |
| struct sk_buff *skb = dev_alloc_skb(SLSI_NETIF_SKB_HEADROOM + SLSI_NETIF_SKB_TAILROOM + length); |
| |
| SLSI_UNUSED_PARAMETER(file); |
| SLSI_UNUSED_PARAMETER(line); |
| |
| if (skb) |
| skb_reserve(skb, SLSI_NETIF_SKB_HEADROOM - SLSI_SKB_GET_ALIGNMENT_OFFSET(skb)); |
| return skb; |
| } |
| |
| static inline struct sk_buff *slsi_alloc_skb_f(unsigned int size, gfp_t priority, const char *file, int line) |
| { |
| struct sk_buff *skb = alloc_skb(SLSI_NETIF_SKB_HEADROOM + SLSI_NETIF_SKB_TAILROOM + size, priority); |
| |
| SLSI_UNUSED_PARAMETER(file); |
| SLSI_UNUSED_PARAMETER(line); |
| |
| if (skb) |
| skb_reserve(skb, SLSI_NETIF_SKB_HEADROOM - SLSI_SKB_GET_ALIGNMENT_OFFSET(skb)); |
| return skb; |
| } |
| |
| #define slsi_dev_alloc_skb(length_) slsi_dev_alloc_skb_f(length_, __FILE__, __LINE__) |
| #define slsi_alloc_skb(size_, priority_) slsi_alloc_skb_f(size_, priority_, __FILE__, __LINE__) |
| #define slsi_skb_realloc_headroom(skb_, headroom_) skb_realloc_headroom(skb_, headroom_) |
| #define slsi_skb_copy(skb_, priority_) skb_copy(skb_, priority_) |
| #define slsi_skb_copy_expand(skb_, newheadroom_, newtailroom_, priority_) skb_copy_expand(skb_, newheadroom_, newtailroom_, priority_) |
| #define slsi_skb_clone(skb_, priority_) skb_clone(skb_, priority_) |
| #define slsi_kfree_skb(skb_) kfree_skb(skb_) |
| #define slsi_skb_unlink(skb_, list_) skb_unlink(skb_, list_) |
| #define slsi_skb_queue_tail(list_, skb_) skb_queue_tail(list_, skb_) |
| #define slsi_skb_queue_head(list_, skb_) skb_queue_head(list_, skb_) |
| #define slsi_skb_dequeue(list_) skb_dequeue(list_) |
| #define slsi_skb_queue_purge(list_) skb_queue_purge(list_) |
| #endif |
| |
| struct slsi_spinlock { |
| /* a std spinlock */ |
| spinlock_t lock; |
| unsigned long flags; |
| }; |
| |
| /* Spinlock create can't fail, so return success regardless. */ |
| static inline void slsi_spinlock_create(struct slsi_spinlock *lock) |
| { |
| spin_lock_init(&lock->lock); |
| } |
| |
| static inline void slsi_spinlock_lock(struct slsi_spinlock *lock) |
| { |
| spin_lock_bh(&lock->lock); |
| } |
| |
| static inline void slsi_spinlock_unlock(struct slsi_spinlock *lock) |
| { |
| spin_unlock_bh(&lock->lock); |
| } |
| |
| struct slsi_dev; |
| struct slsi_skb_work { |
| struct slsi_dev *sdev; |
| struct net_device *dev; /* This can be NULL */ |
| struct workqueue_struct *workqueue; |
| struct work_struct work; |
| struct sk_buff_head queue; |
| void __rcu *sync_ptr; |
| }; |
| |
| static inline int slsi_skb_work_init(struct slsi_dev *sdev, struct net_device *dev, struct slsi_skb_work *work, const char *name, void (*func)(struct work_struct *work)) |
| { |
| rcu_assign_pointer(work->sync_ptr, (void *)sdev); |
| work->sdev = sdev; |
| work->dev = dev; |
| skb_queue_head_init(&work->queue); |
| INIT_WORK(&work->work, func); |
| work->workqueue = alloc_ordered_workqueue(name, 0); |
| |
| if (!work->workqueue) |
| return -ENOMEM; |
| return 0; |
| } |
| |
| static inline void slsi_skb_schedule_work(struct slsi_skb_work *work) |
| { |
| queue_work(work->workqueue, &work->work); |
| } |
| |
| static inline void slsi_skb_work_enqueue_l(struct slsi_skb_work *work, struct sk_buff *skb) |
| { |
| void *sync_ptr; |
| |
| rcu_read_lock(); |
| |
| sync_ptr = rcu_dereference(work->sync_ptr); |
| |
| if (WARN_ON(!sync_ptr)) { |
| slsi_kfree_skb(skb); |
| rcu_read_unlock(); |
| return; |
| } |
| skb_queue_tail(&work->queue, skb); |
| slsi_skb_schedule_work(work); |
| |
| rcu_read_unlock(); |
| } |
| |
| static inline struct sk_buff *slsi_skb_work_dequeue_l(struct slsi_skb_work *work) |
| { |
| return skb_dequeue(&work->queue); |
| } |
| |
| static inline void slsi_skb_work_deinit(struct slsi_skb_work *work) |
| { |
| rcu_read_lock(); |
| |
| if (WARN_ON(!work->sync_ptr)) { |
| rcu_read_unlock(); |
| return; |
| } |
| |
| rcu_assign_pointer(work->sync_ptr, NULL); |
| rcu_read_unlock(); |
| |
| synchronize_rcu(); |
| flush_workqueue(work->workqueue); |
| destroy_workqueue(work->workqueue); |
| work->workqueue = NULL; |
| slsi_skb_queue_purge(&work->queue); |
| } |
| |
| static inline void slsi_cfg80211_put_bss(struct wiphy *wiphy, struct cfg80211_bss *bss) |
| { |
| #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)) |
| cfg80211_put_bss(wiphy, bss); |
| #else |
| cfg80211_put_bss(bss); |
| #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)) */ |
| } |
| |
| #ifdef CONFIG_SCSC_WLAN_SKB_TRACKING |
| static inline void slsi_skb_work_enqueue_f(struct slsi_skb_work *work, struct sk_buff *skb, const char *file, int line) |
| { |
| slsi_dbg_track_skb_marker_f(skb, file, line); |
| slsi_skb_work_enqueue_l(work, skb); |
| } |
| |
| static inline struct sk_buff *slsi_skb_work_dequeue_f(struct slsi_skb_work *work, const char *file, int line) |
| { |
| struct sk_buff *skb; |
| |
| skb = slsi_skb_work_dequeue_l(work); |
| if (skb) |
| slsi_dbg_track_skb_marker_f(skb, file, line); |
| return skb; |
| } |
| |
| #define slsi_skb_work_enqueue(work_, skb_) slsi_skb_work_enqueue_f(work_, skb_, __FILE__, __LINE__) |
| #define slsi_skb_work_dequeue(work_) slsi_skb_work_dequeue_f(work_, __FILE__, __LINE__) |
| #else |
| #define slsi_skb_work_enqueue(work_, skb_) slsi_skb_work_enqueue_l(work_, skb_) |
| #define slsi_skb_work_dequeue(work_) slsi_skb_work_dequeue_l(work_) |
| #endif |
| |
| static inline void slsi_eth_zero_addr(u8 *addr) |
| { |
| memset(addr, 0x00, ETH_ALEN); |
| } |
| |
| static inline void slsi_eth_broadcast_addr(u8 *addr) |
| { |
| memset(addr, 0xff, ETH_ALEN); |
| } |
| |
| static inline int slsi_str_to_int(char *str, int *result) |
| { |
| int i = 0; |
| int sign = 1; |
| int err = 0; |
| long long int res = 0; |
| int digit = 0; |
| |
| if (!str) |
| return 0; |
| if (*str == '-') { |
| sign = -1; |
| ++str; |
| } else if (*str == '+') { |
| sign = 1; |
| ++str; |
| } |
| |
| *result = 0; |
| if ((str[i] >= '0') && (str[i] <= '9')) { |
| while (str[i] >= '0' && str[i] <= '9') { |
| if (res > INT_MAX / 10) { |
| err = 1; |
| break; |
| } |
| res *= 10; |
| digit = str[i] - '0'; |
| |
| if (res > INT_MAX - digit) { |
| if (sign == -1) { |
| res += digit; |
| if (-(res) >= INT_MIN) { |
| break; |
| } else { |
| err = 1; |
| break; |
| } |
| } else { |
| err = 1; |
| break; |
| } |
| } |
| res += digit; |
| i++; |
| } |
| |
| if (!err) |
| *result = ((sign == -1) ? -(res) : res); |
| else |
| return 0; |
| } |
| return i; |
| } |
| |
| #define P80211_OUI_LEN 3 |
| |
| struct ieee80211_snap_hdr { |
| u8 dsap; /* always 0xAA */ |
| u8 ssap; /* always 0xAA */ |
| u8 ctrl; /* always 0x03 */ |
| u8 oui[P80211_OUI_LEN]; /* organizational universal id */ |
| } __packed; |
| |
| struct msdu_hdr { |
| unsigned char da[ETH_ALEN]; |
| unsigned char sa[ETH_ALEN]; |
| __be16 length; |
| struct ieee80211_snap_hdr snap; |
| __be16 ether_type; |
| } __packed; |
| |
| #define ETHER_TYPE_SIZE 2 |
| #define MSDU_HLEN sizeof(struct msdu_hdr) |
| #define MSDU_LENGTH (sizeof(struct ieee80211_snap_hdr) + sizeof(__be16)) |
| |
| static inline int slsi_skb_msdu_to_ethhdr(struct sk_buff *skb) |
| { |
| struct ethhdr *eth; |
| struct msdu_hdr *msdu; |
| |
| unsigned char da[ETH_ALEN]; |
| unsigned char sa[ETH_ALEN]; |
| __be16 proto; |
| |
| msdu = (struct msdu_hdr *)skb->data; |
| SLSI_ETHER_COPY(da, msdu->da); |
| SLSI_ETHER_COPY(sa, msdu->sa); |
| proto = msdu->ether_type; |
| |
| skb_pull(skb, MSDU_HLEN); |
| |
| eth = (struct ethhdr *)skb_push(skb, ETH_HLEN); |
| |
| SLSI_ETHER_COPY(eth->h_dest, da); |
| SLSI_ETHER_COPY(eth->h_source, sa); |
| eth->h_proto = proto; |
| |
| return 0; |
| } |
| |
| static inline int slsi_skb_ethhdr_to_msdu(struct sk_buff *skb) |
| { |
| struct ethhdr *eth; |
| struct msdu_hdr *msdu; |
| unsigned int len; |
| __be16 ether_type; |
| |
| if (skb_headroom(skb) < (MSDU_HLEN - ETH_HLEN)) |
| return -EINVAL; |
| |
| eth = eth_hdr(skb); |
| ether_type = eth->h_proto; |
| |
| len = skb->len; |
| |
| skb_pull(skb, ETH_HLEN); |
| |
| msdu = (struct msdu_hdr *)skb_push(skb, MSDU_HLEN); |
| |
| SLSI_ETHER_COPY(msdu->da, eth->h_dest); |
| SLSI_ETHER_COPY(msdu->sa, eth->h_source); |
| msdu->length = htons(len - ETH_HLEN + MSDU_LENGTH); |
| memcpy(&msdu->snap, rfc1042_header, sizeof(struct ieee80211_snap_hdr)); |
| msdu->ether_type = ether_type; |
| |
| return 0; |
| } |
| |
| static inline u32 slsi_get_center_freq1(struct slsi_dev *sdev, u16 chann_info, u16 center_freq) |
| { |
| u32 center_freq1 = 0x0000; |
| |
| SLSI_UNUSED_PARAMETER(sdev); |
| |
| switch (chann_info & 0xFF) { |
| case 40: |
| center_freq1 = center_freq - 20 * ((chann_info & 0xFF00) >> 8) + 10; |
| break; |
| #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 9)) |
| case 80: |
| center_freq1 = center_freq - 20 * ((chann_info & 0xFF00) >> 8) + 30; |
| break; |
| #endif |
| default: |
| break; |
| } |
| return center_freq1; |
| } |
| |
| /* Name: strtoint |
| * Desc: Converts a string to a decimal or hexadecimal integer |
| * s: the string to be converted |
| * res: pointer to the calculated integer |
| * return: 0 (success), 1(failure) |
| */ |
| static inline int strtoint(const char *s, int *res) |
| { |
| int base = 10; |
| |
| if (strlen(s) > 2) |
| if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) |
| base = 16; |
| return kstrtoint(s, base, res); |
| } |
| |
| static inline u8 *slsi_mem_dup(u8 *src, size_t len) |
| { |
| u8 *dest; |
| |
| if (!src || !len) |
| return NULL; |
| |
| dest = kmalloc(len, GFP_KERNEL); |
| if (!dest) |
| return NULL; |
| memcpy(dest, src, len); |
| return dest; |
| } |
| |
| static inline void slsi_get_random_bytes(u8 *byte_buffer, u32 buffer_len) |
| { |
| return get_random_bytes(byte_buffer, buffer_len); |
| } |
| |
| static inline int slsi_util_nla_get_u8(const struct nlattr *attr, u8 *val) |
| { |
| if (nla_len(attr) >= sizeof(u8)) { |
| *val = nla_get_u8(attr); |
| return 0; |
| } |
| return -EINVAL; |
| } |
| |
| static inline int slsi_util_nla_get_u16(const struct nlattr *attr, u16 *val) |
| { |
| if (nla_len(attr) >= sizeof(u16)) { |
| *val = nla_get_u16(attr); |
| return 0; |
| } |
| return -EINVAL; |
| |
| } |
| |
| static inline int slsi_util_nla_get_u32(const struct nlattr *attr, u32 *val) |
| { |
| if (nla_len(attr) >= sizeof(u32)) { |
| *val = nla_get_u32(attr); |
| return 0; |
| } |
| return -EINVAL; |
| } |
| |
| static inline int slsi_util_nla_get_u64(const struct nlattr *attr, u64 *val) |
| { |
| if (nla_len(attr) >= sizeof(u64)) { |
| *val = nla_get_u64(attr); |
| return 0; |
| } |
| return -EINVAL; |
| } |
| |
| |
| static inline int slsi_util_nla_get_s8(const struct nlattr *attr, s8 *val) |
| { |
| if (nla_len(attr) >= sizeof(s8)) { |
| *val = nla_get_s8(attr); |
| return 0; |
| } |
| return -EINVAL; |
| } |
| |
| static inline int slsi_util_nla_get_s16(const struct nlattr *attr, s16 *val) |
| { |
| if (nla_len(attr) >= sizeof(s16)) { |
| *val = nla_get_s16(attr); |
| return 0; |
| } |
| return -EINVAL; |
| } |
| |
| static inline int slsi_util_nla_get_s32(const struct nlattr *attr, s32 *val) |
| { |
| if (nla_len(attr) >= sizeof(s32)) { |
| *val = nla_get_s32(attr); |
| return 0; |
| } |
| return -EINVAL; |
| } |
| |
| static inline int slsi_util_nla_get_s64(const struct nlattr *attr, s64 *val) |
| { |
| if (nla_len(attr) >= sizeof(s64)) { |
| *val = nla_get_s64(attr); |
| return 0; |
| } |
| return -EINVAL; |
| } |
| |
| static inline int slsi_util_nla_get_be16(const struct nlattr *attr, __be16 *val) |
| { |
| if (nla_len(attr) >= sizeof(__be16)) { |
| *val = nla_get_be16(attr); |
| return 0; |
| } |
| return -EINVAL; |
| } |
| |
| static inline int slsi_util_nla_get_be32(const struct nlattr *attr, __be32 *val) |
| { |
| if (nla_len(attr) >= sizeof(__be32)) { |
| *val = nla_get_be32(attr); |
| return 0; |
| } |
| return -EINVAL; |
| } |
| |
| static inline int slsi_util_nla_get_be64(const struct nlattr *attr, __be64 *val) |
| { |
| if (nla_len(attr) >= sizeof(__be64)) { |
| *val = nla_get_be64(attr); |
| return 0; |
| } |
| return -EINVAL; |
| } |
| |
| static inline int slsi_util_nla_get_le16(const struct nlattr *attr, __le16 *val) |
| { |
| if (nla_len(attr) >= sizeof(__le16)) { |
| *val = nla_get_le16(attr); |
| return 0; |
| } |
| return -EINVAL; |
| } |
| |
| static inline int slsi_util_nla_get_le32(const struct nlattr *attr, __le32 *val) |
| { |
| if (nla_len(attr) >= sizeof(__le32)) { |
| *val = nla_get_le32(attr); |
| return 0; |
| } |
| return -EINVAL; |
| } |
| |
| static inline int slsi_util_nla_get_le64(const struct nlattr *attr, __le64 *val) |
| { |
| if (nla_len(attr) >= sizeof(__le64)) { |
| *val = nla_get_le64(attr); |
| return 0; |
| } |
| return -EINVAL; |
| } |
| |
| static inline int slsi_util_nla_get_data(const struct nlattr *attr, size_t size, void *val) |
| { |
| if(nla_len(attr) >= size) { |
| memcpy(val, nla_data(attr), size); |
| return 0; |
| } |
| return -EINVAL; |
| } |
| |
| #ifdef __cplusplus |
| } |
| #endif |
| |
| #endif /* SLSI_UTILS_H__ */ |