您的位置:首页 > 理论基础 > 计算机网络

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

2014-02-26 14:26 706 查看
昨天晚上突然想到这个东西,今天花了一上午实现了!不过具体速度怎么样就不清楚了!

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

方案!在一个系统上获取鼠标信息网传到另一个系统,接受信息的系统通过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:



arm:



这些都是动动鼠标的结果!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息