1 /******************************************************************************
3 * Copyright (c) 2012 - 2018 Samsung Electronics Co., Ltd. All rights reserved
5 *****************************************************************************/
10 #include <linux/version.h>
11 #include <linux/types.h>
12 #include <linux/spinlock.h>
13 #include <linux/workqueue.h>
14 #include <linux/skbuff.h>
15 #include <net/cfg80211.h>
19 #ifdef CONFIG_SCSC_SMAPPER
26 struct sk_buff
*skb_addr
;
29 static inline struct slsi_skb_cb
*slsi_skb_cb_get(struct sk_buff
*skb
)
31 return (struct slsi_skb_cb
*)skb
->cb
;
34 static inline struct slsi_skb_cb
*slsi_skb_cb_init(struct sk_buff
*skb
)
36 BUILD_BUG_ON(sizeof(struct slsi_skb_cb
) > sizeof(skb
->cb
));
38 memset(skb
->cb
, 0, sizeof(struct slsi_skb_cb
));
39 return slsi_skb_cb_get(skb
);
43 static inline u32
slsi_convert_tlv_data_to_value(u8
*data
, u16 length
)
50 for (i
= 0; i
< length
; i
++)
51 value
|= ((u32
)data
[i
]) << i
* 8;
60 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
61 #define SLSI_ETHER_COPY(dst, src) ether_addr_copy((dst), (src))
62 #define SLSI_ETHER_EQUAL(mac1, mac2) ether_addr_equal((mac1), (mac2))
64 #define SLSI_ETHER_COPY(dst, src) memcpy((dst), (src), ETH_ALEN)
65 #define SLSI_ETHER_EQUAL(mac1, mac2) (memcmp((mac1), (mac2), ETH_ALEN) == 0)
68 extern uint slsi_sg_host_align_mask
;
69 #define SLSI_HIP_FH_SIG_PREAMBLE_LEN 4
70 #define SLSI_SKB_GET_ALIGNMENT_OFFSET(skb) (0)
72 /* Get the Compiler to ignore Unused parameters */
73 #define SLSI_UNUSED_PARAMETER(x) ((void)(x))
75 /* Helper ERROR Macros */
76 #define SLSI_ECR(func) \
80 SLSI_ERR_NODEV("e=%d\n", _err); \
85 #define SLSI_EC(func) \
89 SLSI_ERR_NODEV("e=%d\n", _err); \
94 #define SLSI_EC_GOTO(func, err, label) \
99 SLSI_ERR(sdev, "fail at line:%d\n", __LINE__); \
104 /*------------------------------------------------------------------*/
105 /* Endian conversion */
106 /*------------------------------------------------------------------*/
107 #define SLSI_BUFF_LE_TO_U16(ptr) (((u16)((u8 *)(ptr))[0]) | ((u16)((u8 *)(ptr))[1]) << 8)
108 #define SLSI_U16_TO_BUFF_LE(uint, ptr) \
110 u32 local_uint_tmp = (uint); \
111 ((u8 *)(ptr))[0] = ((u8)((local_uint_tmp & 0x00FF))); \
112 ((u8 *)(ptr))[1] = ((u8)(local_uint_tmp >> 8)); \
115 #define SLSI_U32_TO_BUFF_LE(uint, ptr) ((*(u32 *)ptr) = cpu_to_le32(uint))
117 #define SLSI_BUFF_LE_TO_U16_P(output, input) \
119 (output) = (u16)((((u16)(input)[1]) << 8) | ((u16)(input)[0])); \
123 #define SLSI_BUFF_LE_TO_U32_P(output, input) \
125 (output) = le32_to_cpu(*(u32 *)input); \
129 #define SLSI_U16_TO_BUFF_LE_P(output, input) \
131 (output)[0] = ((u8)((input) & 0x00FF)); \
132 (output)[1] = ((u8)((input) >> 8)); \
136 #define SLSI_U32_TO_BUFF_LE_P(output, input) \
138 (*(u32 *)output) = cpu_to_le32(input); \
142 #ifdef CONFIG_SCSC_WLAN_SKB_TRACKING
143 void slsi_dbg_track_skb_init(void);
144 void slsi_dbg_track_skb_reset(void);
145 void slsi_dbg_track_skb_f(struct sk_buff
*skb
, gfp_t flags
, const char *file
, int line
);
146 bool slsi_dbg_untrack_skb_f(struct sk_buff
*skb
, const char *file
, int line
);
147 bool slsi_dbg_track_skb_marker_f(struct sk_buff
*skb
, const char *file
, int line
);
148 #define slsi_dbg_track_skb(skb_, flags_) slsi_dbg_track_skb_f(skb_, flags_, __FILE__, __LINE__)
149 #define slsi_dbg_untrack_skb(skb_) slsi_dbg_untrack_skb_f(skb_, __FILE__, __LINE__)
150 #define slsi_dbg_track_skb_marker(skb_) slsi_dbg_track_skb_marker_f(skb_, __FILE__, __LINE__)
151 void slsi_dbg_track_skb_report(void);
153 static inline struct sk_buff
*slsi_dev_alloc_skb_f(unsigned int length
, const char *file
, int line
)
155 struct sk_buff
*skb
= dev_alloc_skb(SLSI_NETIF_SKB_HEADROOM
+ SLSI_NETIF_SKB_TAILROOM
+ length
);
158 #ifdef CONFIG_SCSC_SMAPPER
159 slsi_skb_cb_init(skb
);
161 skb_reserve(skb
, SLSI_NETIF_SKB_HEADROOM
- SLSI_SKB_GET_ALIGNMENT_OFFSET(skb
));
162 slsi_dbg_track_skb_f(skb
, GFP_ATOMIC
, file
, line
);
167 static inline struct sk_buff
*slsi_alloc_skb_f(unsigned int size
, gfp_t priority
, const char *file
, int line
)
169 struct sk_buff
*skb
= alloc_skb(size
, priority
);
172 #ifdef CONFIG_SCSC_SMAPPER
173 slsi_skb_cb_init(skb
);
175 slsi_dbg_track_skb_f(skb
, priority
, file
, line
);
181 static inline struct sk_buff
*slsi_alloc_skb_headroom_f(unsigned int size
, gfp_t priority
, const char *file
, int line
)
183 struct sk_buff
*skb
= alloc_skb(SLSI_NETIF_SKB_HEADROOM
+ SLSI_NETIF_SKB_TAILROOM
+ size
, priority
);
186 #ifdef CONFIG_SCSC_SMAPPER
187 slsi_skb_cb_init(skb
);
189 skb_reserve(skb
, SLSI_NETIF_SKB_HEADROOM
- SLSI_SKB_GET_ALIGNMENT_OFFSET(skb
));
190 slsi_dbg_track_skb_f(skb
, priority
, file
, line
);
195 static inline void slsi_skb_unlink_f(struct sk_buff
*skb
, struct sk_buff_head
*list
, const char *file
, int line
)
197 skb_unlink(skb
, list
);
198 slsi_dbg_track_skb_marker_f(skb
, file
, line
);
201 static inline void slsi_skb_queue_tail_f(struct sk_buff_head
*list
, struct sk_buff
*skb
, const char *file
, int line
)
203 skb_queue_tail(list
, skb
);
204 slsi_dbg_track_skb_marker_f(skb
, file
, line
);
207 static inline void slsi_skb_queue_head_f(struct sk_buff_head
*list
, struct sk_buff
*skb
, const char *file
, int line
)
209 skb_queue_head(list
, skb
);
210 slsi_dbg_track_skb_marker_f(skb
, file
, line
);
213 static inline struct sk_buff
*slsi_skb_dequeue_f(struct sk_buff_head
*list
, const char *file
, int line
)
215 struct sk_buff
*skb
= skb_dequeue(list
);
218 slsi_dbg_track_skb_marker_f(skb
, file
, line
);
222 static inline struct sk_buff
*slsi_skb_realloc_headroom_f(struct sk_buff
*skb
, unsigned int headroom
, const char *file
, int line
)
224 skb
= skb_realloc_headroom(skb
, headroom
);
226 #ifdef CONFIG_SCSC_SMAPPER
227 slsi_skb_cb_init(skb
);
229 slsi_dbg_track_skb_f(skb
, GFP_ATOMIC
, file
, line
);
234 static inline struct sk_buff
*slsi_skb_copy_f(struct sk_buff
*skb
, gfp_t priority
, const char *file
, int line
)
236 skb
= skb_copy(skb
, priority
);
239 slsi_dbg_track_skb_f(skb
, priority
, file
, line
);
243 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
)
245 skb
= skb_copy_expand(skb
, newheadroom
, newtailroom
, priority
);
248 slsi_dbg_track_skb_f(skb
, priority
, file
, line
);
252 static inline struct sk_buff
*slsi_skb_clone_f(struct sk_buff
*skb
, gfp_t priority
, const char *file
, int line
)
254 skb
= skb_clone(skb
, priority
);
257 slsi_dbg_track_skb_f(skb
, priority
, file
, line
);
261 static inline void slsi_kfree_skb_f(struct sk_buff
*skb
, const char *file
, int line
)
263 /* If untrack fails we do not free the SKB
264 * This helps tracking bad pointers and double frees
266 #ifdef CONFIG_SCSC_SMAPPER
267 struct slsi_skb_cb
*cb
;
272 cb
= (struct slsi_skb_cb
*)skb
->cb
;
274 if (cb
&& !cb
->free_ma_unitdat
&& cb
->skb_addr
&& slsi_dbg_untrack_skb_f(cb
->skb_addr
, file
, line
)) {
275 kfree_skb(cb
->skb_addr
);
279 if (slsi_dbg_untrack_skb_f(skb
, file
, line
))
283 #define slsi_dev_alloc_skb(length_) slsi_dev_alloc_skb_f(length_, __FILE__, __LINE__)
284 #define slsi_alloc_skb(size_, priority_) slsi_alloc_skb_f(size_, priority_, __FILE__, __LINE__)
285 #define slsi_alloc_skb_headroom(size_, priority_) slsi_alloc_skb_headroom_f(size_, priority_, __FILE__, __LINE__)
286 #define slsi_skb_realloc_headroom(skb_, headroom_) slsi_skb_realloc_headroom_f(skb_, headroom_, __FILE__, __LINE__)
287 #define slsi_skb_copy(skb_, priority_) slsi_skb_copy_f(skb_, priority_, __FILE__, __LINE__)
288 #define slsi_skb_copy_expand(skb_, newheadroom_, newtailroom_, priority_) skb_copy_expand_f(skb_, newheadroom_, newtailroom_, priority_, __FILE__, __LINE__)
289 #define slsi_skb_clone(skb_, priority_) slsi_skb_clone_f(skb_, priority_, __FILE__, __LINE__)
290 #define slsi_kfree_skb(skb_) slsi_kfree_skb_f(skb_, __FILE__, __LINE__)
291 #define slsi_skb_unlink(skb_, list_) slsi_skb_unlink_f(skb_, list_, __FILE__, __LINE__)
292 #define slsi_skb_queue_tail(list_, skb_) slsi_skb_queue_tail_f(list_, skb_, __FILE__, __LINE__)
293 #define slsi_skb_queue_head(list_, skb_) slsi_skb_queue_head_f(list_, skb_, __FILE__, __LINE__)
294 #define slsi_skb_dequeue(list_) slsi_skb_dequeue_f(list_, __FILE__, __LINE__)
296 static inline void slsi_skb_queue_purge(struct sk_buff_head
*list
)
300 while ((skb
= skb_dequeue(list
)) != NULL
)
305 #define slsi_dbg_track_skb_init()
306 #define slsi_dbg_track_skb_reset()
307 #define slsi_dbg_track_skb(skb_, flags_)
308 #define slsi_dbg_untrack_skb(skb_)
309 #define slsi_dbg_track_skb_marker(skb_)
310 #define slsi_dbg_track_skb_report()
312 static inline struct sk_buff
*slsi_dev_alloc_skb_f(unsigned int length
, const char *file
, int line
)
314 struct sk_buff
*skb
= dev_alloc_skb(SLSI_NETIF_SKB_HEADROOM
+ SLSI_NETIF_SKB_TAILROOM
+ length
);
316 SLSI_UNUSED_PARAMETER(file
);
317 SLSI_UNUSED_PARAMETER(line
);
319 #ifdef CONFIG_SCSC_SMAPPER
320 slsi_skb_cb_init(skb
);
322 skb_reserve(skb
, SLSI_NETIF_SKB_HEADROOM
- SLSI_SKB_GET_ALIGNMENT_OFFSET(skb
));
327 static inline struct sk_buff
*slsi_alloc_skb_f(unsigned int size
, gfp_t priority
, const char *file
, int line
)
329 struct sk_buff
*skb
= alloc_skb(size
, priority
);
331 SLSI_UNUSED_PARAMETER(file
);
332 SLSI_UNUSED_PARAMETER(line
);
333 #ifdef CONFIG_SCSC_SMAPPER
335 slsi_skb_cb_init(skb
);
340 static inline struct sk_buff
*slsi_alloc_skb_headroom_f(unsigned int size
, gfp_t priority
, const char *file
, int line
)
342 struct sk_buff
*skb
= alloc_skb(SLSI_NETIF_SKB_HEADROOM
+ SLSI_NETIF_SKB_TAILROOM
+ size
, priority
);
344 SLSI_UNUSED_PARAMETER(file
);
345 SLSI_UNUSED_PARAMETER(line
);
348 #ifdef CONFIG_SCSC_SMAPPER
349 slsi_skb_cb_init(skb
);
351 skb_reserve(skb
, SLSI_NETIF_SKB_HEADROOM
- SLSI_SKB_GET_ALIGNMENT_OFFSET(skb
));
356 static inline void slsi_kfree_skb_f(struct sk_buff
*skb
)
358 /* If untrack fails we do not free the SKB
359 * This helps tracking bad pointers and double frees
361 #ifdef CONFIG_SCSC_SMAPPER
362 struct slsi_skb_cb
*cb
;
367 cb
= (struct slsi_skb_cb
*)skb
->cb
;
369 if (cb
&& !cb
->free_ma_unitdat
&& cb
->skb_addr
) {
370 kfree_skb(cb
->skb_addr
);
377 #define slsi_dev_alloc_skb(length_) slsi_dev_alloc_skb_f(length_, __FILE__, __LINE__)
378 #define slsi_alloc_skb(size_, priority_) slsi_alloc_skb_f(size_, priority_, __FILE__, __LINE__)
379 #define slsi_alloc_skb_headroom(size_, priority_) slsi_alloc_skb_headroom_f(size_, priority_, __FILE__, __LINE__)
380 #define slsi_skb_realloc_headroom(skb_, headroom_) skb_realloc_headroom(skb_, headroom_)
381 #define slsi_skb_copy(skb_, priority_) skb_copy(skb_, priority_)
382 #define slsi_skb_copy_expand(skb_, newheadroom_, newtailroom_, priority_) skb_copy_expand(skb_, newheadroom_, newtailroom_, priority_)
383 #define slsi_skb_clone(skb_, priority_) skb_clone(skb_, priority_)
384 #define slsi_kfree_skb(skb_) slsi_kfree_skb_f(skb_)
385 #define slsi_skb_unlink(skb_, list_) skb_unlink(skb_, list_)
386 #define slsi_skb_queue_tail(list_, skb_) skb_queue_tail(list_, skb_)
387 #define slsi_skb_queue_head(list_, skb_) skb_queue_head(list_, skb_)
388 #define slsi_skb_dequeue(list_) skb_dequeue(list_)
389 #define slsi_skb_queue_purge(list_) slsi_skb_queue_purge(list_)
391 static inline void slsi_skb_queue_purge(struct sk_buff_head
*list
)
395 while ((skb
= skb_dequeue(list
)) != NULL
)
401 struct slsi_spinlock
{
407 /* Spinlock create can't fail, so return success regardless. */
408 static inline void slsi_spinlock_create(struct slsi_spinlock
*lock
)
410 spin_lock_init(&lock
->lock
);
413 static inline void slsi_spinlock_lock(struct slsi_spinlock
*lock
)
415 spin_lock_bh(&lock
->lock
);
418 static inline void slsi_spinlock_unlock(struct slsi_spinlock
*lock
)
420 spin_unlock_bh(&lock
->lock
);
424 struct slsi_skb_work
{
425 struct slsi_dev
*sdev
;
426 struct net_device
*dev
; /* This can be NULL */
427 struct workqueue_struct
*workqueue
;
428 struct work_struct work
;
429 struct sk_buff_head queue
;
430 void __rcu
*sync_ptr
;
433 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
))
435 rcu_assign_pointer(work
->sync_ptr
, (void *)sdev
);
438 skb_queue_head_init(&work
->queue
);
439 INIT_WORK(&work
->work
, func
);
440 work
->workqueue
= alloc_ordered_workqueue(name
, 0);
442 if (!work
->workqueue
)
447 static inline void slsi_skb_schedule_work(struct slsi_skb_work
*work
)
449 queue_work(work
->workqueue
, &work
->work
);
452 static inline void slsi_skb_work_enqueue_l(struct slsi_skb_work
*work
, struct sk_buff
*skb
)
458 sync_ptr
= rcu_dereference(work
->sync_ptr
);
460 if (WARN_ON(!sync_ptr
)) {
465 skb_queue_tail(&work
->queue
, skb
);
466 slsi_skb_schedule_work(work
);
471 static inline struct sk_buff
*slsi_skb_work_dequeue_l(struct slsi_skb_work
*work
)
473 return skb_dequeue(&work
->queue
);
476 static inline void slsi_skb_work_deinit(struct slsi_skb_work
*work
)
480 if (WARN_ON(!work
->sync_ptr
)) {
485 rcu_assign_pointer(work
->sync_ptr
, NULL
);
489 flush_workqueue(work
->workqueue
);
490 destroy_workqueue(work
->workqueue
);
491 work
->workqueue
= NULL
;
492 slsi_skb_queue_purge(&work
->queue
);
495 static inline void slsi_cfg80211_put_bss(struct wiphy
*wiphy
, struct cfg80211_bss
*bss
)
497 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0))
498 cfg80211_put_bss(wiphy
, bss
);
500 cfg80211_put_bss(bss
);
501 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)) */
504 #ifdef CONFIG_SCSC_WLAN_SKB_TRACKING
505 static inline void slsi_skb_work_enqueue_f(struct slsi_skb_work
*work
, struct sk_buff
*skb
, const char *file
, int line
)
507 slsi_dbg_track_skb_marker_f(skb
, file
, line
);
508 slsi_skb_work_enqueue_l(work
, skb
);
511 static inline struct sk_buff
*slsi_skb_work_dequeue_f(struct slsi_skb_work
*work
, const char *file
, int line
)
515 skb
= slsi_skb_work_dequeue_l(work
);
517 slsi_dbg_track_skb_marker_f(skb
, file
, line
);
521 #define slsi_skb_work_enqueue(work_, skb_) slsi_skb_work_enqueue_f(work_, skb_, __FILE__, __LINE__)
522 #define slsi_skb_work_dequeue(work_) slsi_skb_work_dequeue_f(work_, __FILE__, __LINE__)
524 #define slsi_skb_work_enqueue(work_, skb_) slsi_skb_work_enqueue_l(work_, skb_)
525 #define slsi_skb_work_dequeue(work_) slsi_skb_work_dequeue_l(work_)
528 static inline void slsi_eth_zero_addr(u8
*addr
)
530 memset(addr
, 0x00, ETH_ALEN
);
533 static inline void slsi_eth_broadcast_addr(u8
*addr
)
535 memset(addr
, 0xff, ETH_ALEN
);
538 static inline int slsi_str_to_int(char *str
, int *result
)
543 if ((str
[i
] == '-') || ((str
[i
] >= '0') && (str
[i
] <= '9'))) {
546 while (str
[i
] >= '0' && str
[i
] <= '9') {
548 *result
+= (int)str
[i
++] - '0';
551 *result
= ((str
[0] == '-') ? (-(*result
)) : *result
);
556 #define P80211_OUI_LEN 3
558 struct ieee80211_snap_hdr
{
559 u8 dsap
; /* always 0xAA */
560 u8 ssap
; /* always 0xAA */
561 u8 ctrl
; /* always 0x03 */
562 u8 oui
[P80211_OUI_LEN
]; /* organizational universal id */
566 unsigned char da
[ETH_ALEN
];
567 unsigned char sa
[ETH_ALEN
];
569 struct ieee80211_snap_hdr snap
;
573 #define ETHER_TYPE_SIZE 2
574 #define MSDU_HLEN sizeof(struct msdu_hdr)
575 #define MSDU_LENGTH (sizeof(struct ieee80211_snap_hdr) + sizeof(__be16))
577 static inline int slsi_skb_msdu_to_ethhdr(struct sk_buff
*skb
)
580 struct msdu_hdr
*msdu
;
582 unsigned char da
[ETH_ALEN
];
583 unsigned char sa
[ETH_ALEN
];
586 msdu
= (struct msdu_hdr
*)skb
->data
;
587 SLSI_ETHER_COPY(da
, msdu
->da
);
588 SLSI_ETHER_COPY(sa
, msdu
->sa
);
589 proto
= msdu
->ether_type
;
591 skb_pull(skb
, MSDU_HLEN
);
593 eth
= (struct ethhdr
*)skb_push(skb
, ETH_HLEN
);
595 SLSI_ETHER_COPY(eth
->h_dest
, da
);
596 SLSI_ETHER_COPY(eth
->h_source
, sa
);
597 eth
->h_proto
= proto
;
602 static inline int slsi_skb_ethhdr_to_msdu(struct sk_buff
*skb
)
605 struct msdu_hdr
*msdu
;
609 if (skb_headroom(skb
) < (MSDU_HLEN
- ETH_HLEN
))
613 ether_type
= eth
->h_proto
;
617 skb_pull(skb
, ETH_HLEN
);
619 msdu
= (struct msdu_hdr
*)skb_push(skb
, MSDU_HLEN
);
621 SLSI_ETHER_COPY(msdu
->da
, eth
->h_dest
);
622 SLSI_ETHER_COPY(msdu
->sa
, eth
->h_source
);
623 msdu
->length
= htons(len
- ETH_HLEN
+ MSDU_LENGTH
);
624 memcpy(&msdu
->snap
, rfc1042_header
, sizeof(struct ieee80211_snap_hdr
));
625 msdu
->ether_type
= ether_type
;
630 static inline u32
slsi_get_center_freq1(struct slsi_dev
*sdev
, u16 chann_info
, u16 center_freq
)
632 u32 center_freq1
= 0x0000;
634 SLSI_UNUSED_PARAMETER(sdev
);
636 switch (chann_info
& 0xFF) {
638 center_freq1
= center_freq
- 20 * ((chann_info
& 0xFF00) >> 8) + 10;
640 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 9))
642 center_freq1
= center_freq
- 20 * ((chann_info
& 0xFF00) >> 8) + 30;
655 #endif /* SLSI_UTILS_H__ */