#include<linux/module.h>
#include<linux/sched.h>
#include<linux/kernel.h>
#include<linux/slab.h>
#include<linux/errno.h>
#include<linux/types.h>
#include<linux/interrupt.h>
#include<linux/in.h>
#include<linux/netdevice.h>
#include<linux/etherdevice.h>
#include<linux/ip.h>
#include<linux/tcp.h>
#include<linux/skbuff.h>
#include<linux/if_ether.h>
#include<linux/in6.h>
#include<asm/uaccess.h>
#include<asm/checksum.h>
#include<linux/platform_device.h>
#define MAC_AUTO
static struct net_device *vir_net_devs;
struct vir_net_priv {
struct net_device_stats stats;
int status;
int rx_packetlen;
u8 *rx_packetdata;
int tx_packetlen;
u8 *tx_packetdata;
struct sk_buff *skb;
spinlock_t lock;
};
int vir_net_open(struct net_device *dev) {
#ifndef MAC_AUTO
int i;
for (i=0; i<6; i++) {
dev->dev_addr[i] = 0xaa;
}
#else
random_ether_addr(dev->dev_addr);
#endif
netif_start_queue(dev);
printk("vir_net_open\n");
return 0;
}
int vir_net_release(struct net_device *dev) {
netif_stop_queue(dev);
printk("vir_net_release\n");
return 0;
}
void vir_net_rx(struct net_device *pdev, int len, unsigned char *buf) {
struct sk_buff *skb;
struct vir_net_priv *priv = (struct vir_net_priv *) pdev->ml_priv;
skb = dev_alloc_skb(len+2);
if(!skb) {
printk("gecnet rx: low on mem - packet dropped\n");
priv->stats.rx_dropped++;
return;
}
skb_reserve(skb, 2);
memcpy(skb_put(skb, len), buf, len);
skb->dev = pdev;
skb->protocol = eth_type_trans(skb, pdev);
skb->ip_summed = CHECKSUM_UNNECESSARY;
priv->stats.rx_packets++;
priv->stats.rx_bytes += len;
printk("vir_net_rx\n");
netif_rx(skb);
return;
}
void vir_net_hw_tx(char *buf, int len, struct net_device *dev) {
struct net_device *dest;
struct vir_net_priv *priv;
if (len < sizeof(struct ethhdr) + sizeof(struct iphdr)) {
printk("vir_net: packet too short (%i octets)\n", len);
return;
}
dest = vir_net_devs;
priv = (struct vir_net_priv *)dest->ml_priv;
priv->rx_packetlen = len;
priv->rx_packetdata = buf;
printk("vir_net_hw_tx\n");
dev_kfree_skb(priv->skb);
}
int vir_net_tx(struct sk_buff *skb, struct net_device *pdev) {
int len;
char *data;
struct vir_net_priv *priv = (struct vir_net_priv *)pdev->ml_priv;
if(skb == NULL) {
printk("net_device = %p, skb = %p\n", pdev, skb);
return 0;
}
len = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len;
data = skb->data;
priv->skb = skb;
vir_net_hw_tx(data, len, pdev);
printk("vir_net_tx, pdev = %p\n", pdev);
return 0;
}
int vir_net_device_init(struct net_device *pdev) {
ether_setup(pdev);
pdev->flags |= IFF_NOARP;
pdev->ml_priv = kmalloc(sizeof(struct vir_net_priv), GFP_KERNEL);
if (pdev->ml_priv == NULL){
return -ENOMEM;
}
memset(pdev->ml_priv, 0, sizeof(struct vir_net_priv));
spin_lock_init(&((struct vir_net_priv *)pdev->ml_priv)->lock);
printk("vir_net_device_init, pdev = %p\n", pdev);
return 0;
}
static const struct net_device_ops vir_net_netdev_ops = {
.ndo_open = vir_net_open,
.ndo_stop = vir_net_release,
.ndo_start_xmit = vir_net_tx,
.ndo_init = vir_net_device_init,
};
static void vir_plat_net_release(struct device *pdev) {
printk("vir_plat_net_release, pdev = %p\n", pdev);
}
static int vir_net_probe(struct platform_device *pdev) {
int result = 0;
vir_net_devs = alloc_etherdev(sizeof(struct net_device));
vir_net_devs->netdev_ops = &vir_net_netdev_ops;
strcpy(vir_net_devs->name, "net_0");
if ((result = register_netdev(vir_net_devs))) {
printk("vir_net: error %i registering device \"%s\"\n", result, vir_net_devs->name);
}
printk("vir_net_probe, pdev = %p\n", pdev);
return 0;
}
static int vir_net_remove(struct platform_device *pdev) {
kfree(vir_net_devs->ml_priv);
unregister_netdev(vir_net_devs);
return 0;
}
static struct platform_device vir_net= {
.name = "vir_net",
.id = -1,
.dev = {
.release = vir_plat_net_release,
},
};
static struct platform_driver vir_net_driver = {
.probe = vir_net_probe,
.remove = vir_net_remove,
.driver = {
.name = "vir_net",
.owner = THIS_MODULE,
},
};
static int __init vir_net_init(void) {
printk("vir_net_init\n");
platform_device_register(&vir_net);
return platform_driver_register(&vir_net_driver);
}
static void __exit vir_net_exit(void) {
printk("vir_net_exit\n");
platform_driver_unregister(&vir_net_driver);
platform_device_unregister(&vir_net);
}
module_init(vir_net_init);
module_exit(vir_net_exit);
MODULE_LICENSE("GPL");
makefile
CONFIG_MODULE_SIG = n
obj-m+=virnet.o
all:
make -C /lib/modules/$(shell uname -r)/build/ M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build/ M=$(PWD) clean
在使用sudo ifconfig xxx up/down和sudo insmod xxx,sudo rmmod xxx命令时,输出的结果可以通过开启另外一个终端观察,tail -f /var/log/kern.log,查看内核日志的输出,从而观察到各个命令的执行时,他们会去执行哪一个函数。
|