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
cegwsend.c File Reference

Control Area Network - Ethernet - Gateway - Send (Utility) More...

#include <linux/version.h>
#include <linux/if_ether.h>
#include <getopt.h>
#include <stdlib.h>
#include "can.h"
#include <string.h>
#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <errno.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <net/ethernet.h>
#include <netpacket/packet.h>
#include <assert.h>
Include dependency graph for cegwsend.c:

Go to the source code of this file.

Functions

void convert_to_mac (const char *string1)
 converts a string from the console to a MAC address More...
 
static void die (const char *msg)
 It prints an error message in case of a failure and exits the program. More...
 
static unsigned char gethex (const char *s, char **end)
 
unsigned char * convert_to_hex (const char *s, int *length)
 
int main (int argc, char *argv[])
 

Variables

char * mac
 

Detailed Description

Control Area Network - Ethernet - Gateway - Send (Utility)

Author
Jakob Pfeiffer (jakob.nosp@m..pfe.nosp@m.iffer.nosp@m.@in..nosp@m.tum.d.nosp@m.e)

A Ethernet package is created here and sent to the Interface

Date
July, 2013

Definition in file cegwsend.c.

Function Documentation

unsigned char* convert_to_hex ( const char *  s,
int *  length 
)

Definition at line 91 of file cegwsend.c.

References gethex().

Referenced by main().

91  {
92  unsigned char *hex = malloc((strlen(s) +1) / 3);
93  unsigned char *p;
94  for(p = hex; *s; p++)
95  *p = gethex(s, (char **) &s);
96  *length = p - hex;
97  return hex;
98 }

Here is the call graph for this function:

Here is the caller graph for this function:

void convert_to_mac ( const char *  string1)

converts a string from the console to a MAC address

Parameters
string1the string that should be converted to a MAC
Returns
MAC address with the length of 6 Bytes

Definition at line 53 of file cegwsend.c.

References mac.

Referenced by main().

54 {
55  /* i is used in the for loop */
56  int i;
57  char* string2;
58 
59  /*
60  * A MAC address has the length of 6 Bytes.
61  * We need to allocate enough memory to store it.
62  */
63  mac = (char *) malloc(6);
64  mac[0] = strtoul(string1, &string2, 16);
65  for(i = 1; i <= 5; i++){
66  mac[i] = strtoul(string2 + 1, &string2, 16);
67  }
68 }

Here is the caller graph for this function:

static void die ( const char *  msg)
static

It prints an error message in case of a failure and exits the program.

Parameters
msgThe error message which should be written on the console
Returns
EXIT_FAILURE

Definition at line 78 of file cegwsend.c.

Referenced by main().

79 {
80  perror(msg);
81  exit(EXIT_FAILURE);
82 }

Here is the caller graph for this function:

static unsigned char gethex ( const char *  s,
char **  end 
)
static

Definition at line 84 of file cegwsend.c.

Referenced by convert_to_hex().

84  {
85  assert(s);
86  while(isspace(*s)) s++;
87  assert(*s);
88  return strtoul(s, end, 16);
89 }

Here is the caller graph for this function:

int main ( int  argc,
char *  argv[] 
)

Definition at line 109 of file cegwsend.c.

References can_frame::can_dlc, can_frame::can_id, canfd_frame::can_id, CANFD_MAX_DLEN, convert_to_hex(), convert_to_mac(), die(), canfd_frame::flags, canfd_frame::len, and mac.

110 {
111  /* c is used for calling getopt_long() */
112  int c;
113  /*
114  * src points at the beginning of the memory space in which the MAC address
115  * of the message's receiver will be written
116  */
117  char *src;
118  src = (char *) malloc(6);
119  /*
120  * dest points at the beginning of the memory space in which the MAC
121  * address of the message's sender will be written
122  */
123  char *dest;
124  dest = (char *) malloc(6);
125  /* type is the identifier of the EtherType */
126  ushort type;
127  /*
128  * raw_index points at the beginning of the raw data in argv[].
129  * If raw_index == -1, then no data exists
130  */
131  int raw_index = -1;
132  /*
133  * name_index is the index of argv in which the name of the ethernet
134  * device begins. If name_index == -1, then there is no name
135  */
136  int name_index = -1;
137 
138  /*
139  * getopt_long is used here for reading the arguments from the command line
140  */
141  while (1){
142  static struct option long_options[] = {
143  /* source MAC address */
144  {"src", required_argument, 0, 's'},
145  /* destination MAC address */
146  {"dst", required_argument, 0, 'd'},
147  /* packet type ID field */
148  {"type", required_argument, 0, 't'},
149  /* raw data */
150  {"raw", required_argument, 0, 'r'},
151  /* name of the network interface */
152  {"interface", required_argument, 0, 'i'},
153  {0, 0, 0, 0}
154  };
155  /* getopt_long stores the option index here. */
156  int option_index = 0;
157 
158  c = getopt_long(argc, argv, "s:d:t:r:i:", long_options, &option_index);
159 
160  /* Detect the end of the options. */
161  if(c == -1)
162  break;
163 
164  switch (c){
165  case 0:
166  /* If this option set a flag, do nothing else now. */
167  if(long_options[option_index].flag != 0)
168  break;
169  printf("option %s", long_options[option_index].name);
170  if(optarg)
171  printf(" with arg %s", optarg);
172  printf("\n");
173  break;
174 
175  case 's':
176  printf("option -s with value `%s'\n", optarg);
177  /*
178  * convert the argument to a valid MAC address
179  */
180  convert_to_mac(optarg);
181  /*
182  * convert_to_mac writes the address down in mac.
183  * It must be stored in src now.
184  */
185  memcpy(src, mac, 6);
186  break;
187 
188  case 'd':
189  printf("option -d with value `%s'\n", optarg);
190  /*
191  * convert the argument to al valid MAC address
192  */
193  convert_to_mac(optarg);
194  /*
195  * convert_to_mac writes the address down in mac.
196  * It must be stored in dest now.
197  */
198  memcpy(dest, mac, 6);
199  break;
200 
201  case 't':
202  printf("option -t with value `%s'\n", optarg);
203  /*
204  * The EtherType is defined by a number with the length of
205  * 2 Bytes (e. g. 0x8000 for the Internet Protocol). The
206  * argument from the console must be converted to a number.
207  * This happens here.
208  */
209  if(strcmp(optarg, "ipv4") == 0){
210  /*
211  * The EtherType of Internet Protocol, Version 4 is
212  * 0x0800
213  */
214  type = 0x0800;
215  } else if(strcmp(optarg, "ipv6") == 0){
216  /*
217  * The EtherType of Internet Protocol, Version 6 is
218  * 0x86DD
219  */
220  type = 0x86DD;
221  } else if(strcmp(optarg, "can") == 0){
222  /*
223  * The EtherType of Controller Area Network is 0x000C
224  */
225  type = 0x000C;
226  } else if(strcmp(optarg, "canfd") == 0){
227  /*
228  * The EtherType of CAN flexible data rate is 0x000D
229  */
230  type = 0x000D;
231  /*
232  * 0x88B5 and 0x88B6 have been
233  * reserved for experimental use
234  */
235  } else if(strcmp(optarg, "none") == 0){
236  type = 0x88B5;
237  /*
238  * If the identifier was typed in like "0x1234" we cut off
239  * the 0x and convert the number. If instead it was written
240  * down like "1234" we simply convert the argument from the
241  * console to a number.
242  */
243  } else if(strncmp(optarg, "0x", 2) == 0){
244  type = strtoul(optarg + 2, &optarg, 16);
245  } else {
246  type = strtoul(optarg, &optarg, 16);
247  }
248  break;
249 
250  case 'r':
251  printf("option -r with value `%s'\n", optarg);
252  raw_index = optind - 1;
253  break;
254 
255  case 'i':
256  printf("option -i with value `%s'\n", optarg);
257  name_index = optind - 1;
258  break;
259 
260  case '?':
261  /* getopt_long already printed error message- */
262  break;
263 
264  default:
265  abort();
266  }
267  }
268  /* mac is not needed anymore */
269  free(mac);
270 
271  printf("source: %hhX", *src);
272  printf(":%hhX", *(src + 1));
273  printf(":%hhX", *(src + 2));
274  printf(":%hhX", *(src + 3));
275  printf(":%hhX", *(src + 4));
276  printf(":%hhX\n", *(src + 5));
277  printf("destination: %hhX", *dest);
278  printf(":%hhX", *(dest + 1));
279  printf(":%hhX", *(dest + 2));
280  printf(":%hhX", *(dest + 3));
281  printf(":%hhX", *(dest + 4));
282  printf(":%hhX\n", *(dest + 5));
283  printf("type: %hX \n", type);
284 
285  /*
286  * Create the AF_PACKET socket
287  */
288  int fd = socket(AF_PACKET, SOCK_DGRAM, htons(type));
289  /*
290  * In case of a failure the allocated memory must be freed and die is called
291  */
292  if (fd == -1){
293  free(dest);
294  free(src);
295  die(strerror(errno));
296  }
297 
298  /*
299  * Name/index number of the interface
300  * If there is no name, we have a problem and the program must end
301  */
302  if(name_index == -1){
303  free(dest);
304  free(src);
305  die("name/index number of the network interface required");
306  }
307  struct ifreq ifr;
308  size_t if_name_len = strlen(argv[name_index]);
309  if(if_name_len < sizeof(ifr.ifr_name)){
310  memcpy(ifr.ifr_name, argv[name_index], if_name_len);
311  ifr.ifr_name[if_name_len] = 0;
312  } else {
313  printf("sizeof(ifr.ifr_name): %d", sizeof(ifr.ifr_name));
314  printf(" sollte groesser sein als if_name_len: %d", if_name_len);
315  free(src);
316  free(dest);
317  die("interface name is too long");
318  }
319  if(ioctl(fd, SIOCGIFINDEX, &ifr) == -1){
320  free(src);
321  free(dest);
322  die(strerror(errno));
323  }
324  int ifindex = ifr.ifr_ifindex;
325 
326  /*
327  * Construct the destination address
328  */
329  struct sockaddr_ll addr = {0};
330  addr.sll_family = AF_PACKET;
331  addr.sll_ifindex = ifindex;
332  addr.sll_halen = ETHER_ADDR_LEN;
333  addr.sll_protocol = htons(type);
334  memcpy(addr.sll_addr, dest, ETHER_ADDR_LEN);
335  /* dest is not needed anymore */
336  free(dest);
337 
338  /*
339  * Prepare the data to be sent. If it exists, of course
340  */
341  if(raw_index == -1){
342  free(src);
343  die("No data to be sent");
344  }
345  /*
346  * Here, the raw data is converted from a string to a number
347  */
348  unsigned char *data = NULL;
349  int length = strlen(argv[raw_index]);
350  data = convert_to_hex(argv[raw_index], &length);
351  int data_length = ((strlen(argv[raw_index]) + 1) / 3);
352  /*
353  * If the package is a can package, a can frame must be
354  * written into the payload
355  */
356  if(type == 0x000C){
357  /*
358  * The maximum data which fits in a can frame
359  * is 8 Bytes. If the data is too long, the
360  * program terminates.
361  */
362  if(data_length > 8){
363  free(src);
364  free(data);
365  die("The raw data is too long for a can frame");
366  }
367  struct can_frame frame;
368  memset(frame.data, 0, 8);
369  frame.can_id = 0;
370  frame.can_dlc = data_length;
371  memcpy(frame.data, data, data_length);
372  /*
373  * A Ethernet frame which contains the can frame in
374  * its payload is sent
375  */
376  if(sendto(fd, &frame, sizeof(struct can_frame), 0, (struct sockaddr*)&addr, sizeof(addr)) == -1){
377  free(data);
378  free(src);
379  die(strerror(errno));
380  }
381  } else if(type == 0x000D){
382  printf("Ja, wir haben einen canfd\n");
383  /*
384  * The maximum data which fits in a canfd frame
385  * is 64 Bytes. If the data is too long, the
386  * program terminates.
387  */
388  if(data_length > CANFD_MAX_DLEN){
389  free(data);
390  free(src);
391  die("The raw data is too long for a canfd frame");
392  }
393  static struct canfd_frame frame;
394  memset(frame.data, 0, CANFD_MAX_DLEN);
395  frame.can_id = 0;
396  frame.flags = 0;
397  frame.len = data_length;
398  memcpy(frame.data, data, data_length);
399  printf("Alles kopiert und so. Wird gleich gesendet.\n");
400  /*
401  * A Ethernet frame which contains the canfd frame
402  * in its payload is sent
403  */
404  if(sendto(fd, &frame, sizeof(struct canfd_frame), 0, (struct sockaddr*)&addr, sizeof(addr)) == -1){
405  free(data);
406  free(src);
407  die(strerror(errno));
408  }
409  printf("Jap, gesendet.\n");
410  } else {
411  /* Finally, let's send the package */
412  if(sendto(fd, data, data_length, 0, (struct sockaddr*)&addr, sizeof(addr)) == -1){
413  free(data);
414  free(src);
415  die(strerror(errno));
416  }
417  }
418  /*
419  * Nerver forget to free the allocated memory
420  */
421  free(data);
422  free(src);
423  return EXIT_SUCCESS;
424 }

Here is the call graph for this function:

Variable Documentation

char* mac

Definition at line 45 of file cegwsend.c.

Referenced by convert_to_mac(), and main().