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
Netlink
static struct nla_policy ce_gw_genl_policy [CE_GW_A_MAX+1]
 Netlink Policy - Defines the Type for the Netlink Attributes. More...
 
static struct genl_family ce_gw_genl_family
 Generic Netlink Family. More...
 
struct genl_ops ce_gw_genl_ops_echo
 details of ce_gw_netlink_echo() More...
 
struct genl_ops ce_gw_genl_ops_add
 details of ce_gw_netlink_add() More...
 
struct genl_ops ce_gw_genl_ops_del
 details of ce_gw_netlink_del() More...
 
struct genl_ops ce_gw_genl_ops_list
 details of ce_gw_netlink_list() More...
 
int ce_gw_netlink_echo (struct sk_buff *skb_info, struct genl_info *info)
 Generic Netlink Command - Sends a massage back. More...
 
int ce_gw_netlink_add (struct sk_buff *skb_info, struct genl_info *info)
 add a virtual ethernet device or a route More...
 
int ce_gw_netlink_del (struct sk_buff *skb_info, struct genl_info *info)
 Deletes a device by name or a route by ID. More...
 
int ce_gw_netlink_list (struct sk_buff *skb_info, struct genl_info *info)
 Send informations of one or more routes to userspace. More...
 
int ce_gw_netlink_init (void)
 Must called once at module init. More...
 
void ce_gw_netlink_exit (void)
 Must called once at module exit. More...
 

Detailed Description

Function Documentation

int ce_gw_netlink_add ( struct sk_buff *  skb_info,
struct genl_info *  info 
)

add a virtual ethernet device or a route

Parameters
skb_infoNetlink Socket Buffer with Message
infoAdditional Netlink Information will be called by ce_gw_add() in userspace in cegwctl.

Has multiple netlink Attributes.

  • CE_GW_A_SRC: The textual name of the device wich will be the src. Must be NULL if you want do add a device.
  • CE_GW_A_DST: The textual name of the device wich will be the dst OR the name of the device, if you want to add a device.
  • CE_GW_A_TYPE: The Type of the route. For adding dev some settings according to the type will be set.
  • CE_GW_A_FLAGS: The Flags of the route. For adding dev some settings according to the type will be set. See netlink.h for the falgs.
Return values
0on success
<0on failure

Definition at line 216 of file ce_gw_netlink.c.

References CE_GW_A_DST, CE_GW_A_FLAGS, CE_GW_A_SRC, CE_GW_A_TYPE, ce_gw_create_route(), ce_gw_dev_create(), ce_gw_dev_free(), and ce_gw_dev_register().

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 }

Here is the call graph for this function:

int ce_gw_netlink_del ( struct sk_buff *  skb_info,
struct genl_info *  info 
)

Deletes a device by name or a route by ID.

Parameters
skb_infoNetlink Socket Buffer with Message
infoAdditional Netlink Information
Precondition
CE_GW_A_ID must be == 0 OR CE_GW_A_DST must be == NULL

will be called by ce_gw_add() in userspace in cegwctl.

Has multiple netlink Attributes:

  • CE_GW_A_ID The id of the route you want to delete. CE_GW_A_DST must be NULL when you want to delete a route.
  • CE_GW_A_DST The textual name of the virtual device you want to delete. The device must be previously added by ce_gw_add(). CE_GW_A_ID must be 0 if you want to delete a device.
Return values
0on success
<0on failure

Definition at line 333 of file ce_gw_netlink.c.

References CE_GW_A_DST, CE_GW_A_ID, ce_gw_dev_free(), ce_gw_dev_unregister(), and ce_gw_remove_route().

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 }

Here is the call graph for this function:

int ce_gw_netlink_echo ( struct sk_buff *  skb_info,
struct genl_info *  info 
)

Generic Netlink Command - Sends a massage back.

Parameters
skb_infoNetlink Socket Buffer with Message
infoAdditional Netlink Information
Return values
0if parsing is finished

Definition at line 127 of file ce_gw_netlink.c.

References CE_GW_A_DATA, CE_GW_C_ECHO, ce_gw_genl_family, and CE_GW_NO_FLAG.

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 };
static void ce_gw_netlink_exit ( void  )

Must called once at module exit.

During exit of module this function must called. It unregisters the family and its operations.

Definition at line 640 of file ce_gw_netlink.c.

References ce_gw_genl_family.

Referenced by ce_gw_cleanup().

640  {
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 }

Here is the caller graph for this function:

int ce_gw_netlink_init ( void  )

Must called once at module init.

During init of module this function must called. It registers the family and its operations.

Return values
0when init successful
<0if an error occurred.

Definition at line 581 of file ce_gw_netlink.c.

References ce_gw_genl_family.

Referenced by ce_gw_init_module().

581  {
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 }

Here is the caller graph for this function:

int ce_gw_netlink_list ( struct sk_buff *  skb_info,
struct genl_info *  info 
)

Send informations of one or more routes to userspace.

Parameters
skb_infoNetlink Socket Buffer with Message
infoAdditional Netlink Information

will be called by ce_gw_list() in userspace in cegwctl.

get Netlink Attribute:

  • CE_GW_A_ID set it to 0 if you want to send all routes. Else set it to the route id you want to send.

Send multiple netlink Attributes back:

Return values
0on success
<0on failure

Definition at line 401 of file ce_gw_netlink.c.

References CE_GW_A_DROP, CE_GW_A_DST, CE_GW_A_FLAGS, CE_GW_A_HNDL, CE_GW_A_ID, CE_GW_A_SRC, CE_GW_A_TYPE, CE_GW_C_ECHO, ce_gw_genl_family, ce_gw_get_job_list(), CE_GW_NO_FLAG, ce_gw_job::dev, ce_gw_job::dropped_frames, ce_gw_job::dst, ce_gw_job::flags, ce_gw_job::handled_frames, ce_gw_job::id, ce_gw_job::src, and ce_gw_job::type.

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 }

Here is the call graph for this function:

Variable Documentation

struct genl_family ce_gw_genl_family
static
Initial value:
= {
.id = GENL_ID_GENERATE,
.hdrsize = CE_GW_USER_HDR_SIZE,
.maxattr = CE_GW_A_MAX,
.netnsok = false,
.pre_doit = NULL,
.post_doit = NULL,
}

Generic Netlink Family.

Definition at line 91 of file ce_gw_netlink.c.

Referenced by ce_gw_netlink_echo(), ce_gw_netlink_exit(), ce_gw_netlink_init(), and ce_gw_netlink_list().

struct genl_ops ce_gw_genl_ops_add
Initial value:
= {
.cmd = CE_GW_C_ADD,
.internal_flags = CE_GW_NO_FLAG,
.flags = CE_GW_NO_FLAG,
.policy = ce_gw_genl_policy,
.dumpit = NULL,
.done = NULL,
}

details of ce_gw_netlink_add()

Definition at line 542 of file ce_gw_netlink.c.

struct genl_ops ce_gw_genl_ops_del
Initial value:
= {
.cmd = CE_GW_C_DEL,
.internal_flags = CE_GW_NO_FLAG,
.flags = CE_GW_NO_FLAG,
.policy = ce_gw_genl_policy,
.dumpit = NULL,
.done = NULL,
}

details of ce_gw_netlink_del()

Definition at line 556 of file ce_gw_netlink.c.

struct genl_ops ce_gw_genl_ops_echo
Initial value:
= {
.cmd = CE_GW_C_ECHO,
.internal_flags = CE_GW_NO_FLAG,
.flags = CE_GW_NO_FLAG,
.policy = ce_gw_genl_policy,
.dumpit = NULL,
.done = NULL,
}

details of ce_gw_netlink_echo()

Definition at line 528 of file ce_gw_netlink.c.

struct genl_ops ce_gw_genl_ops_list
Initial value:
= {
.cmd = CE_GW_C_LIST,
.internal_flags = CE_GW_NO_FLAG,
.flags = CE_GW_NO_FLAG,
.policy = ce_gw_genl_policy,
.dumpit = NULL,
.done = NULL,
}

details of ce_gw_netlink_list()

Definition at line 570 of file ce_gw_netlink.c.

struct nla_policy ce_gw_genl_policy[CE_GW_A_MAX+1]
static
Initial value:
= {
[CE_GW_A_DATA] = { .type = NLA_NUL_STRING },
[CE_GW_A_SRC] = { .type = NLA_NUL_STRING },
[CE_GW_A_DST] = { .type = NLA_NUL_STRING },
[CE_GW_A_ID] = { .type = NLA_U32 },
[CE_GW_A_FLAGS] = { .type = NLA_U32 },
[CE_GW_A_TYPE] = { .type = NLA_U8 },
[CE_GW_A_HNDL] = { .type = NLA_U32 },
[CE_GW_A_DROP] = { .type = NLA_U32 },
}

Netlink Policy - Defines the Type for the Netlink Attributes.

Definition at line 76 of file ce_gw_netlink.c.