1 // SPDX-License-Identifier: GPL-2.0-only 2 /* Copyright (c) 2022 Benjamin Tissoires 3 * 4 * This is a pure HID-BPF example, and should be considered as such: 5 * on the Etekcity Scroll 6E, the X and Y axes will be swapped and 6 * inverted. On any other device... Not sure what this will do. 7 * 8 * This C main file is generic though. To adapt the code and test, users 9 * must amend only the .bpf.c file, which this program will load any 10 * eBPF program it finds. 11 */ 12 13 #include <assert.h> 14 #include <errno.h> 15 #include <fcntl.h> 16 #include <libgen.h> 17 #include <signal.h> 18 #include <stdbool.h> 19 #include <stdio.h> 20 #include <stdlib.h> 21 #include <string.h> 22 #include <sys/resource.h> 23 #include <unistd.h> 24 25 #include <linux/bpf.h> 26 #include <linux/errno.h> 27 28 #include <bpf/bpf.h> 29 #include <bpf/libbpf.h> 30 31 #include "hid_mouse.skel.h" 32 #include "hid_bpf_attach.h" 33 34 static bool running = true; 35 36 static void int_exit(int sig) 37 { 38 running = false; 39 exit(0); 40 } 41 42 static void usage(const char *prog) 43 { 44 fprintf(stderr, 45 "%s: %s /sys/bus/hid/devices/0BUS:0VID:0PID:00ID\n\n", 46 __func__, prog); 47 fprintf(stderr, 48 "This program will upload and attach a HID-BPF program to the given device.\n" 49 "On the Etekcity Scroll 6E, the X and Y axis will be inverted, but on any other\n" 50 "device, chances are high that the device will not be working anymore\n\n" 51 "consider this as a demo and adapt the eBPF program to your needs\n" 52 "Hit Ctrl-C to unbind the program and reset the device\n"); 53 } 54 55 static int get_hid_id(const char *path) 56 { 57 const char *str_id, *dir; 58 char uevent[1024]; 59 int fd; 60 61 memset(uevent, 0, sizeof(uevent)); 62 snprintf(uevent, sizeof(uevent) - 1, "%s/uevent", path); 63 64 fd = open(uevent, O_RDONLY | O_NONBLOCK); 65 if (fd < 0) 66 return -ENOENT; 67 68 close(fd); 69 70 dir = basename((char *)path); 71 72 str_id = dir + sizeof("0003:0001:0A37."); 73 return (int)strtol(str_id, NULL, 16); 74 } 75 76 int main(int argc, char **argv) 77 { 78 struct hid_mouse *skel; 79 struct bpf_program *prog; 80 int err; 81 const char *optstr = ""; 82 const char *sysfs_path; 83 int opt, hid_id, attach_fd; 84 struct attach_prog_args args = { 85 .retval = -1, 86 }; 87 DECLARE_LIBBPF_OPTS(bpf_test_run_opts, tattr, 88 .ctx_in = &args, 89 .ctx_size_in = sizeof(args), 90 ); 91 92 while ((opt = getopt(argc, argv, optstr)) != -1) { 93 switch (opt) { 94 default: 95 usage(basename(argv[0])); 96 return 1; 97 } 98 } 99 100 if (optind == argc) { 101 usage(basename(argv[0])); 102 return 1; 103 } 104 105 sysfs_path = argv[optind]; 106 if (!sysfs_path) { 107 perror("sysfs"); 108 return 1; 109 } 110 111 skel = hid_mouse__open_and_load(); 112 if (!skel) { 113 fprintf(stderr, "%s %s:%d", __func__, __FILE__, __LINE__); 114 return -1; 115 } 116 117 hid_id = get_hid_id(sysfs_path); 118 119 if (hid_id < 0) { 120 fprintf(stderr, "can not open HID device: %m\n"); 121 return 1; 122 } 123 args.hid = hid_id; 124 125 attach_fd = bpf_program__fd(skel->progs.attach_prog); 126 if (attach_fd < 0) { 127 fprintf(stderr, "can't locate attach prog: %m\n"); 128 return 1; 129 } 130 131 bpf_object__for_each_program(prog, *skel->skeleton->obj) { 132 /* ignore syscalls */ 133 if (bpf_program__get_type(prog) != BPF_PROG_TYPE_TRACING) 134 continue; 135 136 args.retval = -1; 137 args.prog_fd = bpf_program__fd(prog); 138 err = bpf_prog_test_run_opts(attach_fd, &tattr); 139 if (err) { 140 fprintf(stderr, "can't attach prog to hid device %d: %m (err: %d)\n", 141 hid_id, err); 142 return 1; 143 } 144 } 145 146 signal(SIGINT, int_exit); 147 signal(SIGTERM, int_exit); 148 149 while (running) 150 sleep(1); 151 152 hid_mouse__destroy(skel); 153 154 return 0; 155 } 156