can-eth-gw-utils Utilities  0.1
A bidirectional CAN to Ethernet Gateway (Utilities)
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
netlink.c
Go to the documentation of this file.
1 
9 /*****************************************************************************
10  * (C) Copyright 2013 Fabian Raab, Stefan Smarzly
11  *
12  * This file is part of CAN-Eth-GW.
13  *
14  * CAN-Eth-GW is free software: you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License as published by
16  * the Free Software Foundation, either version 3 of the License, or
17  * (at your option) any later version.
18  *
19  * CAN-Eth-GW is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with CAN-Eth-GW. If not, see <http://www.gnu.org/licenses/>.
26  *****************************************************************************/
27 
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <errno.h>
32 #include <stdint.h>
33 
34 #include <netlink/netlink.h>
35 #include <netlink/cache.h>
36 #include <netlink/attr.h>
37 #include <netlink/addr.h>
38 #include <netlink/msg.h>
39 #include <netlink/errno.h>
40 
41 #include <netlink/genl/ctrl.h>
42 #include <netlink/genl/family.h>
43 #include <netlink/genl/genl.h>
44 #include <netlink/genl/mngt.h>
45 #include "netlink.h"
46 
50 #define GE_FAMILY_NAME "CE_GW"
51 #define GE_FAMILY_VERSION 1
52 #define USER_HDR_SIZE 0
53 #define NO_FLAG 0
54 #define IFACE_VERSION 0
55 
61 enum {
72 };
73 #define CE_GW_A_MAX (__CE_GW_A_MAX - 1)
78 static struct nla_policy ce_gw_genl_policy[CE_GW_A_MAX + 1] = {
79  [CE_GW_A_DATA] = { .type = NLA_STRING },
80  [CE_GW_A_SRC] = { .type = NLA_STRING },
81  [CE_GW_A_DST] = { .type = NLA_STRING },
82  [CE_GW_A_ID] = { .type = NLA_U32 },
83  [CE_GW_A_FLAGS] = { .type = NLA_U32 },
84  [CE_GW_A_TYPE] = { .type = NLA_U8 },
85  [CE_GW_A_HNDL] = { .type = NLA_U32 },
86  [CE_GW_A_DROP] = { .type = NLA_U32 },
87 };
88 
89 struct genl_family *genl_fam;
90 struct nl_sock *nl_sk;
96 const struct flags {
97  char *name;
98 } flags_array[] = {
99  { "CAN-FD" },
100  { 0 }
101 };
102 
117 char *flags2str(uint32_t bits, const struct flags *flags, size_t size)
118 {
119  char *str = malloc(size);
120  str[0] = '<';
121  str[1] = '\0';
122 
123  /* Iterate until the end of bits or thh end of flags array */
124  for (int i = 0; i < sizeof(uint32_t) * 8 && flags[i].name != 0; ++i) {
125  // extract the i-th bit
126  int b = ((bits >> i) & 1);
127  // b will be 1 if i-th bit is set, 0 otherwise
128 
129  if (b == 1) {
130  strcat(str, flags[i].name);
131  strcat(str, ",");
132  }
133  }
134  int len = strlen(str);
135 
136  if (len <= 1) {
137  strcat(str, ">");
138  } else {
139  str[len-1] = '>'; /* replace ',' with '>' */
140  }
141 
142  return str;
143 }
144 
149 const struct enums {
150  char *name;
151 } type_array[] = {
152  { "NONE" },
153  { "ETH" },
154  { "NET" },
155  { "TCP" },
156  { "UDP" },
157  { 0 }
158 };
159 
173 char *enum2str(int value, const struct enums *enums, size_t size, int max)
174 {
175  char *str = malloc(size+1); /* +1 for \0 */
176  str[0] = '\0';
177 
178  /* Iterate until the end of value or the end of enums array */
179  for (int i = 0; i <= max && enums[i].name != 0; ++i) {
180  if (i == value) {
181  strcat(str, enums[i].name);
182  return str;
183  }
184  }
185 
186  free(str);
187  return NULL;
188 }
189 
190 
203 int nl_cb_general_errno(struct sockaddr_nl *nla,
204  struct nlmsgerr *nlerr, void *arg)
205 {
206  int err = nlerr->error;
207  fprintf(stderr, "NETLINK returned Error: %s\n", strerror(err));
208 
209  return NL_STOP;
210 }
211 
212 int ce_gw_add(char *dst_name, char *src_name, uint8_t type, uint32_t flags)
213 {
214  int err = 0;
215  struct nl_msg *msg;
216 
217  /* create */
218  msg = nlmsg_alloc();
219  if(msg == NULL) {
220  fprintf(stderr,"add: Message allocation failed.\n");
221  return -ENOMEM;
222  }
223 
224  void *user_hdr;
225  user_hdr = genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ,
226  genl_family_get_id(genl_fam), USER_HDR_SIZE,
228  if (user_hdr == NULL)
229  fprintf(stderr, "add: Message Haeder creation failed\n");
230 
231  if (src_name != NULL) { /* indicates that it is add route command */
232  NLA_PUT_STRING(msg, CE_GW_A_SRC, src_name);
233  } /* else it is add dev command */
234 
235  /* Attributes needed by both, add route and add dev */
236  NLA_PUT_STRING(msg, CE_GW_A_DST, dst_name);
237  NLA_PUT_U8(msg, CE_GW_A_TYPE, type);
238  NLA_PUT_U32(msg, CE_GW_A_FLAGS, flags);
239 
240  /* vaildate */
241  struct nlmsghdr *msghdr = nlmsg_hdr(msg);
242  err = genlmsg_validate(msghdr, USER_HDR_SIZE,
244  if (err != 0) {
245  fprintf(stderr, "add: Validation of Message Failed: %i\n", err);
246  return -1;
247  }
248 
249  /* send */
250  nl_send_auto(nl_sk, msg);
251 
252  err = nl_wait_for_ack(nl_sk);
253  if (err != 0) {
254  fprintf(stderr,
255  "add: ACK is missing or Error returned. "
256  "Operation might fail: %i\n", err);
257  }
258 
259  nlmsg_free(msg);
260 
261  return 0;
262 
263 nla_put_failure:
264  fprintf(stderr, "Attribute Modification failed: %d\n",-EMSGSIZE);
265  nlmsg_free(msg);
266  return -EMSGSIZE;
267 }
268 
269 int ce_gw_del(uint32_t id, char *dev_name)
270 {
271  int err;
272  struct nl_msg *msg;
273  if (id != 0 && dev_name != NULL) {
274  err = -EINVAL;
275  return err;
276  }
277 
278  /* create */
279  msg = nlmsg_alloc();
280  if(msg == NULL) {
281  fprintf(stderr,"del: Message allocation failed.\n");
282  return -1;
283  }
284 
285  void *user_hdr;
286  user_hdr = genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ,
287  genl_family_get_id(genl_fam), USER_HDR_SIZE,
289  if (user_hdr == NULL)
290  fprintf(stderr, "del: Message Haeder creation failed\n");
291 
292  NLA_PUT_U32(msg, CE_GW_A_ID, id);
293  if (dev_name != NULL) { /* del dev is called */
294  NLA_PUT_STRING(msg, CE_GW_A_DST, dev_name);
295  }
296 
297  /* vaildate */
298  struct nlmsghdr *msghdr = nlmsg_hdr(msg);
299  err = genlmsg_validate(msghdr, USER_HDR_SIZE,
301  if (err != 0) {
302  fprintf(stderr, "del: Validation of Message Failed: %i\n", err);
303  return -1;
304  }
305 
306  /* send */
307  nl_send_auto(nl_sk, msg);
308 
309  err = nl_wait_for_ack(nl_sk);
310  if (err != 0) {
311  fprintf(stderr,
312  "add: ACK is missing or Error returned. "
313  "Operation might fail: %i\n", err);
314  }
315 
316  nlmsg_free(msg);
317  return 0;
318 
319 nla_put_failure:
320  fprintf(stderr, "Attribute Modification failed: %d\n",-EMSGSIZE);
321  nlmsg_free(msg);
322  return -EMSGSIZE;
323 }
324 
335 int nl_cb_list_entry(struct nl_msg *msg, void *arg)
336 {
337  int err;
338 
339  struct nlmsghdr *msghdr = nlmsg_hdr(msg);
340 
341  struct nlattr *attrs[CE_GW_A_MAX+1];
342  err = genlmsg_parse(msghdr, USER_HDR_SIZE, attrs,
344  if (err < 0)
345  fprintf(stderr, "ERROR Kernel Message Parsing Failed\n");
346 
347  char *a_msg_src_data = (char *)nla_data(attrs[CE_GW_A_SRC]);
348  char *a_msg_dst_data = (char *)nla_data(attrs[CE_GW_A_DST]);
349  uint32_t *a_msg_id_data = (uint32_t *)nla_data(attrs[CE_GW_A_ID]);
350  uint32_t *a_msg_flags_data = (uint32_t *)nla_data(attrs[CE_GW_A_FLAGS]);
351  uint8_t *a_msg_type_data = (uint8_t *)nla_data(attrs[CE_GW_A_TYPE]);
352  uint32_t *a_msg_hndl_data = (uint32_t *)nla_data(attrs[CE_GW_A_HNDL]);
353  uint32_t *a_msg_drop_data = (uint32_t *)nla_data(attrs[CE_GW_A_DROP]);
354 
355  char *type_str;
356  type_str = enum2str(*a_msg_type_data, type_array, 6, TYPE_MAX);
357  char *flags_str;
358  /* 256 should be big enough */
359  flags_str = flags2str(*a_msg_flags_data, flags_array, 256);
360 
361  printf(" %-8d %-6s %-6s %-6s %-8d %-8d %s\n", *a_msg_id_data,
362  a_msg_src_data, a_msg_dst_data, type_str, *a_msg_hndl_data,
363  *a_msg_drop_data, flags_str);
364 
365  free(type_str);
366  free(flags_str);
367  return NL_OK;
368 }
369 
379 int nl_cb_list_finish(struct nl_msg *msg, void *arg)
380 {
381  return NL_STOP;
382 }
383 
384 int ce_gw_list(uint32_t id)
385 {
386  int err;
387  struct nl_msg *msg;
388 
389  /* create */
390  msg = nlmsg_alloc();
391  if(msg == NULL) {
392  fprintf(stderr,"echo: Message allocation failed.\n");
393  return -1;
394  }
395 
396  void *user_hdr;
397  user_hdr = genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ,
398  genl_family_get_id(genl_fam), USER_HDR_SIZE,
400  if (user_hdr == NULL)
401  fprintf(stderr, "echo: Message Haeder creation failed.\n");
402 
403  NLA_PUT_U32(msg, CE_GW_A_ID, id);
404 
405  /* vaildate */
406  struct nlmsghdr *msghdr = nlmsg_hdr(msg);
407  err = genlmsg_validate(msghdr, 0, CE_GW_A_MAX, ce_gw_genl_policy);
408  if (err != 0) {
409  fprintf(stderr, "echo: Validation of Message Failed: %i\n",
410  err);
411  return -1;
412  }
413 
414  /* send */
415  nl_socket_disable_auto_ack(nl_sk);
416  nl_send_auto(nl_sk, msg);
417 
418  /* create callback system */
419  struct nl_cb *cb = nl_cb_alloc(NL_CB_DEFAULT);
420  nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, nl_cb_list_entry, NULL);
421  nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, nl_cb_list_finish, NULL);
422  nl_cb_err(cb, NL_CB_CUSTOM, nl_cb_general_errno, NULL);
423 
424  printf(" ID SRC DST TYPE HANDLED DROPPED FLAGS\n");
425 
426  nl_recvmsgs(nl_sk, cb);
427 
428  nl_cb_put(cb);
429  nlmsg_free(msg);
430 
431  return 0;
432 
433 nla_put_failure:
434  fprintf(stderr, "Attribute Modification failed: %d\n",-EMSGSIZE);
435  nlmsg_free(msg);
436  return -1;
437 }
438 
448 int nl_cb_echo_answer(struct nl_msg *msg, void *arg)
449 {
450  struct nlmsghdr *msghdr = nlmsg_hdr(msg);
451  struct genlmsghdr *gemsghdr = nlmsg_data(msghdr);
452 
453  struct nlattr *a_msg = genlmsg_attrdata(gemsghdr, 0);
454  char * a_msg_data = (char *) nla_data(a_msg);
455  printf("kernel says: %s\n", a_msg_data);
456 
457  return NL_OK;
458 }
459 
460 int ce_gw_echo(char *message)
461 {
462  int rc; /* return codes */
463  struct nl_msg *msg;
464 
465  /* create */
466  msg = nlmsg_alloc();
467  if(msg == NULL) {
468  fprintf(stderr,"echo: Message allocation failed.\n");
469  return -1;
470  }
471 
472  void *user_hdr;
473  user_hdr = genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ,
474  genl_family_get_id(genl_fam), USER_HDR_SIZE,
476  if (user_hdr == NULL)
477  fprintf(stderr, "echo: Message Haeder creation failed.\n");
478 
479  NLA_PUT_STRING(msg, CE_GW_A_DATA, message);
480 
481  /* vaildate */
482  struct nlmsghdr *msghdr = nlmsg_hdr(msg);
483  if ((rc = genlmsg_validate(msghdr,0,CE_GW_A_MAX, ce_gw_genl_policy)) != 0) {
484  fprintf(stderr, "echo: Validation of Message Failed: %i\n", rc);
485  return -1;
486  }
487 
488  /* send */
489  nl_socket_disable_auto_ack(nl_sk);
490  nl_send_auto(nl_sk, msg);
491 
492  /* create callback system */
493  struct nl_cb *cb = nl_cb_alloc(NL_CB_DEBUG);
494  nl_cb_set(cb, NL_CB_MSG_IN, NL_CB_CUSTOM , nl_cb_echo_answer, NULL);
495  nl_recvmsgs(nl_sk, cb);
496  nl_cb_put(cb);
497 
498 
499  nlmsg_free(msg);
500 
501  return 0;
502 
503 nla_put_failure:
504  fprintf(stderr, "Attribute Modification failed: %d\n",-EMSGSIZE);
505  nlmsg_free(msg);
506  return -1;
507 }
508 
509 
510 int nl_sk_fam_init(void)
511 {
512  int err;
513 
514  /* create gneric netlink socket */
515  nl_sk = nl_socket_alloc();
516  if ( nl_sk == NULL ) {
517  fprintf (stderr, "Socket allocation failed.\n");
518  return -1;
519  }
520 
521  err = genl_connect(nl_sk);
522  if (err != 0) {
523  fprintf (stderr, "Connetion to socket failed: %d\n", err);
524  return err;
525  }
526 
527  err = nl_socket_modify_err_cb(nl_sk, NL_CB_CUSTOM,
528  nl_cb_general_errno, NULL);
529  if (err != 0) {
530  fprintf (stderr, "Error Callback modification failed: %d\n",
531  err);
532  }
533 
534  /* create generic netlink family */
535  genl_fam = genl_family_alloc();
536  if (genl_fam == NULL) {
537  fprintf (stderr, "Family allocation failed.\n");
538  return -1;
539  }
540 
541  genl_family_set_name(genl_fam, GE_FAMILY_NAME);
542  genl_family_set_version(genl_fam, GE_FAMILY_VERSION);
543  genl_family_set_maxattr(genl_fam, CE_GW_A_MAX);
544  genl_family_set_hdrsize(genl_fam, USER_HDR_SIZE);
545 
546  genl_family_set_id(genl_fam,
547  (err = genl_ctrl_resolve(nl_sk, GE_FAMILY_NAME)));
548  if (err < 0) {
549  fprintf(stderr,
550  "Could not resolve Netlink Family ID from kernel. "
551  "Is the module loaded?: %d\n", err);
552  return err;
553  }
554 
555  return 0;
556 }
557 
558 
559 void nl_sk_fam_exit(void)
560 {
561  nl_close(nl_sk);
562  genl_family_put(genl_fam);
563  nl_socket_free(nl_sk);
564 }