昨天晚上突然想到这个东西,今天花了一上午实现了!不过具体速度怎么样就不清楚了!
首先是目的!一个系统上的鼠标去控制另一个系统。通过网线连接。
方案!在一个系统上获取鼠标信息网传到另一个系统,接受信息的系统通过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);
在接受端搞个测试程序:
#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:
这些都是动动鼠标的结果!