179 lines
3.6 KiB
C
Executable File
179 lines
3.6 KiB
C
Executable File
#include <linux/init.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/module.h>
|
|
|
|
#include <linux/netdevice.h>
|
|
#include <linux/etherdevice.h>
|
|
#include <linux/skbuff.h>
|
|
|
|
#include <linux/ip.h>
|
|
|
|
#include "vnet.h"
|
|
|
|
struct net_device *vnet_dev;
|
|
|
|
static int vnet_open(struct net_device *dev)
|
|
{
|
|
netif_start_queue(dev);
|
|
return 0;
|
|
}
|
|
|
|
static int vnet_stop(struct net_device *dev)
|
|
{
|
|
netif_stop_queue(dev);
|
|
return 0;
|
|
}
|
|
|
|
void vnet_rx(struct net_device *dev)
|
|
{
|
|
struct sk_buff *skb;
|
|
struct vnet_priv *priv = netdev_priv(dev);
|
|
|
|
skb = dev_alloc_skb(priv->rxlen + 2);
|
|
if (IS_ERR(skb)) {
|
|
printk(KERN_NOTICE "vnet: low on mem - packet dropped\n");
|
|
dev->stats.rx_dropped++;
|
|
return;
|
|
}
|
|
skb_reserve(skb, 2);
|
|
memcpy(skb_put(skb, priv->rxlen), priv->rxdata, priv->rxlen);
|
|
|
|
skb->dev = dev;
|
|
skb->protocol = eth_type_trans(skb, dev);
|
|
skb->ip_summed = CHECKSUM_UNNECESSARY;
|
|
dev->stats.rx_packets++;
|
|
dev->stats.rx_bytes += priv->rxlen;
|
|
netif_rx(skb);
|
|
|
|
return;
|
|
}
|
|
|
|
static void vnet_rx_int(char *buf, int len, struct net_device *dev)
|
|
{
|
|
struct vnet_priv *priv;
|
|
|
|
priv = netdev_priv(dev);
|
|
priv->rxlen = len;
|
|
memcpy(priv->rxdata, buf, len);
|
|
vnet_rx(dev);
|
|
|
|
return;
|
|
}
|
|
|
|
static void vnet_hw_tx(char *buf, int len, struct net_device *dev)
|
|
{
|
|
#if DEBUG
|
|
int i;
|
|
#endif
|
|
|
|
struct iphdr *ih;
|
|
struct net_device *dest;
|
|
struct vnet_priv *priv;
|
|
u32 *saddr, *daddr;
|
|
|
|
if (len < sizeof(struct ethhdr) + sizeof(struct iphdr)) {
|
|
printk("vnet: Packet too short (%i octets)\n", len);
|
|
return;
|
|
}
|
|
|
|
#if DEBUG
|
|
printk("len is %i\n", len);
|
|
printk("data: ");
|
|
for (i = 0; i < len; i++)
|
|
printk(" %02x",buf[i] & 0xff);
|
|
printk("\n");
|
|
#endif
|
|
|
|
ih = (struct iphdr *)(buf + sizeof(struct ethhdr));
|
|
saddr = &ih->saddr;
|
|
daddr = &ih->daddr;
|
|
((u8 *)saddr)[3] = ((u8 *)saddr)[3] ^ ((u8 *)daddr)[3];
|
|
((u8 *)daddr)[3] = ((u8 *)saddr)[3] ^ ((u8 *)daddr)[3];
|
|
((u8 *)saddr)[3] = ((u8 *)saddr)[3] ^ ((u8 *)daddr)[3];
|
|
|
|
ih->check = 0;
|
|
ih->check = ip_fast_csum((unsigned char *)ih,ih->ihl);
|
|
|
|
#if DEBUG
|
|
printk("len is %i\n", len);
|
|
printk("data: ");
|
|
for (i = 0; i < len; i++)
|
|
printk(" %02x",buf[i] & 0xff);
|
|
printk("\n\n");
|
|
#endif
|
|
|
|
dest = vnet_dev;
|
|
vnet_rx_int(buf, len, dest);
|
|
|
|
dev->stats.tx_packets++;
|
|
dev->stats.tx_bytes += len;
|
|
priv = netdev_priv(dev);
|
|
dev_kfree_skb(priv->txskb);
|
|
}
|
|
|
|
static netdev_tx_t vnet_tx(struct sk_buff *skb, struct net_device *dev)
|
|
{
|
|
int len;
|
|
char *data, shortpkt[ETH_ZLEN];
|
|
struct vnet_priv *priv = netdev_priv(dev);
|
|
|
|
data = skb->data;
|
|
len = skb->len;
|
|
if (len < ETH_ZLEN) {
|
|
memset(shortpkt, 0, ETH_ZLEN);
|
|
memcpy(shortpkt, skb->data, skb->len);
|
|
len = ETH_ZLEN;
|
|
data = shortpkt;
|
|
}
|
|
dev->trans_start = jiffies;
|
|
priv->txskb = skb;
|
|
vnet_hw_tx(data, len, dev);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static const struct net_device_ops vnet_ops = {
|
|
.ndo_open = vnet_open,
|
|
.ndo_stop = vnet_stop,
|
|
.ndo_start_xmit = vnet_tx,
|
|
};
|
|
|
|
|
|
static int __init vnet_init(void)
|
|
{
|
|
int status;
|
|
struct vnet_priv *priv;
|
|
|
|
vnet_dev = alloc_etherdev(sizeof(struct vnet_priv));
|
|
if (IS_ERR(vnet_dev))
|
|
return -ENOMEM;
|
|
|
|
ether_setup(vnet_dev);
|
|
vnet_dev->netdev_ops = &vnet_ops;
|
|
vnet_dev->flags |= IFF_NOARP;
|
|
priv = netdev_priv(vnet_dev);
|
|
memset(priv, 0, sizeof(struct vnet_priv));
|
|
|
|
status = register_netdev(vnet_dev);
|
|
if (status) {
|
|
free_netdev(vnet_dev);
|
|
return status;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void __exit vnet_exit(void)
|
|
{
|
|
|
|
unregister_netdev(vnet_dev);
|
|
free_netdev(vnet_dev);
|
|
}
|
|
|
|
module_init(vnet_init);
|
|
module_exit(vnet_exit);
|
|
|
|
MODULE_LICENSE("GPL");
|
|
MODULE_AUTHOR("Kevin Jiang <jiangxg@farsight.com.cn>");
|
|
MODULE_DESCRIPTION("Virtual ethernet driver");
|