rcv handler
[ana-net.git] / usr / vlink.c
blob83a3e7ff286abd6c84b99c69c01ca1aafeb044a3
1 /*
2 * Lightweight Autonomic Network Architecture
4 * General purpose vlink layer userspace tool for binding low-level
5 * transport layers to LANA, i.e. Ethernet, ATM, Bluetooth, Serial
6 * Link, Inifiband and so on.
8 * strlcpy taken from the Linux kernel.
9 * Copyright 1991, 1992 Linus Torvalds <torvalds@linux-foundation.org>
11 * Copyright 2011 Daniel Borkmann <dborkma@tik.ee.ethz.ch>,
12 * Swiss federal institute of technology (ETH Zurich)
13 * Subject to the GPL.
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <stdint.h>
19 #include <string.h>
20 #include <unistd.h>
21 #include <stdarg.h>
22 #include <sys/socket.h>
23 #include <sys/types.h>
24 #include <linux/netlink.h>
25 #include <linux/if.h>
27 #include "xt_vlink.h"
29 #ifndef likely
30 # define likely(x) __builtin_expect(!!(x), 1)
31 #endif
32 #ifndef unlikely
33 # define unlikely(x) __builtin_expect(!!(x), 0)
34 #endif
35 #ifndef bug
36 # define bug() __builtin_trap()
37 #endif
39 #define PROGNAME "vlink"
40 #define VERSNAME "0.9"
42 size_t strlcpy(char *dest, const char *src, size_t size)
44 size_t ret = strlen(src);
46 if (size) {
47 size_t len = (ret >= size) ? size - 1 : ret;
48 memcpy(dest, src, len);
49 dest[len] = '\0';
52 return ret;
55 static inline void die(void)
57 exit(EXIT_FAILURE);
60 static inline void panic(char *msg, ...)
62 va_list vl;
63 va_start(vl, msg);
64 vfprintf(stderr, msg, vl);
65 va_end(vl);
67 die();
70 static inline void whine(char *msg, ...)
72 va_list vl;
73 va_start(vl, msg);
74 vfprintf(stderr, msg, vl);
75 va_end(vl);
78 static void *xzmalloc(size_t size)
80 void *ptr;
82 if (unlikely(size == 0))
83 panic("xzmalloc: zero size\n");
85 ptr = malloc(size);
86 if (unlikely(ptr == NULL))
87 panic("xzmalloc: out of memory (allocating %lu bytes)\n",
88 (u_long) size);
89 memset(ptr, 0, size);
91 return ptr;
94 static void xfree(void *ptr)
96 if (unlikely(ptr == NULL))
97 panic("xfree: NULL pointer given as argument\n");
98 free(ptr);
101 void check_for_root_maybe_die(void)
103 if (geteuid() != 0 || geteuid() != getuid())
104 panic("Uhhuh, not root?! \n");
107 static void usage(void)
109 printf("\n%s %s\n", PROGNAME, VERSNAME);
110 printf("Usage: %s <linktype> <cmd> [<args> ...]\n", PROGNAME);
111 printf("Linktypes:\n");
112 printf(" ethernet\n");
113 printf("Commands:\n");
114 printf(" add <name> <rootdev> <port>\n");
115 printf(" rm <name>\n");
116 printf(" hook <rootdev>\n");
117 printf(" unhook <rootdev>\n");
118 printf("\n");
119 printf("Please report bugs to <dborkma@tik.ee.ethz.ch>\n");
120 printf("Copyright (C) 2011 Daniel Borkmann\n");
121 printf("License: GNU GPL version 2\n");
122 printf("This is free software: you are free to change and redistribute it.\n");
123 printf("There is NO WARRANTY, to the extent permitted by law.\n\n");
125 die();
128 static void version(void)
130 printf("\n%s %s\n", PROGNAME, VERSNAME);
131 printf("Please report bugs to <dborkma@tik.ee.ethz.ch>\n");
132 printf("Copyright (C) 2011 Daniel Borkmann\n");
133 printf("License: GNU GPL version 2\n");
134 printf("This is free software: you are free to change and redistribute it.\n");
135 printf("There is NO WARRANTY, to the extent permitted by law.\n\n");
137 die();
140 void do_ethernet(int argc, char **argv)
142 int sock, ret;
143 uint8_t cmd = 0;
144 struct sockaddr_nl src_addr, dest_addr;
145 struct nlmsghdr *nlh;
146 struct iovec iov;
147 struct msghdr msg;
148 struct vlinknlmsg *vmsg;
150 if (unlikely(argc == 0))
151 usage();
152 if (!strncmp("add", argv[0], strlen("add")) && argc == 4)
153 cmd = VLINKNLCMD_ADD_DEVICE;
154 else if (!strncmp("rm", argv[0], strlen("rm")) && argc == 2)
155 cmd = VLINKNLCMD_RM_DEVICE;
156 else if (!strncmp("hook", argv[0], strlen("hook")) && argc == 2)
157 cmd = VLINKNLCMD_START_HOOK_DEVICE;
158 else if (!strncmp("unhook", argv[0], strlen("unhook")) && argc == 2)
159 cmd = VLINKNLCMD_STOP_HOOK_DEVICE;
160 else
161 usage();
163 sock = socket(PF_NETLINK, SOCK_RAW, NETLINK_VLINK);
164 if (unlikely(sock < 0))
165 panic("Cannot get NETLINK_VLINK socket from kernel! "
166 "Modules not loaded?!\n");
168 memset(&src_addr, 0, sizeof(src_addr));
169 src_addr.nl_family = AF_NETLINK;
170 src_addr.nl_pad = 0;
171 src_addr.nl_pid = getpid();
172 src_addr.nl_groups = 0;
174 ret = bind(sock, (struct sockaddr *) &src_addr, sizeof(src_addr));
175 if (unlikely(ret))
176 panic("Cannot bind socket!\n");
178 memset(&dest_addr, 0, sizeof(dest_addr));
179 dest_addr.nl_family = AF_NETLINK;
180 dest_addr.nl_pad = 0;
181 dest_addr.nl_pid = 0;
182 dest_addr.nl_groups = 0;
184 nlh = xzmalloc(NLMSG_SPACE(sizeof(*vmsg)));
185 nlh->nlmsg_len = NLMSG_SPACE(sizeof(*vmsg));
186 nlh->nlmsg_pid = getpid();
187 nlh->nlmsg_type = VLINKNLGRP_ETHERNET;
188 nlh->nlmsg_flags = NLM_F_REQUEST;
190 vmsg = (struct vlinknlmsg *) NLMSG_DATA(nlh);
191 vmsg->cmd = cmd;
192 if (cmd == VLINKNLCMD_ADD_DEVICE)
193 vmsg->port = (uint16_t) (0xFFFF & atoi(argv[3]));
194 vmsg->flags = 0;
195 strlcpy((char *) vmsg->virt_name, argv[1], sizeof(vmsg->virt_name));
196 if (cmd == VLINKNLCMD_ADD_DEVICE)
197 strlcpy((char *) vmsg->real_name, argv[2],
198 sizeof(vmsg->real_name));
199 else if (cmd == VLINKNLCMD_START_HOOK_DEVICE ||
200 cmd == VLINKNLCMD_STOP_HOOK_DEVICE)
201 strlcpy((char *) vmsg->real_name, argv[1],
202 sizeof(vmsg->real_name));
204 iov.iov_base = nlh;
205 iov.iov_len = nlh->nlmsg_len;
207 memset(&msg, 0, sizeof(msg));
208 msg.msg_name = &dest_addr;
209 msg.msg_namelen = sizeof(dest_addr);
210 msg.msg_iov = &iov;
211 msg.msg_iovlen = 1;
213 ret = sendmsg(sock, &msg, 0);
214 if (unlikely(ret < 0))
215 panic("Cannot send NETLINK message to the kernel!\n");
217 close(sock);
218 xfree(nlh);
221 int main(int argc, char **argv)
223 check_for_root_maybe_die();
225 if (argc <= 1)
226 usage();
227 argc--; argv++;
228 if (!strncmp("help", argv[0], strlen("help")))
229 usage();
230 else if (!strncmp("version", argv[0], strlen("version")))
231 version();
232 else if (!strncmp("ethernet", argv[0], strlen("ethernet")))
233 do_ethernet(--argc, ++argv);
234 else
235 usage();
237 return 0;