网卡驱动10-做一个与外界交互的虚拟网卡6(突发奇想!搞个网络鼠标!)

昨天晚上突然想到这个东西,今天花了一上午实现了!不过具体速度怎么样就不清楚了!

首先是目的!一个系统上的鼠标去控制另一个系统。通过网线连接。

方案!在一个系统上获取鼠标信息网传到另一个系统,接受信息的系统通过input机制上报。

对于网传的接受,你可以在用户层去做,我是在内核层去做的,参考我之前搞的vnic代码。我就不废话了,直接代码:

/*
 */

#include <linux/capability.h>
#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/rculist.h>
#include <net/p8022.h>
#include <net/arp.h>
#include <net/ip.h>
#include <linux/rtnetlink.h>
#include <linux/notifier.h>
#include <net/rtnetlink.h>
#include <net/net_namespace.h>
#include <net/netns/generic.h>
#include <asm/uaccess.h>
#include <linux/etherdevice.h>
#include <linux/ip.h>
#include <linux/usb/input.h>

#include "vnic.h"

#define DRV_VERSION "1.0"

/* End of global variables definitions. */
    
static void vnic_group_free(struct vnic_group *grp)
{
    int i;

    for (i = 0; i < VNIC_GROUP_ARRAY_SPLIT_PARTS; i++)//释放所有已申请的虚拟网卡
        kfree(grp->vnic_devices_arrays[i]);
    kfree(grp);//释放一个vnic_group结构
}

static struct vnic_group *vnic_group_alloc(void)
{
    struct vnic_group *grp;

    grp = kzalloc(sizeof(struct vnic_group), GFP_KERNEL);//申请一个vnic_group结构
    if (!grp)
        return NULL;

    return grp;
}

static int vnic_group_prealloc_vid(struct vnic_group *vg, u16 vnic_id)
{
    struct net_device **array;
    unsigned int size;

    array = vg->vnic_devices_arrays[vnic_id / VNIC_GROUP_ARRAY_PART_LEN];//这样是为了多组设计的,其实我就一组
    if (array != NULL)
        return 0;

    size = sizeof(struct net_device *) * VNIC_GROUP_ARRAY_PART_LEN;//一组有8个
    array = kzalloc(size, GFP_KERNEL);
    if (array == NULL)
        return -ENOBUFS;

    vg->vnic_devices_arrays[vnic_id / VNIC_GROUP_ARRAY_PART_LEN] = array;

    return 0;
}

static struct net_device *real_netdev = NULL;
static struct vnic_group *vnic_grp = NULL;
static struct input_dev *input_dev = NULL;

static int vnic_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *ptype, struct net_device *orig_dev)
{
#if 0
    struct net_device *vnic_dev;
    struct vnic_pcpu_stats *rx_stats;
    u16 vnic_id = skb->data[1];//这部就相当于解析我们自己的头

#if 1
    u16 i;
    for (i = 0; i < skb->mac_len; i++)
    {
        printk("%x ", skb->mac_header[i]);
    }

    printk("\n");
#endif

    vnic_dev = vnic_group_get_device(vnic_grp, vnic_id);
    if (vnic_dev == NULL)
    {
        return -1;
    }

    //检查skb的应用计数是否大于1,大于1意味着内核的其他部分拥有对
    //该缓冲区的引用。如果大于1,会自己建立一份缓冲区副本。
    skb = skb_share_check(skb, GFP_ATOMIC);
    if (unlikely(!skb))
    {
        return false;
    }

    skb->dev = vnic_dev;
    //PACKET_OTHERHOST表示L2目的地址和接收接口的地址不同
    //通常会被丢弃掉。如果网卡进入混杂模式,会接收所以包
    //这里我们就要自己比较一下。
    if (skb->pkt_type == PACKET_OTHERHOST) {
        if (!compare_ether_addr(eth_hdr(skb)->h_dest, vnic_dev->dev_addr))
            skb->pkt_type = PACKET_HOST;
    }

    rx_stats = (struct vnic_pcpu_stats *)this_cpu_ptr(vnic_dev_info(vnic_dev)->vnic_pcpu_stats);
    
    u64_stats_update_begin(&rx_stats->syncp);
    rx_stats->rx_packets++;
    rx_stats->rx_bytes += skb->len;
    if (skb->pkt_type == PACKET_MULTICAST)
        rx_stats->rx_multicast++;
    u64_stats_update_end(&rx_stats->syncp);
#else
    __u16 type;
    __u16 code;
    //__s8 value;

    type = skb->data[0] | (skb->data[1] << 8);
    code = skb->data[2] | (skb->data[3] << 8);

    if (type == 1)
    {
        switch(code)
        {
        case BTN_LEFT:
            input_report_key(input_dev, BTN_LEFT,   skb->data[6]);break;
        case BTN_RIGHT:
            input_report_key(input_dev, BTN_RIGHT,  skb->data[6]);break;
        case BTN_MIDDLE:
            input_report_key(input_dev, BTN_MIDDLE, skb->data[6]);break;
        case BTN_SIDE:
            input_report_key(input_dev, BTN_SIDE,   skb->data[6]);break;
        case BTN_EXTRA:
            input_report_key(input_dev, BTN_EXTRA,  skb->data[6]);break;
        default: break;
        }
    }
    
    if (type == 2)
    {
        switch(code)
        {
        case 0:
            input_report_rel(input_dev, REL_X,     (signed char)skb->data[6]);break;
        case 1:
            input_report_rel(input_dev, REL_Y,     (signed char)skb->data[6]);break;
        case 8:
            input_report_rel(input_dev, REL_WHEEL, (signed char)skb->data[6]);break;
        default: break;
        }
    }

    input_sync(input_dev);

#endif
    return 0;
}

static struct packet_type vnic_pack_type __read_mostly =
{
    .type = cpu_to_be16(ETH_P_VNIC),
    .func = vnic_rcv,
};

void unregister_vnic_dev(void)
{
    struct vnic_dev_info *vnic;
    struct net_device *real_dev;
    struct net_device *tempdev;
    u16 n = vnic_grp->nr_vnics, i;
    LIST_HEAD(list);

    rtnl_lock();
    for (i = 0; i < n; i++)
    {
        tempdev = vnic_group_get_device(vnic_grp, i);
        if (tempdev == NULL)
        {
            goto enodev;
        }
        vnic = vnic_dev_info(tempdev);
        real_dev = vnic->real_dev;

        vnic_grp->nr_vnics--;//已申请虚拟网卡数减一
        vnic_group_set_device(vnic_grp, i, NULL);//根据vnic_id获取对应的虚拟网卡

        //unregister_netdevice_queue(tempdev, &list);
        unregister_netdevice(tempdev);
        /* 减少真实设备的应用应用计数 */
        dev_put(real_dev);
        vnic->real_dev = NULL;
    }
enodev:
    rtnl_unlock();
}
EXPORT_SYMBOL(unregister_vnic_dev);

int register_vnic_dev(struct net_device *dev)
{
    struct vnic_dev_info *vnic = vnic_dev_info(dev);
    struct net_device *real_dev = vnic->real_dev = real_netdev;
    u16 vnic_id = vnic->vnic_id;
    int err;

    if ((vnic_grp == NULL) || (real_netdev == NULL))
    {
        return -ENODEV;
    }
    
    dev->mtu = real_netdev->mtu;


    rtnl_lock();

    err = register_netdevice(dev);//装载网卡
    if (err < 0)
    {
        rtnl_unlock();

        goto out_uninit_applicant;
    }

    /* 增加真实设备的应用应用计数 */
    dev_hold(real_dev);

    //这个函数是根据real_dev的dormat和连接状态来控制dev的连接上报
    //下面的event也是通过它。
    netif_stacked_transfer_operstate(real_dev, dev);
    
    rtnl_unlock();

    /* So, got the sucker initialized, now lets place
     * it into our local structure.
     */
    vnic_group_set_device(vnic_grp, vnic_id, dev);//设置次虚拟网卡的id
    vnic_grp->nr_vnics++;//已申请虚拟网卡数加一

    return 0;

out_uninit_applicant:

    return err;
}
EXPORT_SYMBOL(register_vnic_dev);

static void vnic_sync_address(struct net_device *dev,
                  struct net_device *vnicdev)//同步mac地址
{
    struct vnic_dev_info *vnic = vnic_dev_info(vnicdev);

    /* May be called without an actual change */
    /*
    下面这个函数很酷,有个判断数组相等的公式:
    ((a[0] ^ b[0]) | (a[1] ^ b[1]) | (a[2] ^ b[2])) != 0;
    成立就是相等
    */
    if (!compare_ether_addr(vnic->real_dev_addr, dev->dev_addr))//相等退出
        return;

    /* vnic address was different from the old address and is equal to
     * the new address */
    if (compare_ether_addr(vnicdev->dev_addr, vnic->real_dev_addr) &&
        !compare_ether_addr(vnicdev->dev_addr, dev->dev_addr))
        dev_uc_del(dev, vnicdev->dev_addr);//释放单播地址

    /* vnic address was equal to the old address and is different from
     * the new address */
    if (!compare_ether_addr(vnicdev->dev_addr, vnic->real_dev_addr) &&
        compare_ether_addr(vnicdev->dev_addr, dev->dev_addr))
        dev_uc_add(dev, vnicdev->dev_addr);//增加单播地址,这样会启动混杂模式,进行监听
                                           //由于vnic和真实网卡的mac不一样,所以要用混杂模式

    memcpy(vnic->real_dev_addr, dev->dev_addr, ETH_ALEN);//赋值地址
}

//通知链会调用的函数
static int vnic_device_event(struct notifier_block *unused, unsigned long event,
                 void *ptr)
{
    struct net_device *dev = ptr;
    int i, flgs;
    struct net_device *vnicdev;
    struct vnic_dev_info *vnic;

    if (!vnic_grp)
        goto out;

    /* It is OK that we do not hold the group lock right now,
     * as we run under the RTNL lock.
     */

    switch (event) {
    case NETDEV_CHANGE:
        /* Propagate real device state to vnic devices */
        for (i = 0; i < VNIC_N_VID; i++) {
            vnicdev = vnic_group_get_device(vnic_grp, i);
            if (!vnicdev)
                continue;

            netif_stacked_transfer_operstate(dev, vnicdev);//链接状态刷新
        }
        break;

    case NETDEV_CHANGEADDR:
        /* Adjust unicast filters on underlying device */
        for (i = 0; i < VNIC_N_VID; i++) {
            vnicdev = vnic_group_get_device(vnic_grp, i);
            if (!vnicdev)
                continue;

            flgs = vnicdev->flags;
            if (!(flgs & IFF_UP))
                continue;

            vnic_sync_address(dev, vnicdev);//更新物理地址,上面有。
        }
        break;

    case NETDEV_CHANGEMTU://MTU被更新。
        for (i = 0; i < VNIC_N_VID; i++) {
            vnicdev = vnic_group_get_device(vnic_grp, i);
            if (!vnicdev)
                continue;

            if (vnicdev->mtu <= dev->mtu)
                continue;

            dev_set_mtu(vnicdev, dev->mtu);
        }
        break;

    case NETDEV_FEAT_CHANGE://功能发生变化
        /* Propagate device features to underlying device */
        for (i = 0; i < VNIC_N_VID; i++) {
            vnicdev = vnic_group_get_device(vnic_grp, i);
            if (!vnicdev)
                continue;

            netdev_update_features(vnicdev);
        }

        break;

    case NETDEV_DOWN://关闭
        /* Put all VNICs for this dev in the down state too.  */
        for (i = 0; i < VNIC_N_VID; i++) {
            vnicdev = vnic_group_get_device(vnic_grp, i);
            if (!vnicdev)
                continue;

            flgs = vnicdev->flags;
            if (!(flgs & IFF_UP))
                continue;

            vnic = vnic_dev_info(vnicdev);

            dev_change_flags(vnicdev, flgs & ~IFF_UP);
            netif_stacked_transfer_operstate(dev, vnicdev);
        }
        break;

    case NETDEV_UP://开启
        /* Put all VNICs for this dev in the up state too.  */
        for (i = 0; i < VNIC_N_VID; i++) {
            vnicdev = vnic_group_get_device(vnic_grp, i);
            if (!vnicdev)
                continue;

            flgs = vnicdev->flags;
            if (flgs & IFF_UP)
                continue;

            vnic = vnic_dev_info(vnicdev);

            dev_change_flags(vnicdev, flgs | IFF_UP);
            netif_stacked_transfer_operstate(dev, vnicdev);
        }
        break;

    case NETDEV_UNREGISTER://注销
        /* twiddle thumbs on netns device moves */
        if (dev->reg_state != NETREG_UNREGISTERING)
            break;

        //unregister_vnic_dev();
    
        break;

    //下面和bonding有关
    case NETDEV_PRE_TYPE_CHANGE:
        /* Forbid underlaying device to change its type. */
        return NOTIFY_BAD;

    case NETDEV_NOTIFY_PEERS:
    case NETDEV_BONDING_FAILOVER://失败
        /* Propagate to vnic devices */
        for (i = 0; i < VNIC_N_VID; i++) {
            vnicdev = vnic_group_get_device(vnic_grp, i);
            if (!vnicdev)
                continue;

            call_netdevice_notifiers(event, vnicdev);//通过call去传播失败信息
        }
        break;
    }

out:
    return NOTIFY_DONE;
}

static struct notifier_block vnic_notifier_block __read_mostly = {
    .notifier_call = vnic_device_event,
};

static char name[10] = "net mouse";
static char phys[10] = "/input0";
static int __init vnic_proto_init(void)
{
    int err = 0;

    real_netdev = dev_get_by_name(&init_net, "eth0");
    if (real_netdev == NULL)
    {
        return -ENODEV;
    }

    vnic_grp = vnic_group_alloc();
    if (vnic_grp == NULL)
    {
        err = -ENOBUFS;

        goto error;
    }

    vnic_grp->real_dev = real_netdev;

    input_dev = input_allocate_device();
    if (!input_dev)
    {
        vnic_group_free(vnic_grp);
        goto error;
    }

    input_dev->name = name;
    input_dev->phys = phys;

    input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
    input_dev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) |
        BIT_MASK(BTN_RIGHT) | BIT_MASK(BTN_MIDDLE);
    input_dev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
    input_dev->keybit[BIT_WORD(BTN_MOUSE)] |= BIT_MASK(BTN_SIDE) |
        BIT_MASK(BTN_EXTRA);
    input_dev->relbit[0] |= BIT_MASK(REL_WHEEL);

    err = input_register_device(input_dev);
    if (err)
    {
        input_free_device(input_dev);
        vnic_group_free(vnic_grp);
        goto error;
    }

    err = vnic_group_prealloc_vid(vnic_grp, 0);
    if (err < 0)
    {
        input_unregister_device(input_dev);
        input_free_device(input_dev);
        vnic_group_free(vnic_grp);
        goto error;
    }

    err = register_netdevice_notifier(&vnic_notifier_block);
    if (err < 0)
    {
        input_unregister_device(input_dev);
        input_free_device(input_dev);
        vnic_group_free(vnic_grp);
        goto error;
    }

    dev_add_pack(&vnic_pack_type);

    return 0;

error:

    return err;
}
    
static void __exit vnic_cleanup_module(void)
{
    input_unregister_device(input_dev);
    input_free_device(input_dev);

    if (vnic_grp != NULL)
    {
        vnic_group_free(vnic_grp);
    }

    unregister_netdevice_notifier(&vnic_notifier_block);

    dev_remove_pack(&vnic_pack_type);
}

module_init(vnic_proto_init);
module_exit(vnic_cleanup_module);

MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_VERSION);


主要就是加上了input上报!下面调试:

在接受端搞个测试程序:

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <linux/input.h>

int main (void)
{
    int fd,i,count;
    struct input_event ev_mouse[2];

    fd = open ("/dev/event0",O_RDWR);

    if (fd < 0) {
        printf ("fd open failed\n");

        return -1;

    }

    printf ("\nmouse opened, fd=%d\n",fd);

    while(1)
    {
        count=read(fd, ev_mouse, sizeof(struct input_event));

        for(i=0;i<(int)count/sizeof(struct input_event);i++)
        {
            if(EV_REL==ev_mouse[i].type)
            {
                printf("%d %d %d\n",ev_mouse[i].type,ev_mouse[i].code,ev_mouse[i].value);
            }

            if(EV_KEY==ev_mouse[i].type)
            {
                printf("%d %d %d\n",ev_mouse[i].type,ev_mouse[i].code,ev_mouse[i].value);
            }
        }
    }

    close (fd);

    return 0;
}
编译运行起来:

然后再搞个发送程序:

#include <stdio.h>  
#include <stdlib.h>  
#include <string.h>  
#include <unistd.h>  
#include <sys/socket.h>  
#include <linux/if_packet.h>  
#include <netdb.h>  
#include <errno.h>  
#include <arpa/inet.h>  
#include <sys/ioctl.h>  
#include <pthread.h>    
#include <net/ethernet.h>  
#include <netinet/ether.h>  
#include <net/if.h>  
#include <netinet/ip.h>  
#include <netinet/tcp.h>
#include <fcntl.h>
#include <linux/input.h>

static int sockfd;   
static struct sockaddr_ll peer_addr;   

static unsigned char vnic_num = 0;//选择哪个网卡

#define X86_TEST //pc上运行定义它

#ifdef X86_TEST
#define ETH_P_VNIC    0x8877

static unsigned char src_mac[6] = {0x00, 0x0c, 0x29, 0x15, 0xd9, 0xc5}; //发送端地址
static unsigned char dst_mac[6] = {0xba, 0x06, 0xdb, 0xe5, 0x7f, 0x0d};  //接收端地址
#else
static unsigned char src_mac[6] = {0xc0, 0x6f, 0x65, 0xaa, 0xdf, 0x61}; //发送端地址
static unsigned char dst_mac[6] = {0x00, 0x0c, 0x29, 0x15, 0xd9, 0xc5};  //接收端地址
#endif
struct arp_packet 
{  
    struct ether_header  eh;  
    __u16 type;
    __u16 code;
    __s32 value;
};  
 
static void send_pkt(void) 
{  

    struct arp_packet frame; 
    int fd,i,count;
    struct input_event ev_mouse[2];

    memset(&frame, 0, sizeof(struct arp_packet));
    memcpy(frame.eh.ether_dhost, dst_mac, 6);  
    memcpy(frame.eh.ether_shost, src_mac, 6);  
#ifdef X86_TEST//pc上只能在应用层去加
    frame.eh.ether_type = htons(ETH_P_VNIC);  
    //frame.data = htons(('w' << 8) | vnic_num);
#endif

    fd = open ("/dev/input/event1",O_RDWR);

    if (fd < 0) {

        printf ("fd open failed\n");

        return;

    }

    printf ("\nmouse opened, fd=%d\n",fd);
    
    while(1)
    {
        count=read(fd, ev_mouse, sizeof(struct input_event));
        for(i=0;i<(int)count/sizeof(struct input_event);i++)
        {
            if(EV_REL==ev_mouse[i].type)
            {

                frame.type = ev_mouse[i].type;
                frame.code = ev_mouse[i].code;
                frame.value = ev_mouse[i].value;
                sendto(sockfd, &frame, sizeof(frame), 0, (struct sockaddr*)&peer_addr, sizeof(peer_addr)); 
                printf("%d %d %d\n",ev_mouse[i].type,ev_mouse[i].code,ev_mouse[i].value);
            }

            if(EV_KEY==ev_mouse[i].type)

            {
                frame.type = ev_mouse[i].type;
                frame.code = ev_mouse[i].code;
                frame.value = ev_mouse[i].value;
                sendto(sockfd, &frame, sizeof(frame), 0, (struct sockaddr*)&peer_addr, sizeof(peer_addr)); 
                printf("%d %d %d\n",ev_mouse[i].type,ev_mouse[i].code,ev_mouse[i].value);
            }
        }

    }


    

    close (fd);
}  

 

int main(int argc, char **argv) 
{   
    struct ifreq req;

    if (argc <= 2)
    {
        return -1;
    }

    sockfd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_VNIC));  
    if(sockfd == -1)
    {
        perror("socket()");
    }

    memset(&peer_addr, 0, sizeof(peer_addr));  
    peer_addr.sll_family = AF_PACKET;  
  
    strcpy(req.ifr_name, argv[1]);  
    vnic_num = (*argv[2] - '0');

    if(ioctl(sockfd, SIOCGIFINDEX, &req) != 0)
    {
        perror("ioctl()");
    }

    peer_addr.sll_ifindex = req.ifr_ifindex;  
    peer_addr.sll_protocol = htons(ETH_P_ARP);  

    send_pkt();
        
    close(sockfd);

    return 0;  
}  

发送在pc上运行,检测的arm上,同时运行,看效果:

pc:

网卡驱动10-做一个与外界交互的虚拟网卡6(突发奇想!搞个网络鼠标!)_第1张图片

arm:

网卡驱动10-做一个与外界交互的虚拟网卡6(突发奇想!搞个网络鼠标!)_第2张图片

这些都是动动鼠标的结果!

你可能感兴趣的:(linux,鼠标,网卡,ARM,linux内核)