ここには非常に具体的なコードがあり、これまでインターネットはほとんど役に立ちませんでした。私は、(初心者向けに) 802.11 (ワイヤレス) パケットを読み取って、MAC ヘッダーから情報を出力できるコードを作成しようとしています。さまざまなチュートリアル、カーネル情報の一部からコードを作成しようとしました... 作成しようとしているプログラムは、Android 用のロード可能なカーネル モジュールです (ただし、Linux カーネルは非常に似ています)。現在 sk_buff パケットを受信できますが、これらは完全に間違っているようです。これは私がこれまでに持っているコードです:
/*
* AUTHOR: MATHIEU DEVOS
*
*/
/* Needed by all modules */
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
/* KModule specific */
#include <linux/skbuff.h> /* ptype_function and others */
#include <linux/netdevice.h> /* used to print list of devices */
#include <linux/nl80211.h> /* used for iftypes types */
#include <net/cfg80211.h> /* used to handle ieee80211_ptr that point to wireless_dev*/
#include <linux/if_ether.h> /* used to specifiy which ethernet packages driver gets, not for header! */
#include <linux/netfilter.h> /* used to determine what to do with the packets */
#include <linux/string.h> /* used for memcmp */
#include <linux/ieee80211.h> /* used for 802.11 header and constants */
#include <net/mac80211.h> /* used for handling skb and getting hw */
/* used to show defines, currently unused, remove later on */
#define STR(x) #x
#define SHOW_DEFINE(x) printk(KERN_CRIT "%s = %s\n", #x, STR(x));
/* defines for modinfo */
#define DRIVER_AUTHOR "Mathieu Devos <mathieu.devos@ugent.be>"
#define DRIVER_DESC "Basic ethernet test"
/* Actual coding start */
/* initialisation of variables and functions */
/* variables */
struct net_device *dev;
struct ieee80211_hw *hw;
static int foundWLAN = 0;
static struct packet_type ptype;
/* functions */
static void print_mac_hdr(struct ieee80211_hdr *e_hdr);
static int dev_is_wireless(struct net_device *dev);
static void throw_hook(struct net_device *dev);
static int ptype_function(struct sk_buff *skb, struct net_device *dev, struct packet_type *ptype, struct net_device *dev2);
/*start of functions*/
static void print_HWinfo(void){
printk(KERN_CRIT "Network device: %s\n",dev->name);
printk(KERN_CRIT "Network address: %pM\n",dev->dev_addr);
}
static int dev_is_wireless(struct net_device *dev){
#ifdef CONFIG_WIRELESS_EXT
if(dev->wireless_handlers && dev->operstate!=5){
return 1;
}
#endif
if(dev->ieee80211_ptr && dev->operstate!=5){
return 1;
}
return 0; /* default false */
}
static int ptype_function(struct sk_buff *skb, struct net_device *dev1, struct packet_type *ptype, struct net_device *dev2){
struct ieee80211_hdr *whdr = NULL;
whdr = (struct ieee80211_hdr *)skb->mac_header;
printk(KERN_CRIT "head: %pF",skb->head);
printk(KERN_CRIT "mac_header: %pF",skb->mac_header);
printk(KERN_CRIT "network_header: %pF",skb->network_header);
printk(KERN_CRIT "transport_header: %pF",skb->transport_header);
printk(KERN_CRIT "len: %u",skb->len);
printk(KERN_CRIT "data_len: %u",skb->data_len);
printk(KERN_CRIT "mac_len: %u",skb->mac_len);
printk(KERN_CRIT "hdr_len: %u",skb->hdr_len);
printk(KERN_CRIT "SKBUFF size: %u", sizeof(*skb));
/*
print_mac_hdr(whdr); */
/* sizeof(*whdr)) = 30 bytes */
/* sizeof(*ehdr)) = 14 bytes */
if(memcmp(whdr->addr1,dev1->dev_addr,dev1->addr_len)==0){
print_mac_hdr(whdr);
}
dev_kfree_skb(skb);
return NF_DROP; /* NF_DROP Basically, print the info of the all the packets flying around, then drop it */
}
static void print_mac_hdr(struct ieee80211_hdr *whdr){
printk(KERN_CRIT "DA ADDR: %pM\n",whdr->addr1);
printk(KERN_CRIT "BSSID ADDR2: %pM\n",whdr->addr2);
printk(KERN_CRIT "SA ADDR3: %pM\n",whdr->addr3);
printk(KERN_CRIT "UNUSED ADDR4: %pM\n",whdr->addr4);
/*printk(KERN_CRIT "PROTOCOL: 0x%04x\n",ntohs(ehdr->h_proto));*/
}
static void throw_hook(struct net_device *dev){
ptype.type = htons(ETH_P_ALL); /* listen to all ethernet packets! This should still work, even for 802.11, change later */
ptype.func = &ptype_function;
ptype.dev = dev;
dev_add_pack(&ptype);
printk(KERN_CRIT "Done setting up packet type");
}
static void delete_hook(struct net_device *dev){
dev_remove_pack(&ptype);
synchronize_net();
}
/* Handle init and exit of module */
static int __init init_mymodule(void){
printk(KERN_CRIT "Started kernel module!\n");
dev = first_net_device(&init_net);
while(dev && !foundWLAN){
foundWLAN = dev_is_wireless(dev);
if(!foundWLAN){
dev = next_net_device(dev);
}
}
if(dev && dev->ieee80211_ptr->iftype==NL80211_IFTYPE_STATION){
print_HWinfo();
/*
hw = wiphy_to_ieee80211_hw(dev->ieee80211_ptr->wiphy);
if(!hw){
printk(KERN_CRIT "Could not assign HW!");
}else{
printk(KERN_CRIT "Assigned hw!");
}
*/
throw_hook(dev);
}
return 0;
}
static void __exit exit_mymodule(void){
delete_hook(dev);
printk(KERN_CRIT "Finished kernel module, exiting \n");
}
module_init(init_mymodule);
module_exit(exit_mymodule);
/*
* Extra info for modinfo
*/
MODULE_LICENSE("GPL");
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
私が認識している現在の項目:
- wifiデバイスをチェックすると、p2p0とwlan0の両方が表示されます。汎用コードを記述したいので、名前だけに基づいて「正しい」デバイスを選択しないことをお勧めします。したがって、DORMANT (operstate) 状態に基づいて選択する理由です。
- 現在、ハードウェア情報 (wiphy_to_ieee80211_hw) を呼び出す必要があるかどうかはわかりませんが、上記の関数を実行しようとすると、__init が 0 を返さなくなり (エラー コードが返されます)、モジュールを起動することさえできません。
- skb->data を使用しようとするとカーネルがクラッシュし、データ ポインター (*data) を読み取ろうとするとクラッシュが発生します。
- 以下のサンプル出力でわかるように、現在 mac_len と data_len の両方を受け取っていることが完全に間違っています。Mac_len は 30 (802.11 ヘッダーのバイト数) である必要があり、data_len は常に 0 であってはなりません。
現在の出力のサンプル:
<2>[19476.400718] c0 head: 0xe2e4f440
<2>[19476.400766] c0 mac_header: 0xe2e4f48e
<2>[19476.400818] c0 network_header: 0xe2e4f432
<2>[19476.400873] c0 transport_header: 0xe2e4f440
<2>[19476.400929] c0 len: 78
<2>[19476.400964] c0 data_len: 0
<2>[19476.401003] c0 mac_len: 14
<2>[19476.401041] c0 hdr_len: 0
<2>[19476.401079] c0 SKBUFF size: 184
<2>[19476.401307] c0 head: 0xe2e4f440
<2>[19476.401362] c0 mac_header: 0xe2e4f4dc
<2>[19476.401423] c0 network_header: 0xe2e4f432
<2>[19476.401485] c0 transport_header: 0xe2e4f440
<2>[19476.401541] c0 len: 156
<2>[19476.401577] c0 data_len: 0
<2>[19476.401615] c0 mac_len: 14
<2>[19476.401656] c0 hdr_len: 0
<2>[19476.401701] c0 SKBUFF size: 184
私はこの Web サイトに投稿するのは初めてなので、これらの問題について前向きな洞察を得られることを願っていますが、プログラミングの問題を解決するためにかなり長い間この Web サイトを使用してきました。
すべての進行状況を保存して明日さらに検索する前に、最初の簡単な編集を行います。
追加した:
extern struct ieee80211_hw *wiphy_to_ieee80211_hw(struct wiphy *wiphy);
関数の初期化に(同じことをしようとすると、* wiphy_to_ieee80211_hwの代わりにwiphy_to_ieee80211_hwを使用すると、大量のエラーが発生するようです)。ポインター関数 (*wiphy_to_ieee80211_hw) を使用すると、未定義であることがわかります。そのため、この関数はまだ定義されていないため、かなり面倒です。Makefile を次のように変更して追加しました: KBUILD_EXTRA_SYMBOLS=../kernel/net/mac80211 (これは、export_symbol がある場所です: ../kernel/net/mac80211/util.c)
obj-m += ethernet_test.o
all:
make -C ../kernel M=$(PWD) KBUILD_EXTRA_SYMBOLS=../kernel/net/mac80211 modules
clean:
make -C ../kernel M=$(PWD) clean
また、__init 部分の ieee80211_hw を再度ロードしようとしました。
struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(dev->ieee802_ptr->wiphy);
しかし、これはまだ定義されていないため、ieee80211_hw にはならず、モジュールがクラッシュします (ロードさえしません) :(。