can_eth_gw Gateway Module  0.1
A bidirectional CAN to Ethernet Gateway (Kernel Module)
 All Data Structures Files Functions Variables Enumerations Enumerator Macros Groups Pages
ce_gw_netlink.c
Go to the documentation of this file.
1 
11 /*****************************************************************************
12  * (C) Copyright 2013 Fabian Raab, Stefan Smarzly
13  *
14  * This file is part of CAN-Eth-GW.
15  *
16  * CAN-Eth-GW is free software: you can redistribute it and/or modify
17  * it under the terms of the GNU General Public License as published by
18  * the Free Software Foundation, either version 3 of the License, or
19  * (at your option) any later version.
20  *
21  * CAN-Eth-GW is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24  * GNU General Public License for more details.
25  *
26  * You should have received a copy of the GNU General Public License
27  * along with CAN-Eth-GW. If not, see <http://www.gnu.org/licenses/>.
28  *****************************************************************************/
29 
30 #include <linux/version.h>
31 #include <net/genetlink.h>
32 #include <net/netlink.h>
33 #include <linux/module.h>
34 #include <linux/kernel.h>
35 #include <linux/types.h>
36 #include <linux/netlink.h>
37 #include "ce_gw_main.h"
38 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0)
39 #include <uapi/linux/netlink.h>
40 #endif
41 #include <asm-generic/errno-base.h>
42 #include <asm-generic/errno.h>
43 
47 #define CE_GW_GE_FAMILY_NAME "CE_GW"
48 #define CE_GW_GE_FAMILY_VERSION 2
49 #define CE_GW_USER_HDR_SIZE 0
50 #define CE_GW_NO_FLAG 0
51 
58 enum {
69 };
70 #define CE_GW_A_MAX (__CE_GW_A_MAX - 1)
76 static struct nla_policy ce_gw_genl_policy[CE_GW_A_MAX + 1] = {
77  [CE_GW_A_DATA] = { .type = NLA_NUL_STRING },
78  [CE_GW_A_SRC] = { .type = NLA_NUL_STRING },
79  [CE_GW_A_DST] = { .type = NLA_NUL_STRING },
80  [CE_GW_A_ID] = { .type = NLA_U32 },
81  [CE_GW_A_FLAGS] = { .type = NLA_U32 },
82  [CE_GW_A_TYPE] = { .type = NLA_U8 },
83  [CE_GW_A_HNDL] = { .type = NLA_U32 },
84  [CE_GW_A_DROP] = { .type = NLA_U32 },
85 };
86 
91 static struct genl_family ce_gw_genl_family = {
93  .id = GENL_ID_GENERATE,
94  .hdrsize = CE_GW_USER_HDR_SIZE,
95  .name = CE_GW_GE_FAMILY_NAME,
96  .version = CE_GW_GE_FAMILY_VERSION,
97  .maxattr = CE_GW_A_MAX,
98  .netnsok = false,
99  .pre_doit = NULL,
100  .post_doit = NULL,
102 };
103 
109 enum {
116 };
117 #define CE_GW_C_MAX (__CE_GW_C_MAX - 1)
127 int ce_gw_netlink_echo(struct sk_buff *skb_info, struct genl_info *info)
128 {
129  struct sk_buff *skb;
130  int err;
131  void *user_hdr;
132 
133  if (info == NULL) {
134  printk(KERN_ERR "ce_gw: info attribute is missing."\
135  " No Massage received.\n");
136  return -1;
137  }
138 
139  struct nlattr *nla_a_msg = info->attrs[CE_GW_A_DATA];
140  char *nla_a_msg_pay = (char *) nla_data(nla_a_msg);
141 
142  if (nla_a_msg_pay == NULL) {
143  pr_warning("ce_gw: String Message is missing.\n");
144  } else {
145  pr_info("ce_gw: Messege received: %s\n", nla_a_msg_pay);
146  }
147 
148  /* send a message back*/
149  skb = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
150  if (skb == NULL) {
151  err = -ENOMEM;
152  pr_err("ce_gw: Socket allocation failed.\n");
153  goto ce_gw_add_error;
154  }
155 
156 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0)
157  user_hdr = genlmsg_put(skb, info->snd_pid, info->snd_seq,
159 #else
160  user_hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq,
162 #endif
163 
164  if (user_hdr == NULL) {
165  err = -ENOMEM;
166  pr_err("ce_gw: Error during putting haeder\n");
167  goto ce_gw_add_error;
168  }
169 
170  err = nla_put_string(skb, CE_GW_A_DATA,
171  "hello world from kernel space \n");
172  if (err != 0) {
173  pr_err("ce_gw: Putting Netlink Attribute Failed.\n");
174  goto ce_gw_add_error;
175  }
176 
177  genlmsg_end(skb, user_hdr);
178 
179 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0)
180  err = genlmsg_unicast(genl_info_net(info),skb,info->snd_pid);
181 #else
182  err = genlmsg_unicast(genl_info_net(info),skb,info->snd_portid);
183 #endif
184  if (err != 0) {
185  pr_err("ce_gw: Message sending failed.\n");
186  goto ce_gw_add_error;
187  }
188 
189  return 0;
190 
191 ce_gw_add_error:
192  kfree_skb(skb);
193  return err;
194 };
195 
216 int ce_gw_netlink_add(struct sk_buff *skb_info, struct genl_info *info)
217 {
218  int err = 0;
219  if (info == NULL) {
220  err = -EINVAL;
221  pr_err("ce_gw: info attribute is missing."\
222  " No Massage received.\n");
223  return err;
224  }
225 
226  struct nlattr *nla_src = info->attrs[CE_GW_A_SRC];
227  char *nla_src_data = (char *) nla_data(nla_src);
228 
229  struct nlattr *nla_dst = info->attrs[CE_GW_A_DST];
230  char *nla_dst_data = (char *) nla_data(nla_dst);
231 
232  struct nlattr *nla_flags = info->attrs[CE_GW_A_FLAGS];
233  u32 *nla_flags_data = (u32 *) nla_data(nla_flags);
234 
235  struct nlattr *nla_type = info->attrs[CE_GW_A_TYPE];
236  u8 *nla_type_data = (u8 *) nla_data(nla_type);
237 
238  if (nla_src == NULL) { /* add dev is called in userspace */
239  pr_info("ce_gw: add dev is called\n");
240  struct net_device *dev;
241 
242  if (nla_dst == NULL ||
243  nla_type == NULL || nla_flags == NULL) {
244  pr_err("ce_gw: DST or TYPE is missing.\n");
245  err = -ENODATA;
246  goto ce_gw_add_error;
247  }
248 
249  dev = ce_gw_dev_create(*nla_type_data, *nla_flags_data,
250  nla_dst_data);
251  if (dev == NULL) {
252  pr_err("ce_gw_netlink: Device allocation failed.");
253  err = -ENOMEM;
254  goto ce_gw_add_error;
255  }
256 
257  err = ce_gw_dev_register(dev);
258  if (err != 0) {
259  pr_err("ce_gw_netlink: Device registration failed.");
260  ce_gw_dev_free(dev);
261  goto ce_gw_add_error;
262  }
263 
264  } else { /* add route is called in userspace*/
265  if (nla_src == NULL || nla_dst == NULL ||
266  nla_type == NULL || nla_flags == NULL) {
267  pr_err("ce_gw: SRC or DST or TYPE is missing.\n");
268  err = -ENODATA;
269  goto ce_gw_add_error;
270  }
271 
272  pr_info("ce_gw: Add : from %s to %s"
273  "(Type %d; Flags %d)\n", nla_src_data,
274  nla_dst_data, *nla_type_data, *nla_flags_data);
275 
276  /* get device index by their names */
277  struct net_device *src_dev;
278  src_dev = dev_get_by_name(&init_net, nla_src_data);
279  if (src_dev == NULL) {
280  err = -ENODEV;
281  pr_err("ce_gw_netlink: src dev not found: %d\n", err);
282  goto ce_gw_add_error;
283  }
284  int src_dev_ifindex = src_dev->ifindex;
285  dev_put(src_dev);
286 
287  struct net_device *dst_dev;
288  dst_dev = dev_get_by_name(&init_net, nla_dst_data);
289  if (dst_dev == NULL) {
290  err = -ENODEV;
291  pr_err("ce_gw_netlink: dst dev not found: %d\n", err);
292  goto ce_gw_add_error;
293  }
294  int dst_dev_ifindex = dst_dev->ifindex;
295  dev_put(dst_dev);
296 
297  err = ce_gw_create_route(src_dev_ifindex, dst_dev_ifindex,
298  *nla_type_data, *nla_flags_data);
299  if (err != 0) {
300  goto ce_gw_add_error;
301  }
302  }
303 
304 ce_gw_add_error:
305  /* TODO if you send two add messages A abd B in in very short
306  * short distance (e.g. with option -b in userspace) than the
307  * ACK Sequence number of Message B is the same of the Massage
308  * A. So the ACK for Message B could not correct assign to
309  * Message B in userspace and the userpace think there is an
310  * error, but all is correct. This seems to be a bug in this
311  * function of netlink */
312  netlink_ack(skb_info, info->nlhdr, -err);
313  return err;
314 }
315 
333 int ce_gw_netlink_del(struct sk_buff *skb_info, struct genl_info *info)
334 {
335  int err = 0;
336  if (info == NULL) {
337  err = -ENODATA;
338  pr_err("ce_gw: info attribute is missing."\
339  " No Massage received: %d\n", err);
340  return err;
341  }
342 
343  struct nlattr *nla_id = info->attrs[CE_GW_A_ID];
344  __u32 *nla_id_data = (__u32 *) nla_data(nla_id);
345 
346  /* DST Contains the device name to delete */
347  struct nlattr *nla_dst = info->attrs[CE_GW_A_DST];
348  char *nla_dst_data = (char *) nla_data(nla_dst);
349 
350  if (nla_dst == NULL) { /* del route is called in userspace */
351  if (*nla_id_data == 0) {
352  err = -ENODATA;
353  pr_warning("ce_gw: ID is missing: %d\n", err);
354  goto ce_gw_del_error;
355  } else
356  pr_debug("ce_gw: del device: %d\n", *nla_id_data);
357 
358  err = ce_gw_remove_route(*nla_id_data);
359 
360  } else { /* del dev is called in userspace */
361 
362  struct net_device *dev;
363  dev = dev_get_by_name(&init_net, nla_dst_data);
364  if (dev == NULL) {
365  err = -ENODEV;
366  pr_err("ce_gw_netlink: No such Device: %d\n", err);
367  goto ce_gw_del_error;
368  }
369  dev_put(dev);
370 
372  ce_gw_dev_free(dev);
373  }
374 
375 ce_gw_del_error:
376  netlink_ack(skb_info, info->nlhdr, -err);
377  return err;
378 }
379 
401 int ce_gw_netlink_list(struct sk_buff *skb_info, struct genl_info *info)
402 {
403  struct sk_buff *skb;
404  int err = 0;
405  void *user_hdr;
406 
407  pr_debug("ce_gw_netlink: ce_gw_netlink_list is called.\n");
408 
409  struct nlattr *nla_id = info->attrs[CE_GW_A_ID];
410  __u32 *nla_id_data = (__u32 *) nla_data(nla_id);
411 
412  /* TODO perhaps pare arguments like ID to only transmit a special GW */
413  struct ce_gw_job *cgj;
414  struct hlist_node *node;
415 
416 # if LINUX_VERSION_CODE >= KERNEL_VERSION(3,9,0)
417  hlist_for_each_entry_safe(cgj, node, ce_gw_get_job_list(), list) {
418 # else
419 
420  struct hlist_node *pos;
421  hlist_for_each_entry_safe(cgj, pos, node, ce_gw_get_job_list(), list) {
422 # endif
423  if (*nla_id_data != 0 && cgj->id != *nla_id_data) {
424  continue;
425  }
426 
427  pr_debug("ce_gw_netlink: Job List entry is send.\n");
428 
429  skb = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
430  if (skb == NULL) {
431  pr_err("ce_gw: Socket allocation failed.\n");
432  goto ce_gw_list_error;
433  }
434 
435 # if LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0)
436  user_hdr = genlmsg_put(skb, info->snd_pid,
437  info->snd_seq, &ce_gw_genl_family,
438  NLM_F_MULTI, CE_GW_C_ECHO);
439 
440 # else
441  user_hdr = genlmsg_put(skb, info->snd_portid,
442  info->snd_seq, &ce_gw_genl_family,
443  NLM_F_MULTI, CE_GW_C_ECHO);
444 # endif
445  if (user_hdr == NULL) {
446  err = -ENOMEM;
447  pr_err("ce_gw: Error during putting haeder\n");
448  goto ce_gw_list_error;
449  }
450 
451  err = nla_put_string(skb, CE_GW_A_SRC, cgj->src.dev->name);
452  err += nla_put_string(skb, CE_GW_A_DST, cgj->dst.dev->name);
453  err += nla_put_u32(skb, CE_GW_A_ID, cgj->id);
454  err += nla_put_u32(skb, CE_GW_A_FLAGS, cgj->flags);
455  err += nla_put_u8(skb, CE_GW_A_TYPE, cgj->type);
456  err += nla_put_u32(skb, CE_GW_A_HNDL, cgj->handled_frames);
457  err += nla_put_u32(skb, CE_GW_A_DROP, cgj->dropped_frames);
458  if (err != 0) {
459  pr_err("ce_gw: Putting Netlink Attribute Failed.\n");
460  goto ce_gw_list_error;
461  }
462 
463  genlmsg_end(skb, user_hdr);
464 
465 # if LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0)
466  err = genlmsg_unicast(genl_info_net(info), skb,
467  info->snd_pid);
468 # else
469 
470  err = genlmsg_unicast(genl_info_net(info), skb,
471  info->snd_portid);
472 # endif
473  if (err != 0) {
474  pr_err("ce_gw: Message sending failed.\n");
475  goto ce_gw_list_error;
476  }
477  }
478 
479  /* send a DONE Message (of a Multimessage Series) back */
480  struct nlmsghdr *nlhdr;
481  skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
482 
483  if (skb == NULL) {
484  pr_err("ce_gw: Socket allocation failed.\n");
485  goto ce_gw_list_error;
486  }
487 
488 # if LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0)
489  nlhdr = nlmsg_put(skb, info->snd_pid, info->snd_seq,
490  NLMSG_DONE, 0, CE_GW_NO_FLAG);
491 # else
492 
493  nlhdr = nlmsg_put(skb, info->snd_portid, info->snd_seq,
494  NLMSG_DONE, 0, CE_GW_NO_FLAG);
495 # endif
496  if (nlhdr == NULL) {
497  err = -ENOMEM;
498  pr_err("ce_gw: Error during putting haeder\n");
499  goto ce_gw_list_error;
500  }
501 
502  nlmsg_end(skb, nlhdr);
503 
504 # if LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0)
505  err = nlmsg_unicast(genl_info_net(info)->genl_sock, skb,
506  info->snd_pid);
507 
508 # else
509  err = nlmsg_unicast(genl_info_net(info)->genl_sock, skb,
510  info->snd_portid);
511 # endif
512  if (err != 0) {
513  pr_err("ce_gw: Message sending failed.\n");
514  goto ce_gw_list_error;
515  }
516 
517  return 0;
518 
519 ce_gw_list_error:
520  kfree_skb(skb);
521  return err;
522 }
523 
528 struct genl_ops ce_gw_genl_ops_echo = {
529  .cmd = CE_GW_C_ECHO,
530  .internal_flags = CE_GW_NO_FLAG,
531  .flags = CE_GW_NO_FLAG,
532  .policy = ce_gw_genl_policy,
533  .doit = ce_gw_netlink_echo,
534  .dumpit = NULL,
535  .done = NULL,
536 };
537 
542 struct genl_ops ce_gw_genl_ops_add = {
543  .cmd = CE_GW_C_ADD,
544  .internal_flags = CE_GW_NO_FLAG,
545  .flags = CE_GW_NO_FLAG,
546  .policy = ce_gw_genl_policy,
547  .doit = ce_gw_netlink_add,
548  .dumpit = NULL,
549  .done = NULL,
550 };
551 
556 struct genl_ops ce_gw_genl_ops_del = {
557  .cmd = CE_GW_C_DEL,
558  .internal_flags = CE_GW_NO_FLAG,
559  .flags = CE_GW_NO_FLAG,
560  .policy = ce_gw_genl_policy,
561  .doit = ce_gw_netlink_del,
562  .dumpit = NULL,
563  .done = NULL,
564 };
565 
570 struct genl_ops ce_gw_genl_ops_list = {
571  .cmd = CE_GW_C_LIST,
572  .internal_flags = CE_GW_NO_FLAG,
573  .flags = CE_GW_NO_FLAG,
574  .policy = ce_gw_genl_policy,
575  .doit = ce_gw_netlink_list,
576  .dumpit = NULL,
577  .done = NULL,
578 };
579 
580 
582  int err;
583 
584  if ((err = genl_register_family(&ce_gw_genl_family)) != 0) {
585  pr_err("ce_gw: Error during registering family ce_gw: %i\n",
586  err);
587  goto ce_gw_init_family_err;
588  }
589 
590  err = genl_register_ops(&ce_gw_genl_family, &ce_gw_genl_ops_echo);
591  if (err != 0) {
592  pr_err("ce_gw: Error during registering operation echo: %i\n",
593  err);
594  goto ce_gw_init_echo_err;
595  }
596 
597  err = genl_register_ops(&ce_gw_genl_family, &ce_gw_genl_ops_del);
598  if (err != 0) {
599  pr_err("ce_gw: Error during registering operation del: %i\n",
600  err);
601  goto ce_gw_init_del_err;
602  }
603 
604  err = genl_register_ops(&ce_gw_genl_family, &ce_gw_genl_ops_add);
605  if (err != 0) {
606  pr_err("ce_gw: Error during registering operation add: %i\n",
607  err);
608  goto ce_gw_init_add_err;
609  }
610 
611  err = genl_register_ops(&ce_gw_genl_family, &ce_gw_genl_ops_list);
612  if (err != 0) {
613  pr_err("ce_gw: Error during registering operation list: %i\n",
614  err);
615  goto ce_gw_init_list_err;
616  }
617 
618  return 0;
619 
620 
621  err = genl_unregister_ops(&ce_gw_genl_family, &ce_gw_genl_ops_list);
622 
623 ce_gw_init_list_err:
624  err = genl_unregister_ops(&ce_gw_genl_family, &ce_gw_genl_ops_add);
625 
626 ce_gw_init_add_err:
627  err = genl_unregister_ops(&ce_gw_genl_family, &ce_gw_genl_ops_del);
628 
629 ce_gw_init_del_err:
630  err = genl_unregister_ops(&ce_gw_genl_family, &ce_gw_genl_ops_echo);
631 
632 ce_gw_init_echo_err:
633  err = genl_unregister_family(&ce_gw_genl_family);
634 
635 ce_gw_init_family_err:
636  return -1;
637 }
638 
639 
640 void ce_gw_netlink_exit(void) {
641  int err;
642  err = genl_unregister_ops(&ce_gw_genl_family, &ce_gw_genl_ops_echo);
643  if (err != 0) {
644  pr_err("ce_gw: Error during unregistering operation echo: %i\n",
645  err);
646  }
647 
648  err = genl_unregister_ops(&ce_gw_genl_family, &ce_gw_genl_ops_add);
649  if (err != 0) {
650  pr_err("ce_gw: Error during unregistering operation add: %i\n",
651  err);
652  }
653 
654  err = genl_unregister_ops(&ce_gw_genl_family, &ce_gw_genl_ops_del);
655  if (err != 0) {
656  pr_err("ce_gw: Error during unregistering operation del: %i\n",
657  err);
658  }
659 
660  err = genl_unregister_ops(&ce_gw_genl_family, &ce_gw_genl_ops_list);
661  if (err != 0) {
662  pr_err("ce_gw: Error during unregistering operation del: %i\n",
663  err);
664  }
665 
666  err = genl_unregister_family(&ce_gw_genl_family);
667  if (err != 0) {
668  pr_err("ce_gw: Error during unregistering family ce_gw: %i\n",
669  err);
670  }
671 }
672 
673