--- /dev/null
+/**************************************************************************/
+/* CAN user space gateway for performance benchmarks */
+/* Copyright (C) 2013, 2014 Michal Sojka, DCE, FEE, CTU Prague */
+/* License: GPLv2 */
+/**************************************************************************/
+
+#define _GNU_SOURCE
+#include <sys/socket.h>
+#include <linux/can.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+#include <stdbool.h>
+
+#define STRINGIFY(val) #val
+#define TOSTRING(val) STRINGIFY(val)
+#define CHECK(cmd) ({ int ret = (cmd); if (ret == -1) { perror(#cmd " line " TOSTRING(__LINE__)); exit(1); }; ret; })
+
+char *devin = "can0";
+char *devout = "can1";
+enum { READ, RECVMMSG } in_method = READ;
+enum { WRITE } out_method = WRITE;
+bool quiet = false;
+
+#define VERBOSE(format, ...) do { if (!quiet) fprintf(stderr, format, ##__VA_ARGS__); } while (0)
+
+struct in_ctx {
+ int s;
+ int for_out;
+ int (*in_fn)(struct in_ctx *ctx, struct can_frame *cf);
+};
+
+struct out_ctx {
+ int s;
+ int from_in;
+ int (*out_fn)(struct out_ctx *ctx, struct can_frame *cf);
+};
+
+int in_read(struct in_ctx *ctx, struct can_frame *cf)
+{
+ int ret = read(ctx->s, cf, sizeof(*cf));
+ if (ret != sizeof(*cf)) {
+ perror("read");
+ exit(1);
+ }
+ return 0;
+}
+
+void init_read(struct in_ctx *ctx)
+{
+ int s;
+ struct sockaddr_can addr;
+ struct ifreq ifr;
+
+ s = CHECK(socket(PF_CAN, SOCK_RAW, CAN_RAW));
+
+ strcpy(ifr.ifr_name, devin);
+ if (-1 == ioctl(s, SIOCGIFINDEX, &ifr)) {
+ perror(devin);
+ exit(1);
+ }
+
+ addr.can_family = AF_CAN;
+ addr.can_ifindex = ifr.ifr_ifindex;
+
+ CHECK(bind(s, (struct sockaddr *)&addr, sizeof(addr)));
+
+ ctx->s = s;
+ ctx->in_fn = in_read;
+}
+
+int out_write(struct out_ctx *ctx, struct can_frame *cf)
+{
+ int ret = write(ctx->s, cf, sizeof(*cf));
+ if (ret != sizeof(*cf)) {
+ perror("write");
+ exit(1);
+ }
+ return 0;
+}
+
+void init_write(struct out_ctx *ctx)
+{
+ int s;
+ struct sockaddr_can addr;
+ struct ifreq ifr;
+
+ s = CHECK(socket(PF_CAN, SOCK_RAW, CAN_RAW));
+
+ strcpy(ifr.ifr_name, devout);
+ if (-1 == ioctl(s, SIOCGIFINDEX, &ifr)) {
+ perror(devout);
+ exit(1);
+ }
+
+ addr.can_family = AF_CAN;
+ addr.can_ifindex = ifr.ifr_ifindex;
+
+ CHECK(bind(s, (struct sockaddr *)&addr, sizeof(addr)));
+
+ ctx->s = s;
+ ctx->out_fn = out_write;
+}
+
+void init_in(struct in_ctx *in)
+{
+ switch (in_method) {
+ case READ: init_read(in); break;
+ default:
+ fprintf(stderr, "Unknown \"in method\" %d\n", in_method);
+ exit(1);
+ }
+}
+
+int in(struct in_ctx *ctx, struct can_frame *cf)
+{
+ return ctx->in_fn(ctx, cf);
+}
+
+void init_out(struct out_ctx *out)
+{
+ switch (out_method) {
+ case WRITE: init_write(out); break;
+ default:
+ fprintf(stderr, "Unknown \"out method\" %d\n", out_method);
+ exit(1);
+ }
+}
+
+int out(struct out_ctx *ctx, struct can_frame *cf)
+{
+ return ctx->out_fn(ctx, cf);
+}
+
+void gw()
+{
+ struct in_ctx ic;
+ struct out_ctx oc;
+ struct can_frame cf;
+
+ init_in(&ic);
+ init_out(&oc);
+
+ VERBOSE("UGW started");
+
+ while (1) {
+ in(&ic, &cf);
+ oc.from_in = ic.for_out;
+ out(&oc, &cf);
+ }
+}
+
+
+int main(int argc, char *argv[])
+{
+ int opt;
+
+ while ((opt = getopt(argc, argv, "q")) != -1) {
+ switch (opt) {
+ case 'q':
+ quiet = true;
+ break;
+ default: /* '?' */
+ fprintf(stderr, "Usage: %s [in_interface out_interface]\n",
+ argv[0]);
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ if (optind < argc)
+ devin = argv[optind];
+ if (optind+1 < argc)
+ devout = argv[optind+1];
+
+ gw();
+
+ return 0;
+}