netlink_gre.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. /* NHRP netlink/GRE tunnel configuration code
  2. * Copyright (c) 2014-2016 Timo Teräs
  3. *
  4. * This file is free software: you may copy, redistribute and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation, either version 2 of the License, or
  7. * (at your option) any later version.
  8. */
  9. #include <sys/socket.h>
  10. #include <linux/netlink.h>
  11. #include <linux/rtnetlink.h>
  12. #include <linux/in.h>
  13. #include <linux/if.h>
  14. #include <linux/ip.h>
  15. #include <linux/ipv6.h>
  16. #include <linux/if_tunnel.h>
  17. #include "debug.h"
  18. #include "netlink.h"
  19. #include "znl.h"
  20. static int __netlink_gre_get_data(struct zbuf *zb, struct zbuf *data, int ifindex)
  21. {
  22. struct nlmsghdr *n;
  23. struct ifinfomsg *ifi;
  24. struct zbuf payload, rtapayload;
  25. struct rtattr *rta;
  26. debugf(NHRP_DEBUG_KERNEL, "netlink-link-gre: get-info %u", ifindex);
  27. n = znl_nlmsg_push(zb, RTM_GETLINK, NLM_F_REQUEST);
  28. ifi = znl_push(zb, sizeof(*ifi));
  29. *ifi = (struct ifinfomsg) {
  30. .ifi_index = ifindex,
  31. };
  32. znl_nlmsg_complete(zb, n);
  33. if (zbuf_send(zb, netlink_req_fd) < 0 ||
  34. zbuf_recv(zb, netlink_req_fd) < 0)
  35. return -1;
  36. n = znl_nlmsg_pull(zb, &payload);
  37. if (!n) return -1;
  38. if (n->nlmsg_type != RTM_NEWLINK)
  39. return -1;
  40. ifi = znl_pull(&payload, sizeof(struct ifinfomsg));
  41. if (!ifi)
  42. return -1;
  43. debugf(NHRP_DEBUG_KERNEL, "netlink-link-gre: ifindex %u, receive msg_type %u, msg_flags %u",
  44. ifi->ifi_index, n->nlmsg_type, n->nlmsg_flags);
  45. if (ifi->ifi_index != ifindex)
  46. return -1;
  47. while ((rta = znl_rta_pull(&payload, &rtapayload)) != NULL)
  48. if (rta->rta_type == IFLA_LINKINFO)
  49. break;
  50. if (!rta) return -1;
  51. payload = rtapayload;
  52. while ((rta = znl_rta_pull(&payload, &rtapayload)) != NULL)
  53. if (rta->rta_type == IFLA_INFO_DATA)
  54. break;
  55. if (!rta) return -1;
  56. *data = rtapayload;
  57. return 0;
  58. }
  59. void netlink_gre_get_info(unsigned int ifindex, uint32_t *gre_key, unsigned int *link_index, struct in_addr *saddr)
  60. {
  61. struct zbuf *zb = zbuf_alloc(8192), data, rtapl;
  62. struct rtattr *rta;
  63. *link_index = 0;
  64. *gre_key = 0;
  65. saddr->s_addr = 0;
  66. if (__netlink_gre_get_data(zb, &data, ifindex) < 0)
  67. goto err;
  68. while ((rta = znl_rta_pull(&data, &rtapl)) != NULL) {
  69. switch (rta->rta_type) {
  70. case IFLA_GRE_LINK:
  71. *link_index = zbuf_get32(&rtapl);
  72. break;
  73. case IFLA_GRE_IKEY:
  74. case IFLA_GRE_OKEY:
  75. *gre_key = zbuf_get32(&rtapl);
  76. break;
  77. case IFLA_GRE_LOCAL:
  78. saddr->s_addr = zbuf_get32(&rtapl);
  79. break;
  80. }
  81. }
  82. err:
  83. zbuf_free(zb);
  84. }
  85. void netlink_gre_set_link(unsigned int ifindex, unsigned int link_index)
  86. {
  87. struct nlmsghdr *n;
  88. struct ifinfomsg *ifi;
  89. struct rtattr *rta_info, *rta_data, *rta;
  90. struct zbuf *zr = zbuf_alloc(8192), data, rtapl;
  91. struct zbuf *zb = zbuf_alloc(8192);
  92. size_t len;
  93. if (__netlink_gre_get_data(zr, &data, ifindex) < 0)
  94. goto err;
  95. n = znl_nlmsg_push(zb, RTM_NEWLINK, NLM_F_REQUEST);
  96. ifi = znl_push(zb, sizeof(*ifi));
  97. *ifi = (struct ifinfomsg) {
  98. .ifi_index = ifindex,
  99. };
  100. rta_info = znl_rta_nested_push(zb, IFLA_LINKINFO);
  101. znl_rta_push(zb, IFLA_INFO_KIND, "gre", 3);
  102. rta_data = znl_rta_nested_push(zb, IFLA_INFO_DATA);
  103. znl_rta_push_u32(zb, IFLA_GRE_LINK, link_index);
  104. while ((rta = znl_rta_pull(&data, &rtapl)) != NULL) {
  105. if (rta->rta_type == IFLA_GRE_LINK)
  106. continue;
  107. len = zbuf_used(&rtapl);
  108. znl_rta_push(zb, rta->rta_type, zbuf_pulln(&rtapl, len), len);
  109. }
  110. znl_rta_nested_complete(zb, rta_data);
  111. znl_rta_nested_complete(zb, rta_info);
  112. znl_nlmsg_complete(zb, n);
  113. zbuf_send(zb, netlink_req_fd);
  114. zbuf_recv(zb, netlink_req_fd);
  115. err:
  116. zbuf_free(zb);
  117. zbuf_free(zr);
  118. }