- 论坛徽章:
- 0
|
本帖最后由 Roemer 于 2010-04-02 16:58 编辑
- /*************************************************************************
- Fake eth char convert
- **************************************************************************/
- #include <linux/kernel.h>
- #include <linux/etherdevice.h>
- #include <linux/netdevice.h>
- #include <linux/moduleparam.h>
- #include <linux/errno.h>
- #include <linux/fcntl.h>
- #include <linux/file.h>
- #include <linux/proc_fs.h>
- #include <linux/init.h>
- #include <linux/module.h>
- #include <linux/smp_lock.h>
- #include <linux/device.h>
- #include <linux/wait.h>
- #include <linux/kmod.h>
- #include <linux/cdev.h>
- /* MAC地址 */
- static char vir_mac[]={0x00, 0xAA, 0xBB, 0xCC, 0xBB, 0xAA};
- char *vir_mac_p = NULL;
- int loop = 0; /* when loop=1, enable loopback mode,not write Yet :) */
- //VIRMAC
- module_param(vir_mac_p, charp, 0444);
- MODULE_PARM_DESC(vir_mac_p, "MAC");
- module_param(loop, int, 0);
- MODULE_PARM_DESC(loop, "loopback mode");
- #define ETH_BUFFER_LEN 1520
- #define FAKE_IRQ 18
- #define ETH_VIR_MAJOR 160
- struct s_buff
- {
- unsigned char buffer[ETH_BUFFER_LEN];
- unsigned int length;
- };
- //buffer for Eth
- static struct s_buff tx_buff;
- static struct s_buff rx_buff;
- struct vireth_priv
- {
- struct net_device * netdev; /* net device parameter */
- struct net_device_stats stats; /* net statistics */
- struct sk_buff *skb; /* free send skb*/
- struct proc_dir_entry *entry;
- wait_queue_head_t inq; /* send waitQ, for eth char read */
- struct semaphore sem;
-
- };
- static struct vireth_priv * dev_vireth = NULL;
- #define VIRETH_NAME "vir_eth" /* 网络设备的名字 */
- static int vireth_open(struct net_device *dev);
- static int vireth_release(struct net_device *dev);
- static void vireth_init(struct net_device *dev);
- static int vireth_xmit(struct sk_buff *skb, struct net_device *dev);
- static int vireth_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
- static int transmit_int(int irq, void *dev_id);
- static int receive_int(int irq, void *dev_id);
- /************************* MII Proc interface **************************/
- static int MII_read_proc(char *page, char **start, off_t off,
- int count, int *eof, void *data)
- {
- #if 0
- int length;
-
- if (down_interruptible(&dev_vireth->sem))
- {
- return -ERESTARTSYS;
- }
- //
- while( 0 == tx_buff.length )
- {
- up(&dev_vireth->sem);
- //sleep
- if( wait_event_interruptible(dev_vireth->inq,(0 != tx_buff.length)) )
- {
- return -ERESTARTSYS;
- }
-
- if (down_interruptible(&dev_vireth->sem))
- {
- return -ERESTARTSYS;
- }
- }
-
- memcpy(page,tx_buff.buffer,tx_buff.length );
- length = tx_buff.length;
- tx_buff.length = 0;
-
- up(&dev_vireth->sem);
- *eof = 1;
-
- transmit_int(FAKE_IRQ,dev_vireth);
- //printk("#### %d##\n",length);
-
- return length;
- #endif
- ////////////
- *eof = 1;
- return 0;
- }
- static int MII_write_proc(struct file *file, const char *buffer,
- unsigned long count, void *data)
- {
- #if 0
-
- if(count > ETH_BUFFER_LEN)
- {
- printk("Error input len\n");
- return -1;
- }
-
- memcpy(rx_buff.buffer, buffer, count);
- rx_buff.length = count;
- receive_int(FAKE_IRQ,dev_vireth);
-
- return count;
-
- #endif
- ///////////////
- return 0;
- }
- /************************* fake interrupt**************************/
- static int receive_int(int irq, void *dev_id)
- {
- struct sk_buff *skb;
- //struct vireth_priv *priv = netdev_priv(dev);
- /*
- * The packet has been retrieved from the transmission
- * medium. Build an skb around it, so upper layers can handle it
- */
- skb = dev_alloc_skb(rx_buff.length + 4);
- if (!skb)
- {
- if (printk_ratelimit())
- { printk(KERN_NOTICE "snull rx: low on mem - packet dropped\n");}
- dev_vireth->stats.rx_dropped++;
- goto out;
- }
- skb_reserve(skb, 2); /* align IP on 16B boundary */
-
- memcpy(skb_put(skb, rx_buff.length), rx_buff.buffer, rx_buff.length);
-
- /* Write metadata, and then pass to the receive level */
- skb->protocol = eth_type_trans(skb, dev_vireth->netdev);
- //skb->ip_summed = CHECKSUM_UNNECESSARY; /* don't check it */
- dev_vireth->stats.rx_packets++;
- dev_vireth->stats.rx_bytes += rx_buff.length;
- netif_rx(skb);
- out:
- return 0;
- }
- //send finished
- static int transmit_int(int irq, void *dev_id)
- {
- dev_kfree_skb(dev_vireth->skb);
- netif_wake_queue(dev_vireth->netdev);
- return 0;
- }
- /*************************Eth interface **************************/
- static int vireth_open(struct net_device *dev)
- {
- /* 启动发送队列 */
- netif_start_queue(dev);
- return 0;
- }
- static int vireth_release(struct net_device *dev)
- { /* 停止发送队列 */
- netif_stop_queue(dev); /* can't transmit any more */
- return 0;
- }
- //copy from skb to buffer
- static int vireth_write_packet(struct sk_buff *skb, struct net_device *dev)
- {
- //lock char read
- if(down_interruptible(&dev_vireth->sem))
- {
- return 1;
- }
- //still have pack int TX buffer
- if(tx_buff.length !=0 )
- {
- up(&dev_vireth->sem);
- return 1;
- }
- memcpy(tx_buff.buffer, skb->data, skb->len);
- tx_buff.length = skb->len;
- up(&dev_vireth->sem);
- wake_up_interruptible(&dev_vireth->inq);
-
- return 0;
- }
- static int vireth_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
- {
- int rc = 0;
- switch (cmd)
- {
- default:
- rc = -ENOSYS;
- break;
- }
- return rc;
- }
- //call by up layer
- static int vireth_xmit(struct sk_buff *skb, struct net_device *dev)
- {
- struct vireth_priv * priv = (struct vireth_priv *)netdev_priv(dev);
- int rc;
- netif_stop_queue(dev);
- if (vireth_write_packet(skb, dev))
- {
- priv->stats.tx_dropped++;
- rc = 1;
- }
- else
- {
- priv->stats.tx_packets++;
- priv->stats.tx_bytes += skb->len;
- priv->skb = skb;
- dev->trans_start = jiffies; /* save the timestamp */
- rc = 0;
- }
- return rc;
- }
- static struct net_device_stats *vireth_get_stats(struct net_device *dev)
- {
- struct vireth_priv * priv = (struct vireth_priv *)netdev_priv(dev);
- return &(priv->stats);
- }
- /* fake multicast ability */
- static void set_multicast_list(struct net_device *dev)
- {
- return;
- }
- static int set_mac_address(struct net_device *dev, void* addr)
- {
- struct sockaddr *address = addr;
- if (!is_valid_ether_addr(address->sa_data))
- {
- return -EADDRNOTAVAIL;
- }
- memcpy(dev->dev_addr, address->sa_data, dev->addr_len);
- printk("%s: Setting MAC address to %pM\n", dev->name, dev->dev_addr);
- return 0;
- }
- static const struct net_device_ops vireth_netdev_ops = {
- .ndo_open = vireth_open,
- .ndo_stop = vireth_release,
- .ndo_do_ioctl = vireth_ioctl,
- .ndo_get_stats = vireth_get_stats,
- .ndo_start_xmit = vireth_xmit,
- .ndo_set_multicast_list = set_multicast_list,
- .ndo_set_mac_address = set_mac_address,
- };
- /************************char dev ************************/
- static struct cdev vireth_cdev;
- static int vireth_char_open(struct inode * inode, struct file * filp)
- {
- return 0;
- }
- static int vireth_char_release(struct inode * inode, struct file * filp)
- {
- return 0;
- }
- static int vireth_char_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg)
- {
- switch(cmd)
- {
- default:
- return -EINVAL;
- }
-
- return 0;
- }
- //eth out put packet
- static ssize_t vireth_char_read(struct file * file, char __user * buf, size_t count, loff_t *ppos)
- {
- int length;
- unsigned long ret;
-
- if (down_interruptible(&dev_vireth->sem))
- {
- return -ERESTARTSYS;
- }
- //
- while( 0 == tx_buff.length )
- {
- up(&dev_vireth->sem);
- //sleep
- if( wait_event_interruptible(dev_vireth->inq,(0 != tx_buff.length)) )
- {
- return -ERESTARTSYS;
- }
-
- if (down_interruptible(&dev_vireth->sem))
- {
- return -ERESTARTSYS;
- }
- }
-
- ret = copy_to_user(buf,tx_buff.buffer,tx_buff.length );
- length = tx_buff.length;
- tx_buff.length = 0;
-
- up(&dev_vireth->sem);
-
- transmit_int(FAKE_IRQ,dev_vireth);
- //printk("#### %d##\n",length);
-
- return length;
-
- }
- static ssize_t vireth_char_write(struct file * file, const char __user * buf, size_t count,
- loff_t *ppos)
- {
- unsigned long ret;
- if(count > ETH_BUFFER_LEN)
- {
- printk("Error input len\n");
- return -1;
- }
-
- ret = copy_from_user(rx_buff.buffer, buf, count);
- rx_buff.length = count;
- receive_int(FAKE_IRQ,dev_vireth);
-
- return count;
- }
- static struct file_operations vireth_char_fops = {
- .llseek = NULL,
- .read = vireth_char_read,
- .write = vireth_char_write,
- .ioctl = vireth_char_ioctl,
- .open = vireth_char_open,
- .release = vireth_char_release,
- .fasync = NULL,
- };
- static int __init vireth_char_init(void)
- {
- int ret;
- int devno = MKDEV(ETH_VIR_MAJOR,0);
-
- printk("Vireth version:%s %s\n",__DATE__,__TIME__);
-
- cdev_init(&vireth_cdev, &vireth_char_fops);
- vireth_cdev.owner = THIS_MODULE;
- ret = cdev_add(&vireth_cdev, devno, 1);
- if(ret)
- {
- return ret;
- }
-
- return 0;
- }
- static void __exit vireth_char_exit(void)
- {
- cdev_del(&vireth_cdev);
- }
- /*************************eth init **************************/
- static void vireth_init(struct net_device *dev)
- {
- struct vireth_priv * priv = NULL;
- ether_setup(dev);
- dev->netdev_ops = &vireth_netdev_ops;
- dev->watchdog_timeo = 3*HZ;
- dev->irq = FAKE_IRQ;//no use
-
- memcpy(dev->dev_addr, vir_mac, ETH_ALEN);
- priv = (struct vireth_priv *)netdev_priv(dev);
- dev_vireth = priv;
-
- priv->netdev = dev;
- }
- inline char ascTochar(char s)
- {
- if( ('0'<= s) && ( s<='9') )
- {
- return (s-'0');
- }
-
- else if( ('a'<= s) && (s<='f') )
- {
- return (s-'a'+10);
- }
- else if( ('A'<= s) && (s<='F') )
- {
- return (s-'A'+10);
- }
- else
- {
- return 0;
- }
-
- }
- static int __init vireth_init_module(void)
- {
- int rc = 0;
- int i;
-
- struct net_device *net_dev = NULL;
-
- printk("Input MAC:%s\n",vir_mac_p);
- if(vir_mac_p)
- {
- for(i=0;i<6;i++)
- {
- vir_mac[i] = ascTochar( *(vir_mac_p+i*2) )<<4;
- vir_mac[i] |=ascTochar( *(vir_mac_p+i*2+1) );
- }
- }
- //
- printk("active MAC: ");
- for(i=0;i<6;i++)
- {
- printk("%02X:",vir_mac[i]);
- }
- printk("\n");
-
- /* alloc net dev */
- net_dev = alloc_netdev(sizeof(struct vireth_priv), VIRETH_NAME, vireth_init);
- if (!net_dev)
- {
- //log(KERN_ERR "no enough memory!\n");
- rc = -1;
- goto ERROR0;
- }
- /* got a name for eth*/
- rc = dev_alloc_name(net_dev, VIRETH_NAME);
- if (rc < 0)
- {
- //log(KERN_INFO "failed to alloc device name %s\n", VIRETH_NAME);
- goto ERROR0;
- }
- rc = register_netdev(net_dev);
- if (rc < 0)
- {
- goto ERROR0;
- }
-
- dev_vireth->entry = create_proc_entry("VIR_ETH_MII_DATA", 0, NULL);
- if (dev_vireth->entry == NULL)
- {
- return -ENOMEM;
- }
- dev_vireth->entry->read_proc = MII_read_proc;
- dev_vireth->entry->write_proc = MII_write_proc;
- dev_vireth->entry->data = NULL;
-
- init_waitqueue_head(&dev_vireth->inq);
- init_MUTEX(&dev_vireth->sem);
-
- vireth_char_init();
- return rc;
- ERROR0:
-
- free_netdev(net_dev);
- return rc;
- }
- static void __exit vireth_cleanup_module(void)
- {
- unregister_netdev(dev_vireth->netdev);
- remove_proc_entry("VIR_ETH_MII_DATA", NULL);
- free_netdev(dev_vireth->netdev);
- vireth_char_exit();
- }
- module_init(vireth_init_module);
- module_exit(vireth_cleanup_module);
- MODULE_AUTHOR("roemer");
- MODULE_DESCRIPTION("virtual ETH driver");
- MODULE_LICENSE("GPL");
复制代码 |
|