📄 ieee80211_skb.c.svn-base
字号:
/*- * Copyright (c) 2007 Michael Taylor, Apprion * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $Id: ieee80211_linux.c 2829 2007-11-05 20:43:50Z mtaylor $ */#ifndef EXPORT_SYMTAB#define EXPORT_SYMTAB#endif/* * IEEE 802.11 support (Linux-specific code) */#ifndef AUTOCONF_INCLUDED#include <linux/config.h>#endif#include <linux/version.h>#include <linux/module.h>#include <linux/kmod.h>#include <linux/init.h>#include <linux/skbuff.h>#include <linux/sysctl.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/if_vlan.h>#include <linux/vmalloc.h>#include <linux/proc_fs.h>#include <net/iw_handler.h>#include <linux/wireless.h>#include <linux/if_arp.h> /* XXX for ARPHRD_* */#include <asm/uaccess.h>#include "if_media.h"#include "if_ethersubr.h"#include <net80211/ieee80211_var.h>#include <net80211/ieee80211_monitor.h>#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)#include <linux/device.h>#endif#undef alloc_skb#undef dev_alloc_skb#undef dev_kfree_skb#undef dev_kfree_skb_any#undef dev_kfree_skb_irq#undef dev_queue_xmit#undef kfree_skb#undef kfree_skb_fast#undef netif_rx#undef pskb_copy#undef skb_clone#undef skb_copy#undef skb_copy_expand#undef skb_get#undef skb_realloc_headroom#undef skb_share_check#undef skb_unshare#undef vlan_hwaccel_rxatomic_t skb_total_counter = ATOMIC_INIT(0);EXPORT_SYMBOL(skb_total_counter);#ifdef IEEE80211_DEBUG_REFCNTatomic_t skb_refs_counter = ATOMIC_INIT(0);EXPORT_SYMBOL(skb_refs_counter);#endif/******************************************************************************* * Debug Helpers ******************************************************************************/static void skb_print_message( int show_counter, const struct sk_buff *skb, const char *func, int line, const char *message, ...){ va_list args; char skb_count[32] = { '\0' }; char expanded_message[1024] = { '\0' }; if (show_counter) {#ifdef IEEE80211_DEBUG_REFCNT snprintf(skb_count, sizeof(skb_count), "[#SKB=%05d #REF=%05d] ", atomic_read(&skb_total_counter), atomic_read(&skb_refs_counter));#else snprintf(skb_count, sizeof(skb_count), "[#SKB=%05d] ", atomic_read(&skb_total_counter));#endif } va_start(args, message); vsnprintf(expanded_message, sizeof(expanded_message), message, args); printk(KERN_DEBUG "%s: %s%s:%d %s\n", ((skb != NULL) ? DEV_NAME(skb->dev) : "none"), skb_count, func, line, expanded_message); va_end(args);#ifdef IEEE80211_DEBUG_REFCNT dump_stack();#endif}#ifdef IEEE80211_DEBUG_REFCNTstatic void print_skb_refchange_message( const struct sk_buff *skb, int users_adjustment, const char *func, int line);static void print_skb_trackchange_message( const struct sk_buff *skb, int users_adjustment, const char *func, int line, char *message);/* Called automatically when an SKB reaches zero users, * reporting any leaked node references. */#ifdef IEEE80211_DEBUG_REFCNT_SKBDESTstatic void skb_destructor(struct sk_buff *skb);#endifstatic void get_skb_description(char *dst, int dst_size, const char *label, const struct sk_buff *skb, int users_adjustment);static struct sk_buff *clean_clone_or_copy(struct sk_buff *skb);static struct sk_buff *track_skb(struct sk_buff *skb, int users_adjustment, const char *func, int line);static struct sk_buff *untrack_skb(struct sk_buff *skb, int users_adjustment, const char *func, int line);#define UNREF_USE_KFREE_SKB 0#define UNREF_USE_DEV_KFREE_SKB_ANY 1#define UNREF_USE_DEV_KFREE_SKB 2#define UNREF_USE_DEV_KFREE_SKB_IRQ 3/* Assumes SKB is not yet freed at the time of the call and shows the new users * count as (users - 1). */static void unref_skb(struct sk_buff *skb, int type, const char *func, int line);/* Assumes SKB reference counter has already been updated and reports count as * atomic_read(&skb->users). */static struct sk_buff *ref_skb(struct sk_buff *skb, const char *func, int line);#ifdef IEEE80211_DEBUG_REFCNT_SKBDEST/* Destructor for reporting node reference leaks */static void skb_destructor(struct sk_buff *skb) { /* Report any node reference leaks - caused by kernel net device queue * dropping buffer, rather than passing it to the driver. */ if (SKB_NI(skb) != NULL) { printk(KERN_ERR "%s:%d - ERROR: non-NULL node pointer in %p, %p<" MAC_FMT ">! " "Leak Detected!\n", __func__, __LINE__, skb, SKB_NI(skb), MAC_ADDR(SKB_NI(skb)->ni_macaddr)); dump_stack(); } if (SKB_CB(skb)->next_destructor != NULL) { SKB_CB(skb)->next_destructor(skb); }}EXPORT_SYMBOL(skb_destructor);#endif /* #ifdef IEEE80211_DEBUG_REFCNT_SKBDEST */static void get_skb_description(char *dst, int dst_size, const char *label, const struct sk_buff *skb, int users_adjustment) { dst[0] = '\0'; if (NULL != skb) { int adj_users = atomic_read(&skb->users) + users_adjustment; if (SKB_NI(skb) != NULL) { snprintf(dst, dst_size, " [%s%s%p,users=%d,node=%p<" MAC_FMT ">,aid=%d%s%s]", label, (label != NULL ? ": " : ""), skb, adj_users, SKB_NI(skb), MAC_ADDR(SKB_NI(skb)->ni_macaddr), SKB_NI(skb)->ni_associd, ((adj_users < 0) ? " ** CORRUPTED **" : ""), ((adj_users == 0) ? " ** RELEASED **" : "") ); } else { snprintf(dst, dst_size, " [%s%s%p,users=%d,node=NULL,aid=N/A%s%s]", label, (label != NULL ? ": " : ""), skb, adj_users, ((adj_users < 0) ? " ** CORRUPTED **" : ""), ((adj_users == 0) ? " ** RELEASED **" : "") ); } dst[dst_size-1] = '\0'; }}static void print_skb_refchange_message( const struct sk_buff *skb, int users_adjustment, const char *func, int line){ char skb_desc[128] = { '\0' }; if (0 == (ath_debug_global & GLOBAL_DEBUG_SKB_REF)) return; get_skb_description(skb_desc, sizeof(skb_desc), "skb", skb, users_adjustment); skb_print_message(0 /* no global count */, skb, func, line, skb_desc);}static void print_skb_trackchange_message( const struct sk_buff *skb, int users_adjustment, const char *func, int line, char *message){ char skb_desc[128] = { '\0' }; if (0 == (ath_debug_global & GLOBAL_DEBUG_SKB)) return; get_skb_description(skb_desc, sizeof(skb_desc), "skb", skb, users_adjustment); skb_print_message(1 /* show global count */, skb, func, line, "%s%s", skb_desc, message);}static struct sk_buff *clean_clone_or_copy(struct sk_buff *skb) { if (skb != NULL) M_FLAG_CLR(skb, M_SKB_TRACKED); return skb;}static struct sk_buff *track_skb(struct sk_buff *skb, int users_adjustment, const char *func, int line) { if (NULL == skb) { skb_print_message(0 /* show_counter */, skb, func2, line2, "ERROR: NULL skb received. Skipping."); return NULL; } if (M_FLAG_GET(skb, M_SKB_TRACKED)) { skb_print_message(0 /* show_counter */, skb, func2, line2, "ERROR: Already tracked skb received. Skipping."); dump_stack(); return skb; } if (skb_shared(skb)) { skb_print_message(0 /* show_counter */, skb, func2, line2, "ERROR: Shared skb received. References leaked??"); dump_stack(); } atomic_inc(&skb_total_counter); atomic_inc(&skb_refs_counter); M_FLAG_SET(skb, M_SKB_TRACKED); print_skb_trackchange_message(skb, users_adjustment, func2, line2, " is now ** TRACKED **");#ifdef IEEE80211_DEBUG_REFCNT_SKBDEST /* Install our debug destructor, chaining to the original... */ if (skb->destructor != skb_destructor) { SKB_CB(skb)->next_destructor = skb->destructor; skb->destructor = skb_destructor; }#endif /* #ifdef IEEE80211_DEBUG_REFCNT_SKBDEST */ return skb;}static struct sk_buff *untrack_skb(struct sk_buff *skb, int users_adjustment, const char *func, int line){ if (NULL == skb) { skb_print_message(0 /* show_counter */, skb, func, line, "ERROR: NULL skb received. No changes made."); return NULL; } if (!M_FLAG_GET(skb, M_SKB_TRACKED)) { skb_print_message(0 /* show_counter */, skb, func, line, "ERROR: Untracked skb received. No changes made."); return skb; } if (skb_shared(skb)) { skb_print_message(0 /* show_counter */, skb, func, line, "ERROR: Shared skb received. References leaked??"); } atomic_dec(&skb_total_counter); atomic_dec(&skb_refs_counter); M_FLAG_CLR(skb, M_SKB_TRACKED);#ifdef IEEE80211_DEBUG_REFCNT_SKBDEST /* Uninstall our debug destructor, restoring any original... */ if (skb->destructor == skb_destructor) { skb->destructor = SKB_CB(skb)->next_destructor; SKB_CB(skb)->next_destructor = NULL; }#endif /* #ifdef IEEE80211_DEBUG_REFCNT_SKBDEST */ print_skb_trackchange_message(skb, users_adjustment, func, line, " is now ** UNTRACKED **"); return skb;}#define UNREF_USE_KFREE_SKB 0#define UNREF_USE_DEV_KFREE_SKB_ANY 1#define UNREF_USE_DEV_KFREE_SKB 2#define UNREF_USE_DEV_KFREE_SKB_IRQ 3/* Assumes SKB is not yet freed at the time of the call and shows the new users * count as (users - 1). */static voidunref_skb(struct sk_buff *skb, int type, const char *func, int line) { if (NULL == skb) { skb_print_message(0 /* show_counter */, skb, func, line, "ERROR: NULL skb received."); dump_stack(); return; } if (!M_FLAG_GET(skb, M_SKB_TRACKED)) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -