libj1939.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. /*
  2. * Copyright (c) 2011 EIA Electronics
  3. *
  4. * Authors:
  5. * Kurt Van Dijck <kurt.van.dijck@eia.be>
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the version 2 of the GNU General Public License
  9. * as published by the Free Software Foundation
  10. */
  11. #include <string.h>
  12. #include <stdio.h>
  13. #include <stdlib.h>
  14. #include <errno.h>
  15. #include <inttypes.h>
  16. #include <error.h>
  17. #include <unistd.h>
  18. #include <fcntl.h>
  19. #include <net/if.h>
  20. #include <sys/ioctl.h>
  21. #include <net/if.h>
  22. #include "libj1939.h"
  23. /* static data */
  24. static struct if_nameindex *saved;
  25. __attribute__((destructor))
  26. static void libj1939_cleanup(void)
  27. {
  28. if (saved)
  29. if_freenameindex(saved);
  30. saved = 0;
  31. }
  32. static inline void fetch_names(void)
  33. {
  34. if (!saved) {
  35. saved = if_nameindex();
  36. if (!saved)
  37. error(1, errno, "if_nameindex()");
  38. }
  39. }
  40. /* retrieve name */
  41. static const char *libj1939_ifnam(int ifindex)
  42. {
  43. const struct if_nameindex *lp, *cached = saved;
  44. fetch_names();
  45. for (lp = saved; lp->if_index; ++lp) {
  46. if (lp->if_index == ifindex)
  47. return lp->if_name;
  48. }
  49. if (cached) {
  50. /*
  51. * the list was not recent
  52. * iterate twice, but force a refresh now
  53. * recursion stops since the 'saved' pointer is cleaned
  54. */
  55. libj1939_cleanup();
  56. return libj1939_ifnam(ifindex);
  57. } else
  58. return NULL;
  59. }
  60. /* retrieve index */
  61. static int libj1939_ifindex(const char *str)
  62. {
  63. const struct if_nameindex *lp, *cached = saved;
  64. char *endp;
  65. int ret;
  66. ret = strtol(str, &endp, 0);
  67. if (!*endp)
  68. /* did some good parse */
  69. return ret;
  70. fetch_names();
  71. for (lp = saved; lp->if_index; ++lp) {
  72. if (!strcmp(lp->if_name, str))
  73. return lp->if_index;
  74. }
  75. if (cached) {
  76. libj1939_cleanup();
  77. return libj1939_ifindex(str);
  78. } else
  79. return 0;
  80. }
  81. int libj1939_str2addr(const char *str, char **endp, struct sockaddr_can *can)
  82. {
  83. char *p;
  84. const char *pstr;
  85. uint64_t tmp64;
  86. unsigned long tmp;
  87. if (!endp)
  88. endp = &p;
  89. memset(can, 0, sizeof(*can));
  90. can->can_family = AF_CAN;
  91. can->can_addr.j1939.name = J1939_NO_NAME;
  92. can->can_addr.j1939.addr = J1939_NO_ADDR;
  93. can->can_addr.j1939.pgn = J1939_NO_PGN;
  94. pstr = strchr(str, ':');
  95. if (pstr) {
  96. char tmp[IFNAMSIZ];
  97. if ((pstr - str) >= IFNAMSIZ)
  98. return -1;
  99. strncpy(tmp, str, pstr - str);
  100. tmp[pstr - str] = 0;
  101. can->can_ifindex = libj1939_ifindex(tmp);
  102. } else {
  103. can->can_ifindex = libj1939_ifindex(str);
  104. if (can->can_ifindex) {
  105. if (endp)
  106. *endp = (char *)&str[strlen(str)];
  107. return 0;
  108. }
  109. }
  110. if (pstr)
  111. ++pstr;
  112. else
  113. pstr = str;
  114. tmp64 = strtoull(pstr, endp, 16);
  115. if (*endp <= pstr)
  116. return 0;
  117. if ((*endp - pstr) == 2)
  118. can->can_addr.j1939.addr = tmp64;
  119. else
  120. can->can_addr.j1939.name = tmp64;
  121. if (!**endp)
  122. return 0;
  123. str = *endp + 1;
  124. tmp = strtoul(str, endp, 16);
  125. if (*endp > str)
  126. can->can_addr.j1939.pgn = tmp;
  127. return 0;
  128. }
  129. const char *libj1939_addr2str(const struct sockaddr_can *can)
  130. {
  131. char *str;
  132. static char buf[128];
  133. str = buf;
  134. if (can->can_ifindex) {
  135. const char *ifname;
  136. ifname = libj1939_ifnam(can->can_ifindex);
  137. if (!ifname)
  138. str += sprintf(str, "#%i:", can->can_ifindex);
  139. else
  140. str += sprintf(str, "%s:", ifname);
  141. }
  142. if (can->can_addr.j1939.name) {
  143. str += sprintf(str, "%016llx", (unsigned long long)can->can_addr.j1939.name);
  144. if (can->can_addr.j1939.pgn == 0x0ee00)
  145. str += sprintf(str, ".%02x", can->can_addr.j1939.addr);
  146. } else if (can->can_addr.j1939.addr <= 0xfe)
  147. str += sprintf(str, "%02x", can->can_addr.j1939.addr);
  148. else
  149. str += sprintf(str, "-");
  150. if (can->can_addr.j1939.pgn <= 0x3ffff)
  151. str += sprintf(str, ",%05x", can->can_addr.j1939.pgn);
  152. return buf;
  153. }